diff --git a/tests/mutations/r2b.toml b/tests/mutations/r2b.toml index 877f01d..8b0f494 100644 --- a/tests/mutations/r2b.toml +++ b/tests/mutations/r2b.toml @@ -262,3 +262,23 @@ old = ''' .blurred-thumb{filter:blur(16px)}''' new = ''' .blurred-thumb{filter:blur(0px)}''' + +# ---- the flake: the test browser has no internet (positive control per file) + +[[mutation]] +label = "the flow test browser can reach the internet (Google Fonts can stall networkidle)" +file = "tests/test_flow_browser.py" +test = "tests/test_flow_browser.py::test_the_test_browser_has_no_internet" +old = ''' + b = pw.chromium.launch(args=OFFLINE)''' +new = ''' + b = pw.chromium.launch()''' + +[[mutation]] +label = "the embed test browser can reach the internet" +file = "tests/test_embed_browser.py" +test = "tests/test_embed_browser.py::test_the_test_browser_has_no_internet" +old = ''' + b = pw.chromium.launch(args=OFFLINE)''' +new = ''' + b = pw.chromium.launch()''' diff --git a/tests/test_embed_browser.py b/tests/test_embed_browser.py index 162146b..2b18fa4 100644 --- a/tests/test_embed_browser.py +++ b/tests/test_embed_browser.py @@ -31,11 +31,22 @@ playwright_api = pytest.importorskip( ) +# NO INTERNET for the test browser. Every Booth page asks fonts.googleapis.com +# for its faces, and "networkidle" waits for that request — so a stalled request +# to Google hung the page until goto's 30s timeout, the failure mode of the +# full-suite flake (Page.goto timeouts in tests far apart in one run; a stalled +# font request reproduces it exactly). Whether that was THE cause is unproven; +# a test that depends on Google being reachable is wrong regardless. Every +# hostname but 127.0.0.1 now fails DNS at once, and the pages fall back to the +# system stacks the tokens declare. Positive control: test_*_has_no_internet. +OFFLINE = ["--host-resolver-rules=MAP * ~NOTFOUND , EXCLUDE 127.0.0.1"] + + @pytest.fixture(scope="module") def browser(): with playwright_api.sync_playwright() as pw: try: - b = pw.chromium.launch() + b = pw.chromium.launch(args=OFFLINE) except Exception as exc: # noqa: BLE001 - any launch failure is a skip pytest.skip(f"no usable chromium: {exc}") yield b @@ -638,3 +649,24 @@ def test_the_keyboard_flag_actually_submits(browser, live): assert flagged == 1, f"the f key flagged {flagged} items, expected 1" assert survived, "the flag reloaded the page; in-place judgment must not" + + +def test_the_test_browser_has_no_internet(browser, live): + """Positive control for OFFLINE (booth-dev's ask: see the fix in force, + don't assume it). An external host fails at once, and a Booth page — whose + fonts are external — still goes idle in well under the goto timeout.""" + base, root = live + (root / "g").mkdir() + page = browser.new_page() + t = time.time() + with pytest.raises(Exception) as err: + page.goto("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans", timeout=10000) + external = time.time() - t + page.close() + page = browser.new_page() + t = time.time() + page.goto(f"{base}/b/g/", wait_until="networkidle") + local = time.time() - t + page.close() + assert "ERR_NAME_NOT_RESOLVED" in str(err.value) and external < 3, (str(err.value)[:80], external) + assert local < 10, local diff --git a/tests/test_flow_browser.py b/tests/test_flow_browser.py index bbeb127..7757147 100644 --- a/tests/test_flow_browser.py +++ b/tests/test_flow_browser.py @@ -24,11 +24,22 @@ playwright_api = pytest.importorskip("playwright.sync_api", reason="playwright i PNG = b"\x89PNG\r\n\x1a\n" +# NO INTERNET for the test browser. Every Booth page asks fonts.googleapis.com +# for its faces, and "networkidle" waits for that request — so a stalled request +# to Google hung the page until goto's 30s timeout, the failure mode of the +# full-suite flake (Page.goto timeouts in tests far apart in one run; a stalled +# font request reproduces it exactly). Whether that was THE cause is unproven; +# a test that depends on Google being reachable is wrong regardless. Every +# hostname but 127.0.0.1 now fails DNS at once, and the pages fall back to the +# system stacks the tokens declare. Positive control: test_*_has_no_internet. +OFFLINE = ["--host-resolver-rules=MAP * ~NOTFOUND , EXCLUDE 127.0.0.1"] + + @pytest.fixture(scope="module") def browser(): with playwright_api.sync_playwright() as pw: try: - b = pw.chromium.launch() + b = pw.chromium.launch(args=OFFLINE) except Exception as exc: # noqa: BLE001 - any launch failure is a skip pytest.skip(f"no usable chromium: {exc}") yield b @@ -773,3 +784,24 @@ def test_the_review_and_doc_top_bars_fit_a_phone(browser, live): '.vbar button, .vbar .vbtn')].filter(e => e.offsetParent).map(e => e.getBoundingClientRect().height)) - 40""") page.close() assert all(v <= 0 for v in over.values()), over + + +def test_the_test_browser_has_no_internet(browser, live): + """Positive control for OFFLINE (booth-dev's ask: see the fix in force, + don't assume it). An external host fails at once, and a Booth page — whose + fonts are external — still goes idle in well under the goto timeout.""" + base, root = live + (root / "g").mkdir() + page = browser.new_page() + t = time.time() + with pytest.raises(Exception) as err: + page.goto("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans", timeout=10000) + external = time.time() - t + page.close() + page = browser.new_page() + t = time.time() + page.goto(f"{base}/b/g/", wait_until="networkidle") + local = time.time() - t + page.close() + assert "ERR_NAME_NOT_RESOLVED" in str(err.value) and external < 3, (str(err.value)[:80], external) + assert local < 10, local