done
This commit is contained in:
263
lib/python3.11/site-packages/dash/testing/plugin.py
Normal file
263
lib/python3.11/site-packages/dash/testing/plugin.py
Normal file
@ -0,0 +1,263 @@
|
||||
# pylint: disable=missing-docstring,redefined-outer-name
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from .consts import SELENIUM_GRID_DEFAULT
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class MissingDashTesting:
|
||||
def __init__(self, **kwargs):
|
||||
raise Exception(
|
||||
"dash[testing] was not installed. "
|
||||
"Please install to use the dash testing fixtures."
|
||||
)
|
||||
|
||||
def __enter__(self) -> Any:
|
||||
"""Implemented to satisfy type checking."""
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
|
||||
"""Implemented to satisfy type checking."""
|
||||
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
from dash.testing.application_runners import (
|
||||
ThreadedRunner,
|
||||
ProcessRunner,
|
||||
RRunner,
|
||||
JuliaRunner,
|
||||
MultiProcessRunner,
|
||||
)
|
||||
from dash.testing.browser import Browser
|
||||
from dash.testing.composite import DashComposite, DashRComposite, DashJuliaComposite
|
||||
|
||||
# pylint: disable=unused-import
|
||||
import dash_testing_stub # noqa: F401
|
||||
|
||||
_installed = True
|
||||
except ImportError:
|
||||
# Running pytest without dash[testing] installed.
|
||||
ThreadedRunner = MissingDashTesting
|
||||
ProcessRunner = MissingDashTesting
|
||||
MultiProcessRunner = MissingDashTesting
|
||||
RRunner = MissingDashTesting
|
||||
JuliaRunner = MissingDashTesting
|
||||
Browser = MissingDashTesting
|
||||
DashComposite = MissingDashTesting
|
||||
DashRComposite = MissingDashTesting
|
||||
DashJuliaComposite = MissingDashTesting
|
||||
_installed = False
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
if not _installed:
|
||||
return
|
||||
|
||||
dash = parser.getgroup("Dash", "Dash Integration Tests")
|
||||
|
||||
dash.addoption(
|
||||
"--webdriver",
|
||||
choices=("Chrome", "Firefox"),
|
||||
default="Chrome",
|
||||
help="Name of the selenium driver to use",
|
||||
)
|
||||
|
||||
dash.addoption(
|
||||
"--remote", action="store_true", help="instruct pytest to use selenium grid"
|
||||
)
|
||||
|
||||
dash.addoption(
|
||||
"--remote-url",
|
||||
action="store",
|
||||
default=SELENIUM_GRID_DEFAULT,
|
||||
help="set a different selenium grid remote url if other than default",
|
||||
)
|
||||
|
||||
dash.addoption(
|
||||
"--headless", action="store_true", help="set this flag to run in headless mode"
|
||||
)
|
||||
|
||||
dash.addoption(
|
||||
"--percy-assets",
|
||||
action="store",
|
||||
default="tests/assets",
|
||||
help="configure how Percy will discover your app's assets",
|
||||
)
|
||||
|
||||
dash.addoption(
|
||||
"--nopercyfinalize",
|
||||
action="store_false",
|
||||
help="set this flag to control percy finalize at CI level",
|
||||
)
|
||||
|
||||
dash.addoption(
|
||||
"--pause",
|
||||
action="store_true",
|
||||
help="pause using pdb after opening the test app, so you can interact with it",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.tryfirst
|
||||
def pytest_addhooks(pluginmanager):
|
||||
if not _installed:
|
||||
return
|
||||
# https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/plugin.py#L67
|
||||
# avoid warnings with pytest-2.8
|
||||
from dash.testing import newhooks # pylint: disable=import-outside-toplevel
|
||||
|
||||
method = getattr(pluginmanager, "add_hookspecs", None)
|
||||
if method is None:
|
||||
method = pluginmanager.addhooks # pragma: no cover
|
||||
method(newhooks)
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_makereport(item, call): # pylint: disable=unused-argument
|
||||
# execute all other hooks to obtain the report object
|
||||
outcome = yield
|
||||
if not _installed:
|
||||
return
|
||||
rep = outcome.get_result()
|
||||
|
||||
# we only look at actual failing test calls, not setup/teardown
|
||||
if rep.when == "call" and rep.failed and hasattr(item, "funcargs"):
|
||||
for name, fixture in item.funcargs.items():
|
||||
try:
|
||||
if name in {"dash_duo", "dash_br", "dashr", "dashjl"}:
|
||||
fixture.take_snapshot(item.name)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
print(e)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Fixtures
|
||||
###############################################################################
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dash_thread_server() -> ThreadedRunner: # type: ignore[reportInvalidTypeForm]
|
||||
"""Start a local dash server in a new thread."""
|
||||
with ThreadedRunner() as starter:
|
||||
yield starter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dash_process_server() -> ProcessRunner: # type: ignore[reportInvalidTypeForm]
|
||||
"""Start a Dash server with subprocess.Popen and waitress-serve."""
|
||||
with ProcessRunner() as starter:
|
||||
yield starter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dash_multi_process_server() -> MultiProcessRunner: # type: ignore[reportInvalidTypeForm]
|
||||
with MultiProcessRunner() as starter:
|
||||
yield starter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dashr_server() -> RRunner: # type: ignore[reportInvalidTypeForm]
|
||||
with RRunner() as starter:
|
||||
yield starter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dashjl_server() -> JuliaRunner: # type: ignore[reportInvalidTypeForm]
|
||||
with JuliaRunner() as starter:
|
||||
yield starter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dash_br(request, tmpdir) -> Browser: # type: ignore[reportInvalidTypeForm]
|
||||
with Browser(
|
||||
browser=request.config.getoption("webdriver"),
|
||||
remote=request.config.getoption("remote"),
|
||||
remote_url=request.config.getoption("remote_url"),
|
||||
headless=request.config.getoption("headless"),
|
||||
options=request.config.hook.pytest_setup_options(),
|
||||
download_path=tmpdir.mkdir("download").strpath,
|
||||
percy_assets_root=request.config.getoption("percy_assets"),
|
||||
percy_finalize=request.config.getoption("nopercyfinalize"),
|
||||
pause=request.config.getoption("pause"),
|
||||
) as browser:
|
||||
yield browser
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dash_duo(request, dash_thread_server, tmpdir) -> DashComposite: # type: ignore[reportInvalidTypeForm]
|
||||
with DashComposite(
|
||||
server=dash_thread_server,
|
||||
browser=request.config.getoption("webdriver"),
|
||||
remote=request.config.getoption("remote"),
|
||||
remote_url=request.config.getoption("remote_url"),
|
||||
headless=request.config.getoption("headless"),
|
||||
options=request.config.hook.pytest_setup_options(),
|
||||
download_path=tmpdir.mkdir("download").strpath,
|
||||
percy_assets_root=request.config.getoption("percy_assets"),
|
||||
percy_finalize=request.config.getoption("nopercyfinalize"),
|
||||
pause=request.config.getoption("pause"),
|
||||
) as dc:
|
||||
yield dc
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dash_duo_mp(request, dash_multi_process_server, tmpdir) -> DashComposite: # type: ignore[reportInvalidTypeForm]
|
||||
with DashComposite(
|
||||
server=dash_multi_process_server,
|
||||
browser=request.config.getoption("webdriver"),
|
||||
remote=request.config.getoption("remote"),
|
||||
remote_url=request.config.getoption("remote_url"),
|
||||
headless=request.config.getoption("headless"),
|
||||
options=request.config.hook.pytest_setup_options(),
|
||||
download_path=tmpdir.mkdir("download").strpath,
|
||||
percy_assets_root=request.config.getoption("percy_assets"),
|
||||
percy_finalize=request.config.getoption("nopercyfinalize"),
|
||||
pause=request.config.getoption("pause"),
|
||||
) as dc:
|
||||
yield dc
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dashr(request, dashr_server, tmpdir) -> DashRComposite: # type: ignore[reportInvalidTypeForm]
|
||||
with DashRComposite(
|
||||
server=dashr_server,
|
||||
browser=request.config.getoption("webdriver"),
|
||||
remote=request.config.getoption("remote"),
|
||||
remote_url=request.config.getoption("remote_url"),
|
||||
headless=request.config.getoption("headless"),
|
||||
options=request.config.hook.pytest_setup_options(),
|
||||
download_path=tmpdir.mkdir("download").strpath,
|
||||
percy_assets_root=request.config.getoption("percy_assets"),
|
||||
percy_finalize=request.config.getoption("nopercyfinalize"),
|
||||
pause=request.config.getoption("pause"),
|
||||
) as dc:
|
||||
yield dc
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dashjl(request, dashjl_server, tmpdir) -> DashJuliaComposite: # type: ignore[reportInvalidTypeForm]
|
||||
with DashJuliaComposite(
|
||||
server=dashjl_server,
|
||||
browser=request.config.getoption("webdriver"),
|
||||
remote=request.config.getoption("remote"),
|
||||
remote_url=request.config.getoption("remote_url"),
|
||||
headless=request.config.getoption("headless"),
|
||||
options=request.config.hook.pytest_setup_options(),
|
||||
download_path=tmpdir.mkdir("download").strpath,
|
||||
percy_assets_root=request.config.getoption("percy_assets"),
|
||||
percy_finalize=request.config.getoption("nopercyfinalize"),
|
||||
pause=request.config.getoption("pause"),
|
||||
) as dc:
|
||||
yield dc
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def diskcache_manager():
|
||||
from dash.background_callback import ( # pylint: disable=import-outside-toplevel
|
||||
DiskcacheManager,
|
||||
)
|
||||
|
||||
return DiskcacheManager()
|
Reference in New Issue
Block a user