API & Client - replace testcafe with selenium for e2e tests
This commit is contained in:
parent
f626559e5e
commit
1ad847c857
9
Makefile
9
Makefile
@ -58,10 +58,10 @@ lint-all: lint-python lint-react
|
||||
lint-all-fix: lint-python-fix lint-react-fix
|
||||
|
||||
lint-python:
|
||||
$(PYTEST) --flake8 --isort --black -m "flake8 or isort or black" fittrackee_api --ignore=fittrackee_api/migrations
|
||||
$(PYTEST) --flake8 --isort --black -m "flake8 or isort or black" fittrackee_api e2e --ignore=fittrackee_api/migrations
|
||||
|
||||
lint-python-fix:
|
||||
$(BLACK) fittrackee_api
|
||||
$(BLACK) fittrackee_api e2e
|
||||
|
||||
lint-react:
|
||||
$(NPM) lint
|
||||
@ -103,7 +103,10 @@ serve-dev:
|
||||
$(MAKE) P="serve-react serve-python-dev" make-p
|
||||
|
||||
test-e2e: init-db
|
||||
$(NPM) test
|
||||
$(PYTEST) e2e --driver firefox $(PYTEST_ARGS) $(E2E_ARGS)
|
||||
|
||||
test-e2e-client: init-db
|
||||
E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
|
||||
|
||||
test-python:
|
||||
$(PYTEST) fittrackee_api --cov-config .coveragerc --cov=fittrackee_api --cov-report term-missing $(PYTEST_ARGS)
|
||||
|
@ -5,7 +5,7 @@ CLIENT_PORT = 3000
|
||||
export FLASK_APP = $(PWD)/fittrackee_api/server.py
|
||||
export APP_SETTINGS=fittrackee_api.config.DevelopmentConfig
|
||||
export FLASK_ENV=development
|
||||
export TEST_URL = http://$(HOST):$(API_PORT)
|
||||
export TEST_APP_URL = http://$(HOST):$(API_PORT)
|
||||
export TEST_CLIENT_URL = http://$(HOST):$(CLIENT_PORT)
|
||||
export DATABASE_URL = postgres://fittrackee:fittrackee@$(HOST):5432/fittrackee
|
||||
export DATABASE_TEST_URL = postgres://fittrackee:fittrackee@$(HOST):5432/fittrackee_test
|
||||
|
0
e2e/__init__.py
Normal file
0
e2e/__init__.py
Normal file
38
e2e/test_activities.py
Normal file
38
e2e/test_activities.py
Normal file
@ -0,0 +1,38 @@
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import Select, WebDriverWait
|
||||
|
||||
from .utils import TEST_URL, register_valid_user
|
||||
|
||||
|
||||
class TestActivity:
|
||||
def test_user_can_add_activity_without_gpx(self, selenium):
|
||||
register_valid_user(selenium)
|
||||
nav_items = selenium.find_elements_by_class_name('nav-item')
|
||||
|
||||
nav_items[3].click()
|
||||
selenium.implicitly_wait(1)
|
||||
radio_buttons = selenium.find_elements_by_class_name(
|
||||
'add-activity-radio'
|
||||
)
|
||||
radio_buttons[1].click()
|
||||
|
||||
selenium.find_element_by_name('title').send_keys('Activity title')
|
||||
select = Select(selenium.find_element_by_name('sport_id'))
|
||||
select.select_by_index(1)
|
||||
selenium.find_element_by_name('activity_date').send_keys('2018-12-20')
|
||||
selenium.find_element_by_name('activity_time').send_keys('14:05')
|
||||
selenium.find_element_by_name('duration').send_keys('01:00:00')
|
||||
selenium.find_element_by_name('distance').send_keys('10')
|
||||
selenium.find_element_by_class_name('btn-primary').click()
|
||||
|
||||
WebDriverWait(selenium, 10).until(
|
||||
EC.url_changes(f"{TEST_URL}/activities/add")
|
||||
)
|
||||
|
||||
activity_details = selenium.find_element_by_class_name(
|
||||
'activity-details'
|
||||
).text
|
||||
assert 'Duration: 1:00:00' in activity_details
|
||||
assert 'Distance: 10 km' in activity_details
|
||||
assert 'Average speed: 10 km/h' in activity_details
|
||||
assert 'Max. speed: 10 km/h' in activity_details
|
17
e2e/test_index.py
Normal file
17
e2e/test_index.py
Normal file
@ -0,0 +1,17 @@
|
||||
from .utils import TEST_URL
|
||||
|
||||
|
||||
class TestIndex:
|
||||
def test_title_contains_fittrackee(self, selenium):
|
||||
selenium.get(TEST_URL)
|
||||
assert 'FitTrackee' in selenium.title
|
||||
|
||||
def test_navbar_contains_all_links(self, selenium):
|
||||
selenium.get(TEST_URL)
|
||||
|
||||
nav = selenium.find_element_by_tag_name('nav').text
|
||||
assert "FitTrackee" in nav
|
||||
assert "Dashboard" in nav
|
||||
assert "Login" in nav
|
||||
assert "Register" in nav
|
||||
assert "en" in nav
|
40
e2e/test_login.py
Normal file
40
e2e/test_login.py
Normal file
@ -0,0 +1,40 @@
|
||||
from .utils import TEST_URL, assert_navbar, login_valid_user
|
||||
|
||||
URL = f'{TEST_URL}/login'
|
||||
|
||||
|
||||
class TestLogin:
|
||||
def test_navbar_contains_login(self, selenium):
|
||||
selenium.get(URL)
|
||||
|
||||
nav = selenium.find_element_by_tag_name('nav').text
|
||||
assert 'Login' in nav
|
||||
|
||||
def test_h1_contains_login(self, selenium):
|
||||
selenium.get(URL)
|
||||
|
||||
title = selenium.find_element_by_tag_name('h1').text
|
||||
assert 'Login' in title
|
||||
|
||||
def test_it_displays_login_form(self, selenium):
|
||||
selenium.get(URL)
|
||||
|
||||
inputs = selenium.find_elements_by_tag_name('input')
|
||||
assert len(inputs) == 3
|
||||
assert inputs[0].get_attribute('name') == 'email'
|
||||
assert inputs[0].get_attribute('type') == 'email'
|
||||
assert inputs[1].get_attribute('name') == 'password'
|
||||
assert inputs[1].get_attribute('type') == 'password'
|
||||
assert inputs[2].get_attribute('name') == ''
|
||||
assert inputs[2].get_attribute('type') == 'submit'
|
||||
|
||||
def test_user_can_log_in(self, selenium):
|
||||
user = {
|
||||
'username': 'admin',
|
||||
'email': 'admin@example.com',
|
||||
'password': 'mpwoadmin',
|
||||
}
|
||||
|
||||
login_valid_user(selenium, user)
|
||||
|
||||
assert_navbar(selenium, user)
|
19
e2e/test_logout.py
Normal file
19
e2e/test_logout.py
Normal file
@ -0,0 +1,19 @@
|
||||
from .utils import register_valid_user
|
||||
|
||||
|
||||
class TestLogout:
|
||||
def test_user_can_log_out(self, selenium):
|
||||
user = register_valid_user(selenium)
|
||||
nav_items = selenium.find_elements_by_class_name('nav-item')
|
||||
|
||||
nav_items[5].click()
|
||||
selenium.implicitly_wait(1)
|
||||
|
||||
nav = selenium.find_element_by_tag_name('nav').text
|
||||
assert 'Register' in nav
|
||||
assert 'Login' in nav
|
||||
assert user['username'] not in nav
|
||||
assert 'Logout' not in nav
|
||||
|
||||
message = selenium.find_element_by_class_name('card-body').text
|
||||
assert 'You are now logged out. Click here to log back in.' in message
|
20
e2e/test_profile.py
Normal file
20
e2e/test_profile.py
Normal file
@ -0,0 +1,20 @@
|
||||
from .utils import TEST_URL, register_valid_user
|
||||
|
||||
URL = f'{TEST_URL}/profile'
|
||||
|
||||
|
||||
class TestProfile:
|
||||
def test_it_displays_user_profile(self, selenium):
|
||||
user = register_valid_user(selenium)
|
||||
|
||||
selenium.get(URL)
|
||||
|
||||
assert 'Profile' in selenium.find_element_by_tag_name('h1').text
|
||||
assert (
|
||||
user['username']
|
||||
in selenium.find_element_by_class_name('userName').text
|
||||
)
|
||||
assert (
|
||||
user['username']
|
||||
in selenium.find_element_by_class_name('userName').text
|
||||
)
|
141
e2e/test_registration.py
Normal file
141
e2e/test_registration.py
Normal file
@ -0,0 +1,141 @@
|
||||
from .utils import (
|
||||
TEST_URL,
|
||||
assert_navbar,
|
||||
random_string,
|
||||
register,
|
||||
register_valid_user,
|
||||
)
|
||||
|
||||
URL = f'{TEST_URL}/register'
|
||||
|
||||
|
||||
class TestRegistration:
|
||||
def test_it_displays_registration_form(self, selenium):
|
||||
selenium.get(URL)
|
||||
selenium.implicitly_wait(1)
|
||||
|
||||
inputs = selenium.find_elements_by_tag_name('input')
|
||||
assert len(inputs) == 5
|
||||
assert inputs[0].get_attribute('name') == 'username'
|
||||
assert inputs[0].get_attribute('type') == 'text'
|
||||
assert inputs[1].get_attribute('name') == 'email'
|
||||
assert inputs[1].get_attribute('type') == 'email'
|
||||
assert inputs[2].get_attribute('name') == 'password'
|
||||
assert inputs[2].get_attribute('type') == 'password'
|
||||
assert inputs[3].get_attribute('name') == 'password_conf'
|
||||
assert inputs[3].get_attribute('type') == 'password'
|
||||
assert inputs[4].get_attribute('name') == ''
|
||||
assert inputs[4].get_attribute('type') == 'submit'
|
||||
|
||||
def test_user_can_register(self, selenium):
|
||||
user = register_valid_user(selenium)
|
||||
|
||||
assert_navbar(selenium, user)
|
||||
|
||||
def test_user_can_not_register_with_invalid_email(self, selenium):
|
||||
user_name = random_string()
|
||||
user_infos = {
|
||||
'username': user_name,
|
||||
'email': user_name,
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'p@ssw0rd',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
nav = selenium.find_element_by_tag_name('nav').text
|
||||
assert 'Register' in nav
|
||||
assert 'Login' in nav
|
||||
|
||||
def test_user_can_not_register_if_username_is_already_taken(
|
||||
self, selenium
|
||||
):
|
||||
user_name = random_string()
|
||||
user_infos = {
|
||||
'username': 'admin',
|
||||
'email': f'{user_name}@example.com',
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'p@ssw0rd',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
errors = selenium.find_element_by_tag_name('code').text
|
||||
assert 'Sorry. That user already exists.' in errors
|
||||
|
||||
def test_user_can_not_register_if_email_is_already_taken(self, selenium):
|
||||
user_name = random_string()
|
||||
user_infos = {
|
||||
'username': user_name,
|
||||
'email': 'admin@example.com',
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'p@ssw0rd',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
errors = selenium.find_element_by_tag_name('code').text
|
||||
assert 'Sorry. That user already exists.' in errors
|
||||
|
||||
def test_user_can_not_register_if_username_is_too_short(self, selenium):
|
||||
user_name = random_string(2)
|
||||
user_infos = {
|
||||
'username': user_name,
|
||||
'email': 'admin@example.com',
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'p@ssw0rd',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
errors = selenium.find_element_by_tag_name('code').text
|
||||
assert '3 to 12 characters required for username.' in errors
|
||||
|
||||
def test_user_can_not_register_if_username_is_too_long(self, selenium):
|
||||
user_name = random_string(13)
|
||||
user_infos = {
|
||||
'username': user_name,
|
||||
'email': 'admin@example.com',
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'p@ssw0rd',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
errors = selenium.find_element_by_tag_name('code').text
|
||||
assert '3 to 12 characters required for username.' in errors
|
||||
|
||||
def test_it_displays_error_if_passwords_do_not_match(self, selenium):
|
||||
user_name = random_string()
|
||||
user_infos = {
|
||||
'username': user_name,
|
||||
'email': f'{user_name}@example.com',
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'password',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
errors = selenium.find_element_by_tag_name('code').text
|
||||
assert 'Password and password confirmation don\'t match' in errors
|
||||
|
||||
def test_it_displays_error_if_password_is_too_short(self, selenium):
|
||||
user_name = random_string()
|
||||
user_infos = {
|
||||
'username': user_name,
|
||||
'email': f'{user_name}@example.com',
|
||||
'password': 'p@ss',
|
||||
'password_conf': 'p@ss',
|
||||
}
|
||||
|
||||
register(selenium, user_infos)
|
||||
|
||||
assert selenium.current_url == URL
|
||||
errors = selenium.find_element_by_tag_name('code').text
|
||||
assert '8 characters required for password.' in errors
|
73
e2e/utils.py
Normal file
73
e2e/utils.py
Normal file
@ -0,0 +1,73 @@
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
TEST_APP_URL = os.getenv('TEST_APP_URL')
|
||||
TEST_CLIENT_URL = os.getenv('TEST_CLIENT_URL')
|
||||
E2E_ARGS = os.getenv('E2E_ARGS')
|
||||
TEST_URL = TEST_CLIENT_URL if E2E_ARGS == 'client' else TEST_APP_URL
|
||||
|
||||
|
||||
def random_string(length=8):
|
||||
return ''.join(random.choice(string.ascii_letters) for x in range(length))
|
||||
|
||||
|
||||
def register(selenium, user):
|
||||
selenium.get(f'{TEST_URL}/register')
|
||||
selenium.implicitly_wait(1)
|
||||
username = selenium.find_element_by_name('username')
|
||||
username.send_keys(user.get('username'))
|
||||
email = selenium.find_element_by_name('email')
|
||||
email.send_keys(user.get('email'))
|
||||
password = selenium.find_element_by_name('password')
|
||||
password.send_keys(user.get('password'))
|
||||
password_conf = selenium.find_element_by_name('password_conf')
|
||||
password_conf.send_keys(user.get('password_conf'))
|
||||
submit_button = selenium.find_element_by_class_name('btn')
|
||||
submit_button.click()
|
||||
|
||||
|
||||
def login(selenium, user):
|
||||
selenium.get(f'{TEST_URL}/login')
|
||||
selenium.implicitly_wait(1)
|
||||
email = selenium.find_element_by_name('email')
|
||||
email.send_keys(user.get('email'))
|
||||
password = selenium.find_element_by_name('password')
|
||||
password.send_keys(user.get('password'))
|
||||
submit_button = selenium.find_element_by_class_name('btn')
|
||||
submit_button.click()
|
||||
|
||||
|
||||
def register_valid_user(selenium):
|
||||
user_name = random_string()
|
||||
user = {
|
||||
'username': user_name,
|
||||
'email': f'{user_name}@example.com',
|
||||
'password': 'p@ssw0rd',
|
||||
'password_conf': 'p@ssw0rd',
|
||||
}
|
||||
register(selenium, user)
|
||||
WebDriverWait(selenium, 10).until(EC.url_changes(f"{TEST_URL}/register"))
|
||||
return user
|
||||
|
||||
|
||||
def login_valid_user(selenium, user):
|
||||
login(selenium, user)
|
||||
WebDriverWait(selenium, 10).until(EC.url_changes(f"{TEST_URL}/login"))
|
||||
return user
|
||||
|
||||
|
||||
def assert_navbar(selenium, user):
|
||||
nav = selenium.find_element_by_tag_name('nav').text
|
||||
assert 'Register' not in nav
|
||||
assert 'Login' not in nav
|
||||
assert 'Dashboard' in nav
|
||||
assert 'Workouts' in nav
|
||||
assert 'Statistics' in nav
|
||||
assert 'Add workout' in nav
|
||||
assert user['username'] in nav
|
||||
assert 'Logout' in nav
|
||||
assert 'en' in nav
|
126
fittrackee_api/poetry.lock
generated
126
fittrackee_api/poetry.lock
generated
@ -651,6 +651,18 @@ toml = "*"
|
||||
version = ">=0.12"
|
||||
python = "<3.8"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-base-url"
|
||||
version = "1.4.2"
|
||||
description = "pytest plugin for URL based testing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=2.7.3"
|
||||
requests = ">=2.9"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-black"
|
||||
version = "0.3.11"
|
||||
@ -694,6 +706,18 @@ python-versions = "*"
|
||||
flake8 = ">=3.5"
|
||||
pytest = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-html"
|
||||
version = "2.1.1"
|
||||
description = "pytest plugin for generating HTML reports"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=5.0"
|
||||
pytest-metadata = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-isort"
|
||||
version = "1.2.0"
|
||||
@ -708,6 +732,17 @@ tests = ["mock"]
|
||||
[package.dependencies]
|
||||
isort = ">=4.0"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-metadata"
|
||||
version = "1.10.0"
|
||||
description = "pytest plugin for test session metadata"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=2.9.0"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-runner"
|
||||
version = "5.2"
|
||||
@ -720,6 +755,42 @@ python-versions = ">=2.7"
|
||||
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs", "pytest-flake8", "pytest-black-multipy", "pytest-cov", "pytest-virtualenv"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-selenium"
|
||||
version = "2.0.0"
|
||||
description = "pytest plugin for Selenium"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
appium = ["appium-python-client (>=0.44)"]
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=5.0.0"
|
||||
pytest-base-url = "*"
|
||||
pytest-html = ">=1.14.0"
|
||||
pytest-variables = ">=1.5.0"
|
||||
requests = "*"
|
||||
selenium = ">=3.0.0"
|
||||
tenacity = ">=6,<7"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-variables"
|
||||
version = "1.9.0"
|
||||
description = "pytest plugin for providing variables to tests/fixtures"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.extras]
|
||||
hjson = ["hjson"]
|
||||
toml = ["toml"]
|
||||
yaml = ["pyyaml"]
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=2.4.2"
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.1"
|
||||
@ -825,6 +896,17 @@ requests = ">=2.0"
|
||||
six = "*"
|
||||
urllib3 = ">=1.25.10"
|
||||
|
||||
[[package]]
|
||||
name = "selenium"
|
||||
version = "3.141.0"
|
||||
description = "Python bindings for Selenium"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
urllib3 = "*"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.15.0"
|
||||
@ -999,6 +1081,20 @@ python-versions = "*"
|
||||
Pillow = "*"
|
||||
requests = "*"
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "6.2.0"
|
||||
description = "Retry code until it succeeds"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.extras]
|
||||
doc = ["reno", "sphinx", "tornado (>=4.5)"]
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.9.0"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.1"
|
||||
@ -1075,7 +1171,7 @@ testing = ["jaraco.itertools", "func-timeout"]
|
||||
[metadata]
|
||||
lock-version = "1.0"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "0d1e7030730e202fc78148ad1e14d5a022d8d37e165c6ace6e2c4b4f8f62cb3c"
|
||||
content-hash = "2dd6612c53553c2dc00eb59a85b3f29d958ae8c7d45ba682392dd0baf06ff824"
|
||||
|
||||
[metadata.files]
|
||||
alabaster = [
|
||||
@ -1476,6 +1572,10 @@ pytest = [
|
||||
{file = "pytest-6.0.2-py3-none-any.whl", hash = "sha256:0e37f61339c4578776e090c3b8f6b16ce4db333889d65d0efb305243ec544b40"},
|
||||
{file = "pytest-6.0.2.tar.gz", hash = "sha256:c8f57c2a30983f469bf03e68cdfa74dc474ce56b8f280ddcb080dfd91df01043"},
|
||||
]
|
||||
pytest-base-url = [
|
||||
{file = "pytest-base-url-1.4.2.tar.gz", hash = "sha256:7f1f32e08c2ee751e59e7f5880235b46e83496adc5cba5a01ca218c6fe81333d"},
|
||||
{file = "pytest_base_url-1.4.2-py2.py3-none-any.whl", hash = "sha256:8b6523a1a3af73c317bdae97b722dfb55a7336733d1ad411eb4a4931347ba77a"},
|
||||
]
|
||||
pytest-black = [
|
||||
{file = "pytest-black-0.3.11.tar.gz", hash = "sha256:595eb0e7908b8a858a8564a5c8f0eae853c3926a4ec7b2afdfcedfa6fec65dd6"},
|
||||
]
|
||||
@ -1487,14 +1587,30 @@ pytest-flake8 = [
|
||||
{file = "pytest-flake8-1.0.6.tar.gz", hash = "sha256:1b82bb58c88eb1db40524018d3fcfd0424575029703b4e2d8e3ee873f2b17027"},
|
||||
{file = "pytest_flake8-1.0.6-py2.py3-none-any.whl", hash = "sha256:2e91578ecd9b200066f99c1e1de0f510fbb85bcf43712d46ea29fe47607cc234"},
|
||||
]
|
||||
pytest-html = [
|
||||
{file = "pytest-html-2.1.1.tar.gz", hash = "sha256:6a4ac391e105e391208e3eb9bd294a60dd336447fd8e1acddff3a6de7f4e57c5"},
|
||||
{file = "pytest_html-2.1.1-py2.py3-none-any.whl", hash = "sha256:9e4817e8be8ddde62e8653c8934d0f296b605da3d2277a052f762c56a8b32df2"},
|
||||
]
|
||||
pytest-isort = [
|
||||
{file = "pytest-isort-1.2.0.tar.gz", hash = "sha256:f0fcf9674f3a627b36e07466d335e82b0f7c4f9e0f7ec39f2a1750b0189d5371"},
|
||||
{file = "pytest_isort-1.2.0-py3-none-any.whl", hash = "sha256:2c6a1d210e8c478e418ab25df2408c235c97b1b8958fb0b139d790d0ec246f58"},
|
||||
]
|
||||
pytest-metadata = [
|
||||
{file = "pytest-metadata-1.10.0.tar.gz", hash = "sha256:b7e6e0a45adacb17a03a97bf7a2ef60cc1f4e172bcce9732ce5e814191932315"},
|
||||
{file = "pytest_metadata-1.10.0-py2.py3-none-any.whl", hash = "sha256:fcbcc5781aee450107c620c79c57e50796b6777b82b3c504be9cbc3017201169"},
|
||||
]
|
||||
pytest-runner = [
|
||||
{file = "pytest-runner-5.2.tar.gz", hash = "sha256:96c7e73ead7b93e388c5d614770d2bae6526efd997757d3543fe17b557a0942b"},
|
||||
{file = "pytest_runner-5.2-py2.py3-none-any.whl", hash = "sha256:5534b08b133ef9a5e2c22c7886a8f8508c95bb0b0bdc6cc13214f269c3c70d51"},
|
||||
]
|
||||
pytest-selenium = [
|
||||
{file = "pytest-selenium-2.0.0.tar.gz", hash = "sha256:6a7c655c9202fa5964b872859d8aad18a67ccbdfbaa078d154cab82914d70504"},
|
||||
{file = "pytest_selenium-2.0.0-py2.py3-none-any.whl", hash = "sha256:114bc1df383b0bb841a62ad03b222aa57d0866d57f03f81b539e59fcf43231b8"},
|
||||
]
|
||||
pytest-variables = [
|
||||
{file = "pytest-variables-1.9.0.tar.gz", hash = "sha256:f79851e4c92a94c93d3f1d02377b5ac97cc8800392e87d108d2cbfda774ecc2a"},
|
||||
{file = "pytest_variables-1.9.0-py2.py3-none-any.whl", hash = "sha256:ccf4afcd70de1f5f18b4463758a19f24647a9def1805f675e80db851c9e00ac0"},
|
||||
]
|
||||
python-dateutil = [
|
||||
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
|
||||
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
|
||||
@ -1552,6 +1668,10 @@ responses = [
|
||||
{file = "responses-0.12.0-py2.py3-none-any.whl", hash = "sha256:0de50fbf600adf5ef9f0821b85cc537acca98d66bc7776755924476775c1989c"},
|
||||
{file = "responses-0.12.0.tar.gz", hash = "sha256:e80d5276011a4b79ecb62c5f82ba07aa23fb31ecbc95ee7cad6de250a3c97444"},
|
||||
]
|
||||
selenium = [
|
||||
{file = "selenium-3.141.0-py2.py3-none-any.whl", hash = "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c"},
|
||||
{file = "selenium-3.141.0.tar.gz", hash = "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
||||
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
|
||||
@ -1632,6 +1752,10 @@ sqlalchemy = [
|
||||
staticmap = [
|
||||
{file = "staticmap-0.5.4.tar.gz", hash = "sha256:9d05a1739cffa0cf6ab8f64873e6dacb36c593c23f2a70053115ef344954b315"},
|
||||
]
|
||||
tenacity = [
|
||||
{file = "tenacity-6.2.0-py2.py3-none-any.whl", hash = "sha256:5a5d3dcd46381abe8b4f82b5736b8726fd3160c6c7161f53f8af7f1eb9b82173"},
|
||||
{file = "tenacity-6.2.0.tar.gz", hash = "sha256:29ae90e7faf488a8628432154bb34ace1cca58244c6ea399fd33f066ac71339a"},
|
||||
]
|
||||
toml = [
|
||||
{file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
|
||||
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
|
||||
|
@ -37,6 +37,7 @@ sphinx-bootstrap-theme = "^0.7.1"
|
||||
recommonmark = "^0.6.0"
|
||||
pyopenssl = "^19.0"
|
||||
freezegun = "^1.0.0"
|
||||
pytest-selenium = "^2.0.0"
|
||||
|
||||
[tool.pytest]
|
||||
norecursedirs = "fittrackee_api/.venv"
|
||||
|
Loading…
Reference in New Issue
Block a user