From 7f5883c918d5f6df54c1f749abe60a92b5912d50 Mon Sep 17 00:00:00 2001 From: Kahlil Hodgson Date: Mon, 9 Mar 2026 22:33:38 +1100 Subject: [PATCH 1/6] Fix AppHarnessProd to find 404.html under frontend_path prefix When frontend_path is set, the build output (including 404.html) is nested under that prefix directory. Update the static file server to mirror what sirv does in real prod deployments. --- reflex/testing.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/reflex/testing.py b/reflex/testing.py index 4ab72602334..a61470b6204 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -1050,8 +1050,13 @@ def _run_frontend(self): / reflex.utils.prerequisites.get_web_dir() / reflex.constants.Dirs.STATIC ) + # When frontend_path is set, the build output (including 404.html) is + # nested under that prefix directory, mirroring what sirv does in real + # prod deployments (see PackageJson.Commands.get_prod_command). + frontend_path = reflex.config.get_config().frontend_path.strip("/") + error_dir = web_root / frontend_path if frontend_path else web_root error_page_map = { - 404: web_root / "404.html", + 404: error_dir / "404.html", } with Subdir404TCPServer( ("", 0), From eaa4237cb3e1bde91bae7c089b8711526e11bbc0 Mon Sep 17 00:00:00 2001 From: Kahlil Hodgson Date: Mon, 9 Mar 2026 22:34:14 +1100 Subject: [PATCH 2/6] Add integration tests for frontend_path redirects Test on_load and on_mount redirects with and without a frontend_path prefix in both dev mode (AppHarness) and prod mode (AppHarnessProd). See https://github.com/reflex-dev/reflex/issues/5674 --- .../tests_playwright/test_frontend_path.py | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 tests/integration/tests_playwright/test_frontend_path.py diff --git a/tests/integration/tests_playwright/test_frontend_path.py b/tests/integration/tests_playwright/test_frontend_path.py new file mode 100644 index 00000000000..1a2b7b2fb99 --- /dev/null +++ b/tests/integration/tests_playwright/test_frontend_path.py @@ -0,0 +1,282 @@ +import os +from collections.abc import Generator + +import pytest +from playwright.sync_api import Page, expect + +from reflex.testing import AppHarness, AppHarnessProd + + +def OnLoadRedirectApp(): + """App to demonstrate an on_load redirection issue. + + See https://github.com/reflex-dev/reflex/issues/5674 for details. + """ + import reflex as rx + + @rx.page("/") + def index(): + return rx.container( + rx.input( + value=rx.State.router.session.client_token, + read_only=True, + id="token", + ), + rx.vstack( + rx.heading("This is the index page!"), + rx.button("Go to Subpage!", on_click=rx.redirect("/subpage")), + ), + ) + + @rx.page("/subpage") + def subpage(): + return rx.container( + rx.vstack( + rx.heading("This is the sub page!"), + rx.button("Go to index!", on_click=rx.redirect("/")), + rx.button("Bounce to index!", on_click=rx.redirect("/bouncer")), + ) + ) + + @rx.page("/bouncer", on_load=rx.redirect("/")) + def bouncer(): + return rx.container( + rx.vstack( + rx.heading("This is the bouncer page!"), + rx.text("You should not be here!"), + rx.button("Go to index!", on_click=rx.redirect("/")), + ), + ) + + app = rx.App() # noqa: F841 + + +@pytest.fixture +def onload_redirect_app(tmp_path) -> Generator[AppHarness, None, None]: + """Start the OnLoadRedirectApp in prod mode without a frontend_path. + + Baseline to show on_load redirects work without a frontend_path. + + Args: + tmp_path: pytest tmp_path fixture + + Yields: + running AppHarness instance + """ + with AppHarnessProd.create( + root=tmp_path / "onload_redirect_app", + app_source=OnLoadRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +@pytest.fixture +def onload_redirect_with_prefix_app_dev(tmp_path) -> Generator[AppHarness, None, None]: + """Start the OnLoadRedirectApp in dev mode with frontend_path set to /prefix. + + Args: + tmp_path: pytest tmp_path fixture + + Yields: + running AppHarness instance + """ + os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" + try: + with AppHarness.create( + root=tmp_path / "onload_redirect_with_prefix_app_dev", + app_source=OnLoadRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + finally: + os.environ.pop("REFLEX_FRONTEND_PATH", None) + + +@pytest.fixture +def onload_redirect_with_prefix_app_prod( + tmp_path, +) -> Generator[AppHarness, None, None]: + """Start the OnLoadRedirectApp in prod mode with frontend_path set to /prefix. + + Args: + tmp_path: pytest tmp_path fixture + + Yields: + running AppHarness instance + """ + os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" + try: + with AppHarnessProd.create( + root=tmp_path / "onload_redirect_with_prefix_app_prod", + app_source=OnLoadRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + finally: + os.environ.pop("REFLEX_FRONTEND_PATH", None) + + +def OnMountRedirectApp(): + """App to demonstrate on_mount redirection behaviour.""" + import reflex as rx + + @rx.page("/") + def index(): + return rx.container( + rx.input( + value=rx.State.router.session.client_token, + read_only=True, + id="token", + ), + rx.vstack( + rx.heading("This is the index page!"), + rx.button("Go to Subpage!", on_click=rx.redirect("/subpage")), + ), + ) + + @rx.page("/subpage") + def subpage(): + return rx.container( + rx.vstack( + rx.heading("This is the sub page!"), + rx.button("Go to index!", on_click=rx.redirect("/")), + rx.button("Bounce to index!", on_click=rx.redirect("/bouncer")), + ) + ) + + @rx.page("/bouncer") + def bouncer(): + return rx.container( + rx.vstack( + rx.heading("This is the bouncer page!"), + rx.text("You should not be here!"), + rx.spinner("Go to index!", on_mount=rx.redirect("/")), + ), + ) + + app = rx.App() # noqa: F841 + + +@pytest.fixture +def onmount_redirect_app(tmp_path) -> Generator[AppHarness, None, None]: + """Start the OnMountRedirectApp in prod mode without a frontend_path. + + Baseline to show on_mount redirects work without a frontend_path. + + Args: + tmp_path: pytest tmp_path fixture + + Yields: + running AppHarness instance + """ + with AppHarnessProd.create( + root=tmp_path / "onmount_redirect_app", + app_source=OnMountRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +@pytest.fixture +def onmount_redirect_with_prefix_app_dev( + tmp_path, +) -> Generator[AppHarness, None, None]: + """Start the OnMountRedirectApp in dev mode with frontend_path set to /prefix. + + Args: + tmp_path: pytest tmp_path fixture + + Yields: + running AppHarness instance + """ + os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" + try: + with AppHarness.create( + root=tmp_path / "onmount_redirect_with_prefix_app_dev", + app_source=OnMountRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + finally: + os.environ.pop("REFLEX_FRONTEND_PATH", None) + + +@pytest.fixture +def onmount_redirect_with_prefix_app_prod( + tmp_path, +) -> Generator[AppHarness, None, None]: + """Start the OnMountRedirectApp in prod mode with frontend_path set to /prefix. + + Args: + tmp_path: pytest tmp_path fixture + + Yields: + running AppHarness instance + """ + os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" + try: + with AppHarnessProd.create( + root=tmp_path / "onmount_redirect_with_prefix_app_prod", + app_source=OnMountRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + finally: + os.environ.pop("REFLEX_FRONTEND_PATH", None) + + +@pytest.mark.ignore_console_error +@pytest.mark.parametrize( + ("app_fixture_name", "frontend_path"), + [ + ("onload_redirect_app", ""), + ("onload_redirect_with_prefix_app_dev", "/prefix"), + ("onload_redirect_with_prefix_app_prod", "/prefix"), + ("onmount_redirect_app", ""), + ("onmount_redirect_with_prefix_app_dev", "/prefix"), + ("onmount_redirect_with_prefix_app_prod", "/prefix"), + ], +) +def test_redirection_triggers( + app_fixture_name: str, frontend_path: str, page: Page, request +): + """Ensure that on_load and on_mount redirects work with/without a frontend_path. + + Tests both dev mode (AppHarness) and prod mode (AppHarnessProd) to cover + the bug reported in https://github.com/reflex-dev/reflex/issues/5674, + where redirects from on_load and on_mount handlers were lost when serving + from a non-root frontend path. + + Args: + app_fixture_name: Name of the app fixture to use for the test. + frontend_path: The frontend_path used by the app fixture. + page: Playwright Page object to interact with the app. + request: Pytest request object to access fixtures. + """ + app_fixture = request.getfixturevalue(app_fixture_name) + assert app_fixture.frontend_url is not None + + base_url = app_fixture.frontend_url.rstrip("/") + base_url += frontend_path + page.goto(f"{base_url}/") + expect(page.get_by_text("This is the index page!")).to_be_visible() + + # Go to /subpage + page.get_by_role("button", name="Go to Subpage!").click() + expect(page.get_by_text("This is the sub page!")).to_be_visible() + expect(page).to_have_url(f"{base_url}/subpage") + + # Click "Bounce to index!" (should redirect to index via on_load/on_mount) + page.get_by_role("button", name="Bounce to index!").click() + expect(page.get_by_text("This is the index page!")).to_be_visible() + expect(page).to_have_url(f"{base_url}/") + + # Directly navigate to /bouncer/ and verify redirect + page.goto(f"{base_url}/bouncer/") + expect(page.get_by_text("This is the index page!")).to_be_visible() + + # Check that 404's work and do not change the url + page.goto(f"{base_url}/not-a-page") + expect(page.get_by_text("404: Page not found")).to_be_visible() + expect(page).to_have_url(f"{base_url}/not-a-page") From 4c7b3c94ddd9c5b3bf58cf16c76ff17975192a34 Mon Sep 17 00:00:00 2001 From: Kahlil Hodgson Date: Mon, 9 Mar 2026 22:34:45 +1100 Subject: [PATCH 3/6] Fix link hover test to disable built-with-reflex badge Use REFLEX_SHOW_BUILT_WITH_REFLEX env var to set the Config value, avoiding the need for a custom environment variable definition. --- .../tests_playwright/test_link_hover.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/integration/tests_playwright/test_link_hover.py b/tests/integration/tests_playwright/test_link_hover.py index c4a473f410f..2c1e38f8f7b 100644 --- a/tests/integration/tests_playwright/test_link_hover.py +++ b/tests/integration/tests_playwright/test_link_hover.py @@ -1,3 +1,4 @@ +import os from collections.abc import Generator import pytest @@ -27,12 +28,16 @@ def index(): @pytest.fixture def link_app(tmp_path_factory) -> Generator[AppHarness, None, None]: - with AppHarness.create( - root=tmp_path_factory.mktemp("link_app"), - app_source=LinkApp, - ) as harness: - assert harness.app_instance is not None, "app is not running" - yield harness + os.environ["REFLEX_SHOW_BUILT_WITH_REFLEX"] = "false" + try: + with AppHarness.create( + root=tmp_path_factory.mktemp("link_app"), + app_source=LinkApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + finally: + os.environ.pop("REFLEX_SHOW_BUILT_WITH_REFLEX", None) def test_link_hover(link_app: AppHarness, page: Page): From 4be4cbe7d0d619855a7a1ff80abbac5c10e48252 Mon Sep 17 00:00:00 2001 From: Kahlil Hodgson Date: Mon, 9 Mar 2026 22:37:54 +1100 Subject: [PATCH 4/6] Add comments explaining why env vars are used instead of Config AppHarness._initialize_app calls get_config(reload=True), which resets any direct Config mutations made before the harness starts. --- tests/integration/tests_playwright/test_frontend_path.py | 2 ++ tests/integration/tests_playwright/test_link_hover.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/integration/tests_playwright/test_frontend_path.py b/tests/integration/tests_playwright/test_frontend_path.py index 1a2b7b2fb99..63deedc56ec 100644 --- a/tests/integration/tests_playwright/test_frontend_path.py +++ b/tests/integration/tests_playwright/test_frontend_path.py @@ -81,6 +81,8 @@ def onload_redirect_with_prefix_app_dev(tmp_path) -> Generator[AppHarness, None, Yields: running AppHarness instance """ + # Set via env var rather than Config directly because AppHarness._initialize_app + # calls get_config(reload=True), which resets any prior Config mutations. os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" try: with AppHarness.create( diff --git a/tests/integration/tests_playwright/test_link_hover.py b/tests/integration/tests_playwright/test_link_hover.py index 2c1e38f8f7b..1b527543f48 100644 --- a/tests/integration/tests_playwright/test_link_hover.py +++ b/tests/integration/tests_playwright/test_link_hover.py @@ -28,6 +28,8 @@ def index(): @pytest.fixture def link_app(tmp_path_factory) -> Generator[AppHarness, None, None]: + # Set via env var rather than Config directly because AppHarness._initialize_app + # calls get_config(reload=True), which resets any prior Config mutations. os.environ["REFLEX_SHOW_BUILT_WITH_REFLEX"] = "false" try: with AppHarness.create( From 1b9a94b9cbecfc5ded915136fec8a64ddfc911c4 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 9 Mar 2026 14:29:40 -0700 Subject: [PATCH 5/6] consolidate tests into a single app faster run time, less code --- .../tests_playwright/test_frontend_path.py | 180 +++++------------- 1 file changed, 44 insertions(+), 136 deletions(-) diff --git a/tests/integration/tests_playwright/test_frontend_path.py b/tests/integration/tests_playwright/test_frontend_path.py index 63deedc56ec..55bf1b5cfa4 100644 --- a/tests/integration/tests_playwright/test_frontend_path.py +++ b/tests/integration/tests_playwright/test_frontend_path.py @@ -1,5 +1,5 @@ -import os from collections.abc import Generator +from pathlib import Path import pytest from playwright.sync_api import Page, expect @@ -34,7 +34,10 @@ def subpage(): rx.vstack( rx.heading("This is the sub page!"), rx.button("Go to index!", on_click=rx.redirect("/")), - rx.button("Bounce to index!", on_click=rx.redirect("/bouncer")), + rx.button("Bounce to index on_load!", on_click=rx.redirect("/bouncer")), + rx.button( + "Bounce to index on_mount!", on_click=rx.redirect("/bouncer-mount") + ), ) ) @@ -48,11 +51,21 @@ def bouncer(): ), ) + @rx.page("/bouncer-mount") + def bouncer_mount(): + return rx.container( + rx.vstack( + rx.heading("This is the bouncer page!"), + rx.text("You should not be here!"), + rx.spinner("Go to index!", on_mount=rx.redirect("/")), + ), + ) + app = rx.App() # noqa: F841 @pytest.fixture -def onload_redirect_app(tmp_path) -> Generator[AppHarness, None, None]: +def onload_redirect_app(tmp_path: Path) -> Generator[AppHarness, None, None]: """Start the OnLoadRedirectApp in prod mode without a frontend_path. Baseline to show on_load redirects work without a frontend_path. @@ -72,162 +85,51 @@ def onload_redirect_app(tmp_path) -> Generator[AppHarness, None, None]: @pytest.fixture -def onload_redirect_with_prefix_app_dev(tmp_path) -> Generator[AppHarness, None, None]: +def onload_redirect_with_prefix_app_dev( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> Generator[AppHarness, None, None]: """Start the OnLoadRedirectApp in dev mode with frontend_path set to /prefix. Args: tmp_path: pytest tmp_path fixture + monkeypatch: pytest monkeypatch fixture to set env var Yields: running AppHarness instance """ # Set via env var rather than Config directly because AppHarness._initialize_app # calls get_config(reload=True), which resets any prior Config mutations. - os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" - try: - with AppHarness.create( - root=tmp_path / "onload_redirect_with_prefix_app_dev", - app_source=OnLoadRedirectApp, - ) as harness: - assert harness.app_instance is not None, "app is not running" - yield harness - finally: - os.environ.pop("REFLEX_FRONTEND_PATH", None) + monkeypatch.setenv("REFLEX_FRONTEND_PATH", "/prefix") + with AppHarness.create( + root=tmp_path / "onload_redirect_with_prefix_app_dev", + app_source=OnLoadRedirectApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness @pytest.fixture def onload_redirect_with_prefix_app_prod( - tmp_path, + tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> Generator[AppHarness, None, None]: """Start the OnLoadRedirectApp in prod mode with frontend_path set to /prefix. Args: tmp_path: pytest tmp_path fixture + monkeypatch: pytest monkeypatch fixture to set env var Yields: running AppHarness instance """ - os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" - try: - with AppHarnessProd.create( - root=tmp_path / "onload_redirect_with_prefix_app_prod", - app_source=OnLoadRedirectApp, - ) as harness: - assert harness.app_instance is not None, "app is not running" - yield harness - finally: - os.environ.pop("REFLEX_FRONTEND_PATH", None) - - -def OnMountRedirectApp(): - """App to demonstrate on_mount redirection behaviour.""" - import reflex as rx - - @rx.page("/") - def index(): - return rx.container( - rx.input( - value=rx.State.router.session.client_token, - read_only=True, - id="token", - ), - rx.vstack( - rx.heading("This is the index page!"), - rx.button("Go to Subpage!", on_click=rx.redirect("/subpage")), - ), - ) - - @rx.page("/subpage") - def subpage(): - return rx.container( - rx.vstack( - rx.heading("This is the sub page!"), - rx.button("Go to index!", on_click=rx.redirect("/")), - rx.button("Bounce to index!", on_click=rx.redirect("/bouncer")), - ) - ) - - @rx.page("/bouncer") - def bouncer(): - return rx.container( - rx.vstack( - rx.heading("This is the bouncer page!"), - rx.text("You should not be here!"), - rx.spinner("Go to index!", on_mount=rx.redirect("/")), - ), - ) - - app = rx.App() # noqa: F841 - - -@pytest.fixture -def onmount_redirect_app(tmp_path) -> Generator[AppHarness, None, None]: - """Start the OnMountRedirectApp in prod mode without a frontend_path. - - Baseline to show on_mount redirects work without a frontend_path. - - Args: - tmp_path: pytest tmp_path fixture - - Yields: - running AppHarness instance - """ + monkeypatch.setenv("REFLEX_FRONTEND_PATH", "/prefix") with AppHarnessProd.create( - root=tmp_path / "onmount_redirect_app", - app_source=OnMountRedirectApp, + root=tmp_path / "onload_redirect_with_prefix_app_prod", + app_source=OnLoadRedirectApp, ) as harness: assert harness.app_instance is not None, "app is not running" yield harness -@pytest.fixture -def onmount_redirect_with_prefix_app_dev( - tmp_path, -) -> Generator[AppHarness, None, None]: - """Start the OnMountRedirectApp in dev mode with frontend_path set to /prefix. - - Args: - tmp_path: pytest tmp_path fixture - - Yields: - running AppHarness instance - """ - os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" - try: - with AppHarness.create( - root=tmp_path / "onmount_redirect_with_prefix_app_dev", - app_source=OnMountRedirectApp, - ) as harness: - assert harness.app_instance is not None, "app is not running" - yield harness - finally: - os.environ.pop("REFLEX_FRONTEND_PATH", None) - - -@pytest.fixture -def onmount_redirect_with_prefix_app_prod( - tmp_path, -) -> Generator[AppHarness, None, None]: - """Start the OnMountRedirectApp in prod mode with frontend_path set to /prefix. - - Args: - tmp_path: pytest tmp_path fixture - - Yields: - running AppHarness instance - """ - os.environ["REFLEX_FRONTEND_PATH"] = "/prefix" - try: - with AppHarnessProd.create( - root=tmp_path / "onmount_redirect_with_prefix_app_prod", - app_source=OnMountRedirectApp, - ) as harness: - assert harness.app_instance is not None, "app is not running" - yield harness - finally: - os.environ.pop("REFLEX_FRONTEND_PATH", None) - - @pytest.mark.ignore_console_error @pytest.mark.parametrize( ("app_fixture_name", "frontend_path"), @@ -235,13 +137,15 @@ def onmount_redirect_with_prefix_app_prod( ("onload_redirect_app", ""), ("onload_redirect_with_prefix_app_dev", "/prefix"), ("onload_redirect_with_prefix_app_prod", "/prefix"), - ("onmount_redirect_app", ""), - ("onmount_redirect_with_prefix_app_dev", "/prefix"), - ("onmount_redirect_with_prefix_app_prod", "/prefix"), ], ) +@pytest.mark.parametrize("redirect_type", ["on_load", "on_mount"]) def test_redirection_triggers( - app_fixture_name: str, frontend_path: str, page: Page, request + app_fixture_name: str, + frontend_path: str, + redirect_type: str, + page: Page, + request: pytest.FixtureRequest, ): """Ensure that on_load and on_mount redirects work with/without a frontend_path. @@ -253,6 +157,7 @@ def test_redirection_triggers( Args: app_fixture_name: Name of the app fixture to use for the test. frontend_path: The frontend_path used by the app fixture. + redirect_type: Whether to test on_load or on_mount redirection. page: Playwright Page object to interact with the app. request: Pytest request object to access fixtures. """ @@ -270,12 +175,15 @@ def test_redirection_triggers( expect(page).to_have_url(f"{base_url}/subpage") # Click "Bounce to index!" (should redirect to index via on_load/on_mount) - page.get_by_role("button", name="Bounce to index!").click() + page.get_by_role("button", name=f"Bounce to index {redirect_type}!").click() expect(page.get_by_text("This is the index page!")).to_be_visible() expect(page).to_have_url(f"{base_url}/") # Directly navigate to /bouncer/ and verify redirect - page.goto(f"{base_url}/bouncer/") + if redirect_type == "on_mount": + page.goto(f"{base_url}/bouncer-mount/") + else: + page.goto(f"{base_url}/bouncer/") expect(page.get_by_text("This is the index page!")).to_be_visible() # Check that 404's work and do not change the url From 0afccdf26a571006fbe238d8105ef15069837e33 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 9 Mar 2026 15:04:11 -0700 Subject: [PATCH 6/6] use monkeypatch instead of os.environ --- .../tests_playwright/test_link_hover.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/integration/tests_playwright/test_link_hover.py b/tests/integration/tests_playwright/test_link_hover.py index 1b527543f48..d03bc4e6574 100644 --- a/tests/integration/tests_playwright/test_link_hover.py +++ b/tests/integration/tests_playwright/test_link_hover.py @@ -1,4 +1,3 @@ -import os from collections.abc import Generator import pytest @@ -27,19 +26,16 @@ def index(): @pytest.fixture -def link_app(tmp_path_factory) -> Generator[AppHarness, None, None]: +def link_app(tmp_path_factory, monkeypatch) -> Generator[AppHarness, None, None]: # Set via env var rather than Config directly because AppHarness._initialize_app # calls get_config(reload=True), which resets any prior Config mutations. - os.environ["REFLEX_SHOW_BUILT_WITH_REFLEX"] = "false" - try: - with AppHarness.create( - root=tmp_path_factory.mktemp("link_app"), - app_source=LinkApp, - ) as harness: - assert harness.app_instance is not None, "app is not running" - yield harness - finally: - os.environ.pop("REFLEX_SHOW_BUILT_WITH_REFLEX", None) + monkeypatch.setenv("REFLEX_SHOW_BUILT_WITH_REFLEX", "false") + with AppHarness.create( + root=tmp_path_factory.mktemp("link_app"), + app_source=LinkApp, + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness def test_link_hover(link_app: AppHarness, page: Page):