From 3aff10557c97f5b3d80f1f75e76cd1f822cac5f3 Mon Sep 17 00:00:00 2001 From: Anders Olsson Date: Tue, 9 Jun 2026 11:51:35 +0200 Subject: [PATCH] ci: make the logout pending-state test deterministic (gate, not delay) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same timing-window race as object-new-page: the 50ms delay let the logout resolve (menu unmounts on me=null) before findByText caught 'Signing out…' on the slow CI runner. Hold the logout open with a promise released only after the pending state is asserted. Co-Authored-By: Claude Opus 4.8 (1M context) --- web/src/shell/user-menu.test.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/web/src/shell/user-menu.test.tsx b/web/src/shell/user-menu.test.tsx index 784c478..901301e 100644 --- a/web/src/shell/user-menu.test.tsx +++ b/web/src/shell/user-menu.test.tsx @@ -1,7 +1,7 @@ import { expect, test } from "vitest"; import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { delay, http, HttpResponse } from "msw"; +import { http, HttpResponse } from "msw"; import { server } from "../test/server"; import { renderApp } from "../test/render"; import { UserMenu } from "./user-menu"; @@ -35,9 +35,13 @@ test("opens the menu showing email + role and signs out", async () => { }); test("shows a pending state on Sign out while logging out", async () => { + let release!: () => void; + const gate = new Promise((resolve) => { + release = resolve; + }); server.use( http.post("/api/admin/logout", async () => { - await delay(50); + await gate; return new HttpResponse(null, { status: 204 }); }), ); @@ -50,5 +54,10 @@ test("shows a pending state on Sign out while logging out", async () => { const menu = within(document.body); await userEvent.click(await menu.findByText("Sign out")); + // The logout is held open by `gate`, so the pending state is observed + // deterministically (no reliance on a timing window). expect(await menu.findByText(/signing out/i)).toBeInTheDocument(); + + release(); + await waitFor(() => expect(menu.queryByText(/signing out/i)).toBeNull()); });