From bfa15aabab5f1fa27f050121ea4d55b0dc8be8b3 Mon Sep 17 00:00:00 2001 From: User Date: Tue, 22 Sep 2026 04:54:30 +0000 Subject: [PATCH] Fix flaky `test_one_websocket_per_page` after the offline test `test_offline_component` tears down the offline webserver while the shared Playwright page is still on the /offline/ page. That page's client (`createReconnectingWebSocket`) keeps retrying the now-dead port on a backoff timer, so a reconnect attempt that lands inside the next test's navigation window leaks a second WebSocket URL and flakes `test_one_websocket_per_page` (observed intermittently on CI as "Expected 1 unique WebSocket URL, got 2 ... /offline/"). Navigating to about:blank at the end of `test_offline_component` destroys the document and cancels its pending reconnect timers, so later tests start from a clean state. --- tests/test_app/tests/test_components.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_app/tests/test_components.py b/tests/test_app/tests/test_components.py index afe5f871..d7bde5e6 100644 --- a/tests/test_app/tests/test_components.py +++ b/tests/test_app/tests/test_components.py @@ -711,6 +711,18 @@ def test_offline_component(self): self.page.wait_for_selector("div:not([hidden]) > #offline") assert self.page.query_selector("div[hidden] > #online") is not None + # Tearing down the server above severs the offline page's WebSocket, but its + # client (createReconnectingWebSocket) keeps retrying the now-dead port on a + # backoff timer for the rest of the session. All tests share one browser page, + # so that zombie loop keeps firing `new WebSocket()` against the dead port + # during subsequent tests. Any attempt that lands inside another test's + # navigation window leaks a second WebSocket URL and flakes tests such as + # `test_one_websocket_per_page` (observed intermittently on CI as + # "Expected 1 unique WebSocket URL, got 2 ... /offline/"). Navigating away + # destroys this document and cancels its pending reconnect timers, so later + # tests start from a clean state with no lingering client. + self.page.goto("about:blank") + ############## # Form Tests # ##############