CampaignDetail content-packs tests are flaky: a listPacks call from one test lands in the next #604
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happened
CI run 9404 (PR #602, 2026-09-11 14:25 UTC), job "Frontend tests, audit, and build", failed on two tests in
webapp/frontend/src/pages/CampaignDetail.test.jsx. PR #602 doesn't touch that file.gives the GM a content packs panel for this campaign(line 326):expected "spy" to be called with arguments: [ { scope: 'campaign', campaignId: 'campaign-1' }, … ], Number of calls: 0.does not show the content packs panel to players(line 340):expected "spy" to not be called at all, but actually been called 1 times. The call it received was{ campaignId: "campaign-1", scope: "campaign" }with anAbortSignal, which is exactly the GM test's call.The same tests passed on main's previous CI run (PR #601) and in a full local vitest run of the same branch (863 passed).
Diagnosis
The mirror-image failure means the GM test's asynchronous
listPacksfetch (from an effect, with an abort signal) fired after that test's assertion ran and during the next test. That test then counted it as a player-side call.Two gaps allow it:
expect(...).toHaveBeenCalledWithstraight after afindBy…on something else), rather than awaiting the call itself.It shows up under CI's slower environment: the run's "environment" phase took 92 s.
Fix
await waitFor(() => expect(packsApi.listPacks).toHaveBeenCalledWith(...)).listPacksmock at the start (vi.mocked(packsApi.listPacks).mockClear(), orvi.clearAllMocks()inbeforeEachif the file doesn't already), and make sure the previous test's tree is unmounted (cleanup).AbortSignal, so a test-only mock that ignores the signal will still "call through" late. Assert on the signal, or have the mock honour it.The fix is in test code only.