From 0b921723225b6636009d32427a0bfe6e66407d07 Mon Sep 17 00:00:00 2001 From: maziggy Date: Tue, 5 May 2026 14:35:08 +0200 Subject: [PATCH] fix(tests): make SPA cache-header tests work without a built frontend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backend/tests/integration/test_static_html_cache_headers.py asserted that "/", "/spoolbuddy/", and "/printers" return text/html with Cache-Control: no-cache, must-revalidate. The Dockerfile.test backend-test target intentionally doesn't bake in the built frontend (saves ~30s of build time per test run), so static/index.html doesn't exist inside the container. The route handlers correctly fall through to their "frontend not built" JSON branches, and the test fails with "non-HTML content-type: application/json" — latent since the test was added in e9200449 (Apr 26). Add a fake_static_index fixture that creates a tmp dir with a one-line stub and monkeypatches app_settings.static_dir to it. Both call sites are patched (config.settings and main.app_settings) in case a future refactor splits the singleton. The test continues to hit the real serve_frontend / serve_spa route handlers and validates the real cache-header contract — just doesn't depend on a built bundle being present. Verified passing both with and without static/index.html present. --- .../test_static_html_cache_headers.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/backend/tests/integration/test_static_html_cache_headers.py b/backend/tests/integration/test_static_html_cache_headers.py index 56d025380..17c055fd3 100644 --- a/backend/tests/integration/test_static_html_cache_headers.py +++ b/backend/tests/integration/test_static_html_cache_headers.py @@ -42,9 +42,38 @@ HTML_ROUTES = [ ] +@pytest.fixture +def fake_static_index(monkeypatch, tmp_path): + """Provide a minimal ``static/index.html`` so the route handlers don't + fall through to their "frontend not built" JSON branch. + + The ``backend-test`` Dockerfile.test target intentionally doesn't bake + in the built frontend (saves ~30 s of build time per test run), and + contributors running ``pytest backend/tests/`` from a checkout without + a prior ``npm run build`` would also miss it. The test asserts the + cache-header contract on the index.html serve path, not the bundle + contents — so a one-line stub is enough to exercise the real route + handlers in ``main.py:serve_frontend`` / ``main.py:serve_spa`` against + a real ``index.html`` on disk. + """ + from backend.app import main as main_mod + from backend.app.core import config as config_mod + + static_dir = tmp_path / "static" + static_dir.mkdir() + (static_dir / "index.html").write_text("stub") + + monkeypatch.setattr(config_mod.settings, "static_dir", static_dir) + # main.py imports `settings as app_settings`, so the route handlers + # resolve `app_settings.static_dir` per request. Patch the import-site + # binding too in case future refactors stop sharing the singleton. + monkeypatch.setattr(main_mod.app_settings, "static_dir", static_dir) + return static_dir + + @pytest.mark.asyncio @pytest.mark.parametrize(("path",), HTML_ROUTES) -async def test_index_html_emits_no_cache_directive(async_client: AsyncClient, path: str): +async def test_index_html_emits_no_cache_directive(async_client: AsyncClient, fake_static_index, path: str): """Every index.html serve must emit ``Cache-Control: no-cache, must-revalidate`` — kiosks rely on this to pick up new builds without operator intervention."""