From e1810f64bd00c2e0a83ec747367294293ada776f Mon Sep 17 00:00:00 2001 From: sfmig <33267254+sfmig@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:33:15 +0100 Subject: [PATCH] Common components integration tests (#82) * add ids for sidebar and sidebar links * add tests to check components common to all pages are created correctly * add docstring for map fixture and clean comments for review * move fixtures to conftest * parametrise test sidebar links * add xfail for each parametrized case * use fixture in pytest parametrize * add fixture to parametrize * adding fixtures in conftest * remove map from comftest. add question for review. * remove commented input arg * correct type in test input args Co-authored-by: Sam Cunliffe * Update docstrings Co-authored-by: Sam Cunliffe * add type and docstrings for request input * change docstrings to numpy format * extra time for windows? * The ROI page was not sending errors on Windows. So it was an XPASS and we had XFAIL strict (expected fail, but found the test to pass therefore FAIL). Without strict we get an XPASS on Windows. Something to investigate further as we add more tests. --------- Co-authored-by: Sam Cunliffe Co-authored-by: Sam Cunliffe --- tests/test_integration/conftest.py | 38 +++++ tests/test_integration/test_common_layout.py | 138 +++++++++++++++++++ wazp/app.py | 2 + 3 files changed, 178 insertions(+) create mode 100644 tests/test_integration/test_common_layout.py diff --git a/tests/test_integration/conftest.py b/tests/test_integration/conftest.py index b155c77..2328194 100644 --- a/tests/test_integration/conftest.py +++ b/tests/test_integration/conftest.py @@ -51,3 +51,41 @@ def pytest_setup_options(): options.add_argument("--headless") options.add_argument("--disable-gpu") return options + + +@pytest.fixture +def home_page_name_and_title(): + return ("Home", "Home") + + +@pytest.fixture +def metadata_page_name_and_title(): + return ("01 metadata", "Metadata") + + +@pytest.fixture +def roi_page_name_and_title(): + return ("02 roi", "ROI definition") + + +@pytest.fixture +def pose_estimation_page_name_and_title(): + return ("03 pose estimation", "Pose estimation inference") + + +@pytest.fixture +def dashboard_page_name_and_title(): + return ("04 dashboard", "Dashboard & data export") + + +@pytest.fixture +def timeout() -> float: + """Maximum time to wait for a component + to be located in layout + + Returns + ------- + timeout : float + maximum time to wait in seconds + """ + return 4 diff --git a/tests/test_integration/test_common_layout.py b/tests/test_integration/test_common_layout.py new file mode 100644 index 0000000..7b1e9d6 --- /dev/null +++ b/tests/test_integration/test_common_layout.py @@ -0,0 +1,138 @@ +import pytest +import selenium +from dash.testing.composite import DashComposite + +from wazp.app import app + + +def test_components_created( + dash_duo: DashComposite, + timeout: float, +) -> None: + """Check that the components that are common to all pages are created. + + The components common to all pages are: + - the page content container, and + - the sidebar. + + Parameters + ---------- + dash_duo : DashComposite + Default fixture for Dash Python integration tests. + timeout : float + maximum time to wait in seconds for a component + """ + + # start server + dash_duo.start_server(app) + + # wait for main content container to be rendered + try: + dash_duo.wait_for_element("#page-content", timeout=timeout) + except selenium.common.exceptions.TimeoutException: + pytest.fail("Main content component not generated") + + # wait for sidebar to be rendered + try: + dash_duo.wait_for_text_to_equal( + "#sidebar h2", "WAZP 🐝", timeout=timeout + ) + except selenium.common.exceptions.TimeoutException: + pytest.fail("Sidebar component not generated") + + # check there are no errors in browser console + assert ( + dash_duo.get_logs() == [] + ), f"There are {len(dash_duo.get_logs())} errors" + " in the browser console!" + + +unloaded_config_xfail = pytest.mark.xfail( + raises=AssertionError, + reason=( + "Feature not yet implemented:" + "When config has not been loaded, " + "warnings should show in pages that are not Home" + ), + strict=False, + # with strict=True + # if the test passes unexpectedly, + # it will fail the test suite +) + + +# Q for review: is there a way to have this with +# one fixture only? +# https://docs.pytest.org/en/latest/how-to/skipping.html#skip-xfail-with-parametrize +@pytest.mark.parametrize( + ("page_name_and_title"), + [ + pytest.param(fx, marks=mark) + for fx, mark in [ + ("home_page_name_and_title", []), + ("metadata_page_name_and_title", unloaded_config_xfail), + ("roi_page_name_and_title", unloaded_config_xfail), + ("pose_estimation_page_name_and_title", []), + ("dashboard_page_name_and_title", unloaded_config_xfail), + ] + ], +) +def test_sidebar_links( + dash_duo: DashComposite, + page_name_and_title: tuple[str], + timeout: float, + request: pytest.FixtureRequest, +) -> None: + """Check the sidebar links take to the corresponding pages + and that no errors occur in the browser console + + The pages are checked via their title. + + Parameters + ---------- + dash_duo : DashComposite + Default fixture for Dash Python integration tests. + page_name_and_title : tuple[str] + name of the page in the dash registry and the main title shown on + the page + timeout : float + maximum time to wait in seconds for a component + request : pytest.FixtureRequest + a special fixture providing information of the requesting test + function. See [1]_ + + References + ---------- + .. [1] https://docs.pytest.org/en/6.2.x/reference.html#std-fixture-request + """ + + # get fixture value + (page_name, page_title) = request.getfixturevalue(page_name_and_title) + + # start server + dash_duo.start_server(app) + + # click sidebar link + dash_duo.find_element( + "#sidebar #link-" + page_name.replace(" ", "-"), + ).click() + + # check page title is expected + try: + dash_duo.wait_for_text_to_equal("h1", page_title, timeout=timeout) + + except selenium.common.exceptions.TimeoutException: + pytest.fail( + f"Timeout waiting for page {page_name} " + "to show a title with the text: " + f"{page_title}" + ) + + dash_duo.find_element("#sidebar #link-Home").click() + # TODO: if no config file has been loaded, check a warning is shown? + # ... + + # NOTE: this is expected to fail for a few pages (hence the marked xfails) + assert ( + dash_duo.get_logs() == [] + ), "There are errors in the browser console!" diff --git a/wazp/app.py b/wazp/app.py index e1b6156..29396f7 100644 --- a/wazp/app.py +++ b/wazp/app.py @@ -54,6 +54,7 @@ dbc.Nav( children=[ dcc.Link( + id="link-" + page["name"].replace(" ", "-"), children=f"{page['name']}", href=page["relative_path"], # url of each page ) @@ -64,6 +65,7 @@ ), ], style=SIDEBAR_STYLE, + id="sidebar", ) # Main content style