Add selenium tests

This commit is contained in:
Gabriel Augendre 2022-11-10 19:23:47 +01:00
parent 5d3869403d
commit abf2aeb459
8 changed files with 214 additions and 15 deletions

View file

@ -19,7 +19,7 @@
<excludeFolder url="file://$MODULE_DIR$/src/test_reports" /> <excludeFolder url="file://$MODULE_DIR$/src/test_reports" />
<excludeFolder url="file://$MODULE_DIR$/src/character/tests/test_reports" /> <excludeFolder url="file://$MODULE_DIR$/src/character/tests/test_reports" />
</content> </content>
<orderEntry type="jdk" jdkName="Python 3.10 (charasheet)" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.11 (charasheet)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (charasheet)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (charasheet)" project-jdk-type="Python SDK" />
</project> </project>

110
poetry.lock generated
View file

@ -25,6 +25,14 @@ category = "main"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
[[package]]
name = "atomicwrites"
version = "1.4.1"
description = "Atomic file writes."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
name = "attrs" name = "attrs"
version = "22.1.0" version = "22.1.0"
@ -654,23 +662,36 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "7.2.0" version = "6.2.5"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0" attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""} colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*" iniconfig = "*"
packaging = "*" packaging = "*"
pluggy = ">=0.12,<2.0" pluggy = ">=0.12,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} py = ">=1.8.2"
toml = "*"
[package.extras] [package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]]
name = "pytest-base-url"
version = "2.0.0"
description = "pytest plugin for URL based testing"
category = "dev"
optional = false
python-versions = ">=3.7,<4.0"
[package.dependencies]
pytest = ">=3.0.0,<8.0.0"
requests = ">=2.9"
[[package]] [[package]]
name = "pytest-cov" name = "pytest-cov"
@ -726,6 +747,42 @@ python-versions = ">=3.7,<4.0"
[package.dependencies] [package.dependencies]
pytest = ">=3.0.0,<8.0.0" pytest = ">=3.0.0,<8.0.0"
[[package]]
name = "pytest-selenium"
version = "4.0.0"
description = "pytest plugin for Selenium"
category = "dev"
optional = false
python-versions = ">=3.7,<4.0"
[package.dependencies]
pytest = ">=6.0.0,<7.0.0"
pytest-base-url = ">=2.0.0,<3.0.0"
pytest-html = ">=2.0.0"
pytest-variables = ">=2.0.0,<3.0.0"
requests = ">=2.26.0,<3.0.0"
selenium = ">=4.0.0,<5.0.0"
tenacity = ">=6.0.0,<7.0.0"
[package.extras]
appium = ["appium-python-client (>=2.0.0,<3.0.0)"]
[[package]]
name = "pytest-variables"
version = "2.0.0"
description = "pytest plugin for providing variables to tests/fixtures"
category = "dev"
optional = false
python-versions = ">=3.7,<4.0"
[package.dependencies]
pytest = ">=3.0.0,<8.0.0"
[package.extras]
hjson = ["hjson"]
toml = ["toml"]
yaml = ["pyyaml"]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.8.2" version = "2.8.2"
@ -800,7 +857,7 @@ requests = ">=2.0.1,<3.0.0"
[[package]] [[package]]
name = "selenium" name = "selenium"
version = "4.5.0" version = "4.6.0"
description = "" description = ""
category = "main" category = "main"
optional = false optional = false
@ -852,6 +909,20 @@ category = "main"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
[[package]]
name = "tenacity"
version = "6.3.1"
description = "Retry code until it succeeds"
category = "dev"
optional = false
python-versions = "*"
[package.dependencies]
six = ">=1.9.0"
[package.extras]
doc = ["reno", "sphinx", "tornado (>=4.5)"]
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.10.2" version = "0.10.2"
@ -973,7 +1044,7 @@ h11 = ">=0.9.0,<1"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = ">=3.10.0, <4" python-versions = ">=3.10.0, <4"
content-hash = "0f3a51fc5bde7b9ffb5f8596be2c7f9db40d1279a3dbda8daff47f4312e94e83" content-hash = "c415c2b6a560284b2c3ffff9ccd7bf2ff79e8fd1b8f5d845fee1f0970fb6360f"
[metadata.files] [metadata.files]
ansicon = [ ansicon = [
@ -988,6 +1059,9 @@ async-generator = [
{file = "async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b"}, {file = "async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b"},
{file = "async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"}, {file = "async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"},
] ]
atomicwrites = [
{file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
]
attrs = [ attrs = [
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
@ -1479,8 +1553,12 @@ pysocks = [
{file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
] ]
pytest = [ pytest = [
{file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
{file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
]
pytest-base-url = [
{file = "pytest-base-url-2.0.0.tar.gz", hash = "sha256:e1e88a4fd221941572ccdcf3bf6c051392d2f8b6cef3e0bc7da95abec4b5346e"},
{file = "pytest_base_url-2.0.0-py3-none-any.whl", hash = "sha256:ed36fd632c32af9f1c08f2c2835dcf42ca8fcd097d6ed44a09f253d365ad8297"},
] ]
pytest-cov = [ pytest-cov = [
{file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"},
@ -1498,6 +1576,14 @@ pytest-metadata = [
{file = "pytest_metadata-2.0.3-py3-none-any.whl", hash = "sha256:7fbb5a09110a7f62060ecad77110c6481e4e3a85e46556605b323fc97c072c7f"}, {file = "pytest_metadata-2.0.3-py3-none-any.whl", hash = "sha256:7fbb5a09110a7f62060ecad77110c6481e4e3a85e46556605b323fc97c072c7f"},
{file = "pytest_metadata-2.0.3.tar.gz", hash = "sha256:4a09b7582a4b8307be7c604bc392d33b9cc03831a5ed62f9bc3d08e4bc721250"}, {file = "pytest_metadata-2.0.3.tar.gz", hash = "sha256:4a09b7582a4b8307be7c604bc392d33b9cc03831a5ed62f9bc3d08e4bc721250"},
] ]
pytest-selenium = [
{file = "pytest-selenium-4.0.0.tar.gz", hash = "sha256:a0b45a0d1d5833a67b14a279cfe1a0eeaf4981ab4b0d12e9787fcfa1ed48049f"},
{file = "pytest_selenium-4.0.0-py3-none-any.whl", hash = "sha256:1a512e2bc49140cf347a9a45036245da956d569a5fe53b653a85695470cd9fe1"},
]
pytest-variables = [
{file = "pytest-variables-2.0.0.tar.gz", hash = "sha256:1c9e4fc321e33be7d1b352ac9cf20fdd2c39a8e4e6fa2dcd042aaf70ed516be7"},
{file = "pytest_variables-2.0.0-py3-none-any.whl", hash = "sha256:1a24a30b7acf9654d71bcdc8b10c1eb0d81b73b3eec72d810703c522475d643b"},
]
python-dateutil = [ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
@ -1561,7 +1647,7 @@ requests-toolbelt = [
{file = "requests_toolbelt-0.10.1-py2.py3-none-any.whl", hash = "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7"}, {file = "requests_toolbelt-0.10.1-py2.py3-none-any.whl", hash = "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7"},
] ]
selenium = [ selenium = [
{file = "selenium-4.5.0-py3-none-any.whl", hash = "sha256:a733dd77d3171b846893f4d51b18967d809313f547a10974e26579f9ce797462"}, {file = "selenium-4.6.0-py3-none-any.whl", hash = "sha256:3f1999875ef487ae676a254e7293a68041f1f1ec76be81402d8a1cd5a481bf3b"},
] ]
six = [ six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
@ -1583,6 +1669,10 @@ sqlparse = [
{file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"}, {file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"},
{file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"}, {file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"},
] ]
tenacity = [
{file = "tenacity-6.3.1-py2.py3-none-any.whl", hash = "sha256:baed357d9f35ec64264d8a4bbf004c35058fad8795c5b0d8a7dc77ecdcbb8f39"},
{file = "tenacity-6.3.1.tar.gz", hash = "sha256:e14d191fb0a309b563904bbc336582efe2037de437e543b38da749769b544d7f"},
]
toml = [ toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},

View file

@ -31,6 +31,7 @@ pytest = ">=6.0"
pytest-cov = ">=3.0.0" pytest-cov = ">=3.0.0"
pytest-django = ">=4.1.0" pytest-django = ">=4.1.0"
pytest-html = ">=3.1.1" pytest-html = ">=3.1.1"
pytest-selenium = ">=4.0.0"
pre-commit = ">=2.1" pre-commit = ">=2.1"
model-bakery = ">=1.3.1" model-bakery = ">=1.3.1"
freezegun = ">=1.1.0" freezegun = ">=1.1.0"
@ -39,6 +40,7 @@ poetry-deps-scanner = ">=2.0.0"
invoke = ">=1.7.3" invoke = ">=1.7.3"
hypothesis = ">=6.56.4" hypothesis = ">=6.56.4"
django-browser-reload = ">=1.6.0" django-browser-reload = ">=1.6.0"
selenium = ">=4.5.0"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
@ -51,7 +53,10 @@ build-backend = "poetry.core.masonry.api"
addopts = """ addopts = """
--html=test_reports/pytest_result/pytest.html --color=yes --durations 20 --html=test_reports/pytest_result/pytest.html --color=yes --durations 20
--no-cov-on-fail --strict-markers --no-cov-on-fail --strict-markers
--driver=Firefox
-W error -W error
-W "ignore:capabilities and desired_capabilities have been deprecated:DeprecationWarning:pytest_selenium.pytest_selenium"
-W "ignore:service_log_path has been deprecated:DeprecationWarning:pytest_selenium.pytest_selenium"
""" """
markers = [] markers = []
minversion = "6.0" minversion = "6.0"

View file

@ -5,7 +5,7 @@
{% block content %} {% block content %}
<h1>Personnages</h1> <h1>Personnages</h1>
<a href="{% url "character:create" %}" class="btn btn-primary mb-3"> <a id="new-character" href="{% url "character:create" %}" class="btn btn-primary mb-3">
<i class="fa-solid fa-user-plus"></i> Nouveau perso <i class="fa-solid fa-user-plus"></i> Nouveau perso
</a> </a>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4"> <div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4">

View file

@ -0,0 +1,98 @@
import pytest
from django.core.management import call_command
from django.urls import reverse
from pytest_django.live_server_helper import LiveServer
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.webdriver import WebDriver
from character.models import Character
from common.models import User
@pytest.mark.django_db
def test_create_character(selenium: WebDriver, live_server: LiveServer):
# Load fixtures
call_command("loaddata", "initial_data")
# Create a user
username, password = "user", "some_password"
player = User.objects.create_user(username, password=password)
# Go to home page
selenium.get(live_server.url)
# Login as user
selenium.find_element(By.ID, "login").click()
selenium.find_element(By.ID, "id_username").send_keys(username)
selenium.find_element(By.ID, "id_password").send_keys(password)
selenium.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
# Click on new character
selenium.find_element(By.ID, "new-character").click()
# Check no existing character
assert Character.objects.count() == 0
# Fill form
raw_values = {
"name": "My Character",
"equipment": "Lighter, blanket",
"damage_reduction": "Something here",
"level": 8,
"age": 32,
"height": 134,
"weight": 78,
"value_strength": 9,
"value_dexterity": 12,
"value_constitution": 15,
"value_intelligence": 13,
"value_wisdom": 19,
"value_charisma": 10,
"armor": 5,
"shield": 6,
"defense_misc": 7,
"health_max": 67,
"money_pp": 1,
"money_po": 2,
"money_pa": 3,
"money_pc": 4,
}
related_values = {
"race": "Gnome",
"profile": "Druide",
"racial_capability": "Don étrange",
}
for name, value in raw_values.items():
element = selenium.find_element(By.ID, f"id_{name}")
element.clear()
element.send_keys(str(value))
for name, value in related_values.items():
element = selenium.find_element(By.ID, f"id_{name}")
element.send_keys(str(value))
# Save
selenium.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
# Assert redirected on list view
assert selenium.current_url == live_server.url + reverse("character:list")
# Assert character in DB, belongs to user
assert Character.objects.count() == 1
character = Character.objects.get()
assert character.player == player
for name, value in raw_values.items():
assert getattr(character, name) == value
@pytest.mark.django_db
def test_list_characters(selenium: WebDriver, live_server: LiveServer):
# Load fixtures
call_command("loaddata", "initial_data")
# Create user 1
# Create user 2
# Create two characters (1, 2) for user 1
# Create a character (3) for user 2
# Login as user 1
# Go to home page
# Assert characters 1 and 2 are shown
raise AssertionError()

View file

@ -9,8 +9,8 @@
Bienvenue sur CharaSheet !<br> Bienvenue sur CharaSheet !<br>
Vous devez vous identifier pour créer et gérer votre personnage. Vous devez vous identifier pour créer et gérer votre personnage.
</p> </p>
<a href="{% url "django_registration_register" %}" class="btn btn-primary btn-lg">Créer un compte</a> <a id="signup" href="{% url "django_registration_register" %}" class="btn btn-primary btn-lg">Créer un compte</a>
<a href="{% url "login" %}" class="btn btn-secondary btn-lg">Se connecter</a> <a id="login" href="{% url "login" %}" class="btn btn-secondary btn-lg">Se connecter</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -5,3 +5,9 @@ from django.core.management import call_command
@pytest.fixture(scope="session", autouse=True) @pytest.fixture(scope="session", autouse=True)
def collectstatic(): def collectstatic():
call_command("collectstatic", "--clear", "--noinput", "--verbosity=0") call_command("collectstatic", "--clear", "--noinput", "--verbosity=0")
@pytest.fixture
def firefox_options(firefox_options):
firefox_options.add_argument("-headless")
return firefox_options