Skip to content

Commit

Permalink
#203 Add more tests and add pytest-xdist
Browse files Browse the repository at this point in the history
  • Loading branch information
alexhad6 committed Dec 14, 2023
1 parent fba2c59 commit 5be6c82
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 19 deletions.
2 changes: 1 addition & 1 deletion paramview/_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _available_port(host: str, default_port: int) -> int:

def start_server(
db_path: str,
host: str = "localhost",
host: str = "127.0.0.1",
default_port: int = 5050,
open_window: bool = True,
) -> None:
Expand Down
36 changes: 35 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ flake8 = "^6.1.0"
pylint = "^3.0.2"
black = "^23.11.0"
pytest = "^7.4.3"
pytest-xdist = "^3.5.0"
pytest-playwright = "^0.4.3"
freezegun = "1.2.2"
requests = "^2.31.0"
Expand All @@ -40,5 +41,4 @@ strict = true

[tool.pytest.ini_options]
addopts = ["--import-mode=importlib"]
base_url = "http://localhost:5050"
filterwarnings = ["ignore::DeprecationWarning:eventlet.support.greenlets"]
33 changes: 31 additions & 2 deletions tests/e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,38 @@
from typing import Any
from collections.abc import Generator
import pytest
from xdist import get_xdist_worker_id # type: ignore
from playwright.sync_api import Page
from paramdb import ParamDB
from tests.e2e.helpers import setup_db_and_start_server, clear, reset

HOST = "http://127.0.0.1"
STARTING_PORT = 7001 # xdist workers will increment up from this port


@pytest.fixture(name="port", scope="session")
def fixture_port(request: pytest.FixtureRequest) -> int:
"""Port to run ParamView server on."""
worker_id = get_xdist_worker_id(request)
if worker_id == "master":
port_offset = 0
else:
assert worker_id[:2] == "gw"
port_offset = int(worker_id[2:])
return STARTING_PORT + port_offset


@pytest.fixture(name="base_url", scope="session")
def fixture_base_url(port: int) -> str:
"""Base URL for ParamView."""
return f"{HOST}:{port}"


@pytest.fixture(name="_visit_page")
def fixture_visit_page(page: Page, base_url: str) -> None:
"""Visits the page."""
page.goto(base_url)


@pytest.fixture(name="db_name", scope="session")
def fixture_db_name() -> str:
Expand All @@ -19,14 +48,14 @@ def fixture_db_name() -> str:

@pytest.fixture(name="db_path", scope="session")
def fixture_db_path(
tmp_path_factory: pytest.TempPathFactory, base_url: str, db_name: str
tmp_path_factory: pytest.TempPathFactory, port: int, base_url: str, db_name: str
) -> Generator[str, None, None]:
"""
Path to the ParamDB database. The ParamView server for the database is also started
and cleaned up by this fixture.
"""
db_path = str(tmp_path_factory.mktemp("db") / db_name)
stop_server = setup_db_and_start_server(db_path, base_url)
stop_server = setup_db_and_start_server(db_path, port, base_url)
yield db_path
stop_server()

Expand Down
8 changes: 6 additions & 2 deletions tests/e2e/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ def reset(db: ParamDB[Any], num_commits: int = 3) -> None:
commit(db)


def setup_db_and_start_server(db_path: str, base_url: str) -> Callable[[], None]:
def setup_db_and_start_server(
db_path: str, port: int, base_url: str
) -> Callable[[], None]:
"""
Set up the database, start the server, wait for the server to be up, and return a
function to stop the server.
Expand All @@ -98,7 +100,9 @@ def setup_db_and_start_server(db_path: str, base_url: str) -> Callable[[], None]
reset(ParamDB(db_path))

# pylint: disable=consider-using-with
server_process = subprocess.Popen(["paramview", db_path, "--no-open"])
server_process = subprocess.Popen(
["paramview", db_path, "--port", f"{port}", "--no-open"]
)

# Wait for server to be up
for _ in range(_SERVER_POLLING_MAX_RETRIES):
Expand Down
8 changes: 4 additions & 4 deletions tests/e2e/test_page_title.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
from playwright.sync_api import Page, expect


def test_title_is_db_name(_reset_db: None, page: Page, db_name: str) -> None:
def test_title_is_db_name(
_reset_db: None, _visit_page: None, page: Page, db_name: str
) -> None:
"""Page title is the database file name."""
page.goto("/")
expect(page).to_have_title(db_name)


def test_title_is_error(_clear_db: None, page: Page) -> None:
def test_title_is_error(_clear_db: None, _visit_page: None, page: Page) -> None:
"""Page title is "Error" if an error has occurred."""
page.goto("/")
expect(page).to_have_title("Error")
108 changes: 100 additions & 8 deletions tests/e2e/test_parameter_editing.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,106 @@
"""Tests for parameter editing."""

from __future__ import annotations
import pytest
from playwright.sync_api import Page, expect
from tests.e2e.helpers import get_date


def test_displays_inputs(_reset_single_db: None, page: Page) -> None:
"""Displays correct input for each parameter type."""
page.goto("/")
@pytest.fixture(autouse=True)
def setup(_reset_single_db: None, _visit_page: None, page: Page) -> None:
"""Automatically run before each test in this module."""
page.get_by_test_id("edit-button").click()
expect(
page.get_by_test_id("parameter-list-item-int")
.get_by_test_id("leaf-input")
.get_by_role("textbox")
).to_have_value("123")


def test_displays_input_int(page: Page) -> None:
"""Displays correct input for int parameters."""
item = page.get_by_test_id("parameter-list-item-int")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("textbox")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_value("123")
expect(item.get_by_test_id("leaf-unit-input")).not_to_be_attached()
expect(leaf_type_input).to_have_text("int/float")


def test_displays_input_float(page: Page) -> None:
"""Displays correct input for float parameters."""
item = page.get_by_test_id("parameter-list-item-float")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("textbox")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_value("1.2345")
expect(item.get_by_test_id("leaf-unit-input")).not_to_be_attached()
expect(leaf_type_input).to_have_text("int/float")


def test_displays_input_bool(page: Page) -> None:
"""Displays correct input for bool parameters."""
item = page.get_by_test_id("parameter-list-item-bool")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("combobox")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_text("True")
expect(item.get_by_test_id("leaf-unit-input")).not_to_be_attached()
expect(leaf_type_input).to_have_text("bool")


def test_displays_input_str(page: Page) -> None:
"""Displays correct input for str parameters."""
item = page.get_by_test_id("parameter-list-item-str")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("textbox")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_value("test")
expect(item.get_by_test_id("leaf-unit-input")).not_to_be_attached()
expect(leaf_type_input).to_have_text("str")


def test_displays_input_none(page: Page) -> None:
"""Displays correct input for None parameters."""
item = page.get_by_test_id("parameter-list-item-None")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("textbox")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_value("None")
expect(leaf_input).to_be_disabled()
expect(item.get_by_test_id("leaf-unit-input")).not_to_be_attached()
expect(leaf_type_input).to_have_text("None")


def test_displays_input_datetime(page: Page) -> None:
"""Displays correct input for datetime parameters."""
datetime_input_value = get_date(1).astimezone().strftime("%Y-%m-%dT%H:%M")
item = page.get_by_test_id("parameter-list-item-datetime")
leaf_input = item.get_by_test_id("leaf-input").locator("input[type=datetime-local]")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_value(datetime_input_value)
expect(item.get_by_test_id("leaf-unit-input")).not_to_be_attached()
expect(leaf_type_input).to_have_text("datetime")


def test_displays_input_quantity(page: Page) -> None:
"""Displays correct input for Quantity parameters."""
item = page.get_by_test_id("parameter-list-item-Quantity")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("textbox")
leaf_unit_input = item.get_by_test_id("leaf-unit-input").get_by_role("textbox")
leaf_type_input = item.get_by_test_id("leaf-type-input").get_by_role("combobox")

expect(leaf_input).to_have_value("1.2345")
expect(leaf_unit_input).to_have_value("m")
expect(leaf_type_input).to_have_text("Quantity")


def test_can_edit_input_int(page: Page) -> None:
"""Input for int parameters can be edited and reset."""
item = page.get_by_test_id("parameter-list-item-int")
leaf_input = item.get_by_test_id("leaf-input").get_by_role("textbox")
reset_button = item.get_by_test_id("reset-leaf-button")

expect(leaf_input).to_have_attribute("aria-invalid", "false")
leaf_input.fill("123a")
expect(leaf_input).to_have_attribute("aria-invalid", "true")
reset_button.click()
expect(leaf_input).to_have_value("123")
expect(leaf_input).to_have_attribute("aria-invalid", "false")

0 comments on commit 5be6c82

Please sign in to comment.