diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index ad355f70b..ccaf669f5 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -193,6 +193,15 @@ jobs: working-directory: examples/brownian/shinymediapipe run: | npm ci + - name: Checkout py-shiny-templates repository + uses: actions/checkout@v4 + with: + repository: posit-dev/py-shiny-templates + path: py-shiny-templates + + - name: Install py-shiny-templates dependencies + run: | + make install-py-shiny-templates-deps - name: Run example app tests timeout-minutes: 60 diff --git a/Makefile b/Makefile index 215ef4cb4..1a8c9338e 100644 --- a/Makefile +++ b/Makefile @@ -220,13 +220,15 @@ ci-install-wheel: dist FORCE uv pip install dist/shiny*.whl install-deps: FORCE ## install dependencies - pip install -e ".[dev,test]" --upgrade + uv pip install -e ".[dev,test]" --upgrade ci-install-deps: FORCE uv pip install -e ".[dev,test]" +install-py-shiny-templates-deps: FORCE + uv pip install -r py-shiny-templates/requirements.txt install-docs: FORCE - pip install -e ".[dev,test,doc]" - pip install https://github.com/posit-dev/py-shinylive/tarball/main + uv pip install -e ".[dev,test,doc]" + uv pip install https://github.com/posit-dev/py-shinylive/tarball/main ci-install-docs: FORCE uv pip install -e ".[dev,test,doc]" \ "shinylive @ git+https://github.com/posit-dev/py-shinylive.git" diff --git a/pyproject.toml b/pyproject.toml index 0a5ef7e76..f69807faa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,6 +91,7 @@ test = [ "dask[dataframe]", "pyarrow", "pyarrow-stubs", + ] dev = [ "black>=24.0", diff --git a/tests/playwright/examples/example_apps.py b/tests/playwright/examples/example_apps.py index a3bf05c1a..2dce2eab2 100644 --- a/tests/playwright/examples/example_apps.py +++ b/tests/playwright/examples/example_apps.py @@ -4,7 +4,7 @@ from pathlib import PurePath from typing import Literal -from playwright.sync_api import ConsoleMessage, Page +from playwright.sync_api import ConsoleMessage, Page, expect from shiny.run import ShinyAppProc, run_shiny_app @@ -15,6 +15,9 @@ reruns = 1 if is_interactive else 3 reruns_delay = 0 +SHINY_INIT_TIMEOUT = 30_000 +ERROR_ELEMENT_TIMEOUT = 1_000 + def get_apps(path: str) -> typing.List[str]: full_path = pyshiny_root / path @@ -95,6 +98,13 @@ def get_apps(path: str) -> typing.List[str]: "examples/brownian": ["Failed to acquire camera feed:"], } +# Check for Shiny output errors, except for known exception cases +app_allow_output_error = [ + "shiny/api-examples/SafeException/app-express.py", + "shiny/api-examples/SafeException/app-core.py", + "examples/global_pyplot/app.py", +] + # Altered from `shinytest2:::app_wait_for_idle()` # https://github.com/rstudio/shinytest2/blob/b8fdce681597e9610fc078aa6e376134c404f3bd/R/app-driver-wait.R @@ -250,3 +260,8 @@ def on_console_msg(msg: ConsoleMessage) -> None: + " had JavaScript console errors!\n" + "* ".join(console_errors) ) + + if ex_app_path not in app_allow_output_error: + # Ensure there are no output errors present + error_locator = page.locator(".shiny-output-error") + expect(error_locator).to_have_count(0, timeout=ERROR_ELEMENT_TIMEOUT) diff --git a/tests/playwright/examples/test_external_templates.py b/tests/playwright/examples/test_external_templates.py new file mode 100644 index 000000000..ae158b8ab --- /dev/null +++ b/tests/playwright/examples/test_external_templates.py @@ -0,0 +1,20 @@ +from pathlib import Path + +import pytest +from conftest import here_root +from example_apps import get_apps, reruns, reruns_delay, validate_example +from playwright.sync_api import Page + +if not Path(here_root / "py-shiny-templates").exists(): + pytest.skip( + "./py-shiny-templates dir is not available. Skipping test.", + allow_module_level=True, + ) + + +@pytest.mark.only_browser("chromium") +@pytest.mark.flaky(reruns=reruns, reruns_delay=reruns_delay) +@pytest.mark.parametrize("ex_app_path", get_apps("py-shiny-templates")) +def test_external_templates(page: Page, ex_app_path: str) -> None: + + validate_example(page, ex_app_path) diff --git a/tests/playwright/shiny/components/data_frame/edit/app.py b/tests/playwright/shiny/components/data_frame/edit/app.py index 2f8707e39..ed7c580b1 100644 --- a/tests/playwright/shiny/components/data_frame/edit/app.py +++ b/tests/playwright/shiny/components/data_frame/edit/app.py @@ -1,6 +1,7 @@ from __future__ import annotations import pkgutil +from typing import Any # pyright: reportUnknownMemberType = false # pyright: reportMissingTypeStubs = false @@ -264,7 +265,7 @@ def df_styles_fn(data: pd.DataFrame) -> list[StyleInfo]: # from shiny import reactive @render_widget - def country_detail_pop(): + def country_detail_pop() -> Any: import plotly.express as px return px.line(