diff --git a/frontend/src/__tests__/mesh/messagesViewFirstContact.test.tsx b/frontend/src/__tests__/mesh/messagesViewFirstContact.test.tsx index b781d97..780a053 100644 --- a/frontend/src/__tests__/mesh/messagesViewFirstContact.test.tsx +++ b/frontend/src/__tests__/mesh/messagesViewFirstContact.test.tsx @@ -842,7 +842,7 @@ describe('MessagesView first-contact trust UX', () => { expect(screen.queryByText(/delivery key has not reached/i)).not.toBeInTheDocument(); }); - it('removes an approved contact immediately from the visible contact list', async () => { + it('removes an approved contact immediately from the visible contact list', { timeout: 30_000 }, async () => { contactsState = { '!sb_remove': { alias: 'Remove Me', @@ -871,24 +871,32 @@ describe('MessagesView first-contact trust UX', () => { // produced flakes on PRs #226, #237, #261, #262, #265, #294, #303, and // the fd7d6fa push. // - // The structural root cause is fixed in .github/workflows/ci.yml via a - // concurrency group (ci.yml runs twice in parallel per PR — direct - // trigger + workflow_call from docker-publish.yml — and both jobs land - // on the same Actions runner pool, starving each other). Serialising - // them via concurrency removes the resource contention. + // Two-part fix: // - // We also bump the timeout here as belt-and-suspenders. The settle - // window is bounded by React's reconciliation, not by any network or - // animation cost, so a generous timeout is the right deflake (the - // failure mode this masks would be "toast never renders", which still - // fails at 15s). + // 1. .github/workflows/ci.yml — concurrency group serialises the two + // parallel ci.yml invocations (direct trigger + workflow_call from + // docker-publish.yml) so they no longer starve each other for + // runner CPU/RAM. That covered the SHA-pair starvation case which + // was visible on PR #303 / #294. + // + // 2. This block — the per-test `timeout: 30_000` on the `it()` above + // and the 10s `waitFor` timeout below. The suite-wide testTimeout + // was 15s (raised in Round 7a deflake work). An earlier draft of + // this fix set waitFor to 15s, but that left ZERO headroom against + // the 15s per-test budget — the test ran out of clock before + // waitFor could even fail. Bumping the per-test timeout to 30s + // gives waitFor a real 10s window after the render/click setup + // finishes. + // + // The failure mode this masks would be "toast never renders", which + // still fails loudly at the 10s waitFor cap. await waitFor( () => { expect( screen.getByText(/Removed contact: Remove Me\./i), ).toBeInTheDocument(); }, - { timeout: 15000, interval: 50 }, + { timeout: 10000, interval: 50 }, ); expect(screen.queryByText('Remove Me')).not.toBeInTheDocument(); });