From d2e225666b1f55cada1f9cb54b69291d249b8d08 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 11 Sep 2026 01:42:17 +0200 Subject: [PATCH] test(playlists): let react-query's notify tick run inside act before the reopen click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The D1 regression test patched the cache and clicked at once; react-query delivers a cache write to its observers on a setTimeout(0), so under the gate's parallel load the click could beat the page's re-render and read the old row (748, not 830). Test-only race — a human reopen comes seconds later. Stable across three full-suite runs; the D1 mutation still turns it red. --- frontend/src/components/Playlists.dom.test.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Playlists.dom.test.tsx b/frontend/src/components/Playlists.dom.test.tsx index db537359..e835fc1a 100644 --- a/frontend/src/components/Playlists.dom.test.tsx +++ b/frontend/src/components/Playlists.dom.test.tsx @@ -124,8 +124,15 @@ describe("Playlists — the row the player is launched with", () => { await waitFor(() => expect(h.player?.video.position_seconds).toBe(748)); act(() => h.player!.onClose()); h.player = null; - // What the player's cleanup does with the position the server confirmed. - act(() => patchCachedProgress(qc, new Map([["V", 830]]))); + // What the player's cleanup does with the position the server confirmed. react-query hands a + // cache write to its observers on a setTimeout(0); outside act, the re-render it triggers is + // scheduled by React on its own and raced the click below under the gate's parallel load (the + // reopen read 748). The write is SYNCHRONOUS, so its notify timer is registered before ours and + // fires first — and inside act, the render it causes is flushed before act returns. + await act(async () => { + patchCachedProgress(qc, new Map([["V", 830]])); + await new Promise((r) => setTimeout(r, 0)); + }); await play("Video V"); await waitFor(() => expect(h.player?.video.position_seconds).toBe(830)); });