diff --git a/vizro-ai/changelog.d/20240805_140630_alexey_snigir_vizro_ai_dashboard_tests.md b/vizro-ai/changelog.d/20240805_140630_alexey_snigir_vizro_ai_dashboard_tests.md new file mode 100644 index 000000000..f1f65e73c --- /dev/null +++ b/vizro-ai/changelog.d/20240805_140630_alexey_snigir_vizro_ai_dashboard_tests.md @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/vizro-ai/hatch.toml b/vizro-ai/hatch.toml index 258e6c479..27d7a20b0 100644 --- a/vizro-ai/hatch.toml +++ b/vizro-ai/hatch.toml @@ -13,11 +13,15 @@ dependencies = [ "devtools[pygments]", "coverage[toml]>=6.5", "pytest", + "pytest-rerunfailures", "toml", "nbformat>=4.2.0", "pyhamcrest", "jupyter", - "langchain_community" + "langchain_community", + "dash[testing]", + "chromedriver-autoinstaller>=0.6.4", + "urllib3<2.0.0" # helps to resolve bug with urllib3 timeout from vizro-ai integration tests: https://bugs.launchpad.net/python-jenkins/+bug/2018567 ] [envs.default.env-vars] @@ -36,7 +40,7 @@ prep-release = [ pypath = "hatch run python -c 'import sys; print(sys.executable)'" secrets = "pre-commit run gitleaks --all-files" test = "pytest tests {args}" -test-integration = "pytest -v tests/integration {args}" +test-integration = "pytest -vs --reruns 1 tests/integration --headless {args}" test-unit = "pytest tests/unit {args}" test-unit-coverage = [ "coverage run -m pytest tests/unit {args}", diff --git a/vizro-ai/pyproject.toml b/vizro-ai/pyproject.toml index d6c027b84..7e5ebb1b6 100644 --- a/vizro-ai/pyproject.toml +++ b/vizro-ai/pyproject.toml @@ -23,7 +23,6 @@ dependencies = [ "python-dotenv>=1.0.0", # TODO decide env var management to see if we need this "vizro>=0.1.4", # TODO set upper bound later "ipython>=8.10.0", # not directly required, pinned by Snyk to avoid a vulnerability: https://app.snyk.io/vuln/SNYK-PYTHON-IPYTHON-3318382 - "urllib3>=2.0.7", # not directly required, pinned by Snyk to avoid a vulnerability: https://security.snyk.io/vuln/SNYK-PYTHON-URLLIB3-6002459 "aiohttp>=3.9.2", # not directly required, pinned by Snyk to avoid a vulnerability: https://security.snyk.io/vuln/SNYK-PYTHON-AIOHTTP-6209407 "langchain-core>=0.1.31" # not directly required, pinned by Snyk to avoid a vulnerability: https://security.snyk.io/vuln/SNYK-PYTHON-LANGCHAINCORE-6370598 ] diff --git a/vizro-ai/snyk/requirements.txt b/vizro-ai/snyk/requirements.txt index 19da50b49..7edd1f742 100644 --- a/vizro-ai/snyk/requirements.txt +++ b/vizro-ai/snyk/requirements.txt @@ -7,6 +7,5 @@ langgraph>=0.1.2 python-dotenv>=1.0.0 vizro>=0.1.4 ipython>=8.10.0 -urllib3>=2.0.7 aiohttp>=3.9.2 langchain-core>=0.1.31 diff --git a/vizro-ai/tests/integration/conftest.py b/vizro-ai/tests/integration/conftest.py new file mode 100644 index 000000000..e623a6601 --- /dev/null +++ b/vizro-ai/tests/integration/conftest.py @@ -0,0 +1,12 @@ +import pytest +from vizro import Vizro + + +@pytest.fixture(autouse=True) +def reset_managers(): + # this ensures that the managers are reset before and after each test + # the reset BEFORE all tests is important because at pytest test collection, fixtures are evaluated and hence + # the model_manager may be populated with models from other tests + Vizro._reset() + yield + Vizro._reset() diff --git a/vizro-ai/tests/integration/test_dashboard.py b/vizro-ai/tests/integration/test_dashboard.py new file mode 100644 index 000000000..c78ac1dcd --- /dev/null +++ b/vizro-ai/tests/integration/test_dashboard.py @@ -0,0 +1,53 @@ +"""Tests for dashboard using VizroAI.""" + +import os + +import chromedriver_autoinstaller +import pytest +import vizro.plotly.express as px +from vizro import Vizro +from vizro_ai import VizroAI + +vizro_ai = VizroAI() + +df1 = px.data.gapminder() +df2 = px.data.stocks() + + +@pytest.fixture(scope="module", autouse=True) +def setup_test_environment(): + # We only need to install chromedriver outside CI. + if not os.getenv("CI"): + chromedriver_autoinstaller.install() + + +@pytest.mark.filterwarnings("ignore::langchain_core._api.beta_decorator.LangChainBetaWarning") +@pytest.mark.filterwarnings("ignore::UserWarning") +@pytest.mark.filterwarnings("ignore:HTTPResponse.getheader()") +def test_simple_dashboard(dash_duo): + input_text = """ + I need a page with 1 table. + The table shows the tech companies stock data. + + I need a second page showing 2 cards and one chart. + The first card says 'The Gapminder dataset provides historical data on countries' development indicators.' + The chart is an scatter plot showing life expectancy vs. GDP per capita by country. Life expectancy on the y axis, + GDP per capita on the x axis, and colored by continent. + The second card says 'Data spans from 1952 to 2007 across various countries.' + The layout uses a grid of 3 columns and 2 rows. + + Row 1: The first row has three columns: + The first column is occupied by the first card. + The second and third columns are spanned by the chart. + + Row 2: The second row mirrors the layout of the first row with respect to chart, but the first column is occupied + by the second card. + + Add a filter to filter the scatter plot by continent. + Add a second filter to filter the chart by year. + """ + + dashboard = vizro_ai.dashboard([df1, df2], input_text) + app = Vizro().build(dashboard).dash + dash_duo.start_server(app) + assert dash_duo.get_logs() == []