mirror of
https://github.com/ankitects/anki.git
synced 2026-10-02 05:24:38 +08:00
fix(ci): fix flaky e2e editor tests caused by premature webServer readiness (#5116)
## Linked issue (required) Fixes #5108 ## Summary / motivation (required) `/favicon.ico` responds as soon as mediasrv's HTTP thread starts, before the profile's collection finishes loading, `setupMediaServer()` runs synchronously in `AnkiQt.__init__`, while `setupProfile()` is deferred via a `QTimer`. Playwright's `webServer.url` readiness check polled `/favicon.ico`, so the first e2e test to run in a given CI run could race the async profile load and time out waiting for `.note-editor`, an intermittent false negative, not a real editor bug. This adds `GET /_anki/readyz`, which only returns 200 once `aqt.mw.col` is open (503 otherwise — Playwright's webServer keeps polling on non-2xx/3xx responses), and points `playwright.config.ts`'s `webServer.url` at it instead of `/favicon.ico`. ## Steps to reproduce (required, use N/A if not applicable) 1. Run `just test-e2e` repeatedly on a loaded machine (or add artificial delay to profile loading). 2. Occasionally, the first test in `context-switching.spec.ts` times out at `fixtures.ts:37` (`waitForSelector(".note-editor")`) because Playwright started the test run before the collection had finished opening. 3. See CI failure: https://github.com/ankitects/anki/actions/runs/28748635969/job/85243844164 ## How to test (required) - Ran `just test-e2e` locally and confirmed the suite passes. - Verified `/_anki/readyz` returns 503 immediately after mediasrv starts and 200 once the profile/collection finishes loading, by curling it during `qt/tests/launch_anki_for_e2e.py` startup. - No new test was added — this is a fix to test *infrastructure* (the readiness gate), not to editor behavior; existing e2e specs are the regression coverage. ## Before / after behavior (optional) Before: e2e run could fail intermittently on the first test with a `.note-editor` timeout, unrelated to the change under test. After: `webServer` only accepts traffic once the collection is open, so no test races the profile-load window. ## Risk / compatibility / migration (optional) Low risk. `/_anki/readyz` is a new, isolated, read-only route used only by the e2e harness; no existing behavior changes.
This commit is contained in:
@@ -26,7 +26,11 @@ export default defineConfig({
|
||||
},
|
||||
webServer: {
|
||||
command: `${PYENV_PYTHON} qt/tests/launch_anki_for_e2e.py`,
|
||||
url: `http://127.0.0.1:${MEDIASRV_PORT}/favicon.ico`,
|
||||
// /favicon.ico responds as soon as the HTTP server thread starts,
|
||||
// before the profile's collection has finished loading. /_anki/readyz
|
||||
// only returns 200 once the collection is open, so tests never race
|
||||
// against the async profile-load that follows server startup.
|
||||
url: `http://127.0.0.1:${MEDIASRV_PORT}/_anki/readyz`,
|
||||
timeout: 60_000,
|
||||
reuseExistingServer: process.env.ANKI_E2E_REUSE_SERVER === "1",
|
||||
stdout: "pipe",
|
||||
|
||||
@@ -233,6 +233,22 @@ def favicon() -> Response:
|
||||
return _handle_builtin_file_request(request)
|
||||
|
||||
|
||||
@app.route("/_anki/readyz")
|
||||
def readyz() -> Response:
|
||||
"""Reports whether the profile's collection is open.
|
||||
|
||||
The HTTP server starts listening before the profile/collection finishes
|
||||
loading (setupMediaServer() runs synchronously in AnkiQt.__init__, while
|
||||
setupProfile() is deferred via a QTimer), so callers that need the
|
||||
collection open - e.g. the e2e test harness's webServer readiness check -
|
||||
should poll this instead of /favicon.ico, which responds regardless of
|
||||
collection state.
|
||||
"""
|
||||
if aqt.mw.col is None:
|
||||
return Response(status=HTTPStatus.SERVICE_UNAVAILABLE)
|
||||
return Response(status=HTTPStatus.OK)
|
||||
|
||||
|
||||
def _mime_for_path(path: str) -> str:
|
||||
"Mime type for provided path/filename."
|
||||
|
||||
|
||||
Reference in New Issue
Block a user