[Frontend] Two Dashboard tests flake under CI load (exact call count, 1s findBy) #645

Closed
opened 2026-09-14 03:43:47 +00:00 by claude-bot · 1 comment
Collaborator

Found reading the failed CI run on Renovate PR #639 (sentry-sdk bump, run 1087, job 46051). A Python dependency cannot affect the frontend suite, and the same file passed on the neighbouring runs (#640/#641), so both failures are flakes. The runner was heavily loaded: 401s of test time for 868 tests.

The two failures

1. Dashboard - next-session cache dedup › serves next-session from the client cache on a remount within the TTL (Dashboard.test.jsx:212)
expected "vi.fn()" to be called 4 times, but got 5 times

  • The test asserts campaignsApi.fetchNextSession is called exactly 4 times. That's once per campaign per mount, an implementation detail of how often SessionCountdown's effect runs. Any extra render re-fires the effect.
  • The behaviour the test is named for is the line above it: global.fetch stays at 2, because the client's TTL cache served the remount. That assertion is what matters.
  • Fix: drop the exact fetchNextSession count, or relax it to >= 4, and keep the global.fetch count as the claim.

2. Dashboard - Needs you (#368) › makes the next-session countdown a link to that session (Dashboard.test.jsx:143)
Unable to find role="link" and name /Next session in/, via waitForWrapper, i.e. a findByRole timeout.

  • The countdown renders only after campaigns load and fetchNextSession resolves. The default 1000 ms findBy timeout isn't enough on a loaded shared runner. The failure DOM shows the campaign card rendered, with no countdown yet.
  • Fix: give this findByRole an explicit { timeout: 5000 }. Alternatively, set asyncUtilTimeout for the whole suite in the vitest setup, since the same shape (an assertion waiting on chained async loads) caused #604.

Acceptance

  • Both tests changed as above, with a comment saying why the count or timeout is what it is.
  • Mutation check: disable the client GET cache and confirm the dedup test still fails on the global.fetch count.
  • Afterwards, get #639 a fresh CI run: tick Renovate's rebase checkbox on the PR.

Deferred until #643 lands, because that work touches the Dashboard Join box and possibly this test file.

Found reading the failed CI run on Renovate PR #639 (sentry-sdk bump, run 1087, job 46051). A Python dependency cannot affect the frontend suite, and the same file passed on the neighbouring runs (#640/#641), so both failures are flakes. The runner was heavily loaded: 401s of test time for 868 tests. ## The two failures **1. `Dashboard - next-session cache dedup › serves next-session from the client cache on a remount within the TTL`** (`Dashboard.test.jsx:212`) `expected "vi.fn()" to be called 4 times, but got 5 times` - The test asserts `campaignsApi.fetchNextSession` is called **exactly** 4 times. That's once per campaign per mount, an implementation detail of how often `SessionCountdown`'s effect runs. Any extra render re-fires the effect. - The behaviour the test is named for is the line above it: `global.fetch` stays at **2**, because the client's TTL cache served the remount. That assertion is what matters. - **Fix:** drop the exact `fetchNextSession` count, or relax it to `>= 4`, and keep the `global.fetch` count as the claim. **2. `Dashboard - Needs you (#368) › makes the next-session countdown a link to that session`** (`Dashboard.test.jsx:143`) `Unable to find role="link" and name /Next session in/`, via `waitForWrapper`, i.e. a `findByRole` timeout. - The countdown renders only after campaigns load *and* `fetchNextSession` resolves. The default 1000 ms `findBy` timeout isn't enough on a loaded shared runner. The failure DOM shows the campaign card rendered, with no countdown yet. - **Fix:** give this `findByRole` an explicit `{ timeout: 5000 }`. Alternatively, set `asyncUtilTimeout` for the whole suite in the vitest setup, since the same shape (an assertion waiting on chained async loads) caused #604. ## Acceptance - [ ] Both tests changed as above, with a comment saying why the count or timeout is what it is. - [ ] Mutation check: disable the client GET cache and confirm the dedup test still fails on the `global.fetch` count. - [ ] Afterwards, get #639 a fresh CI run: tick Renovate's rebase checkbox on the PR. Deferred until #643 lands, because that work touches the Dashboard Join box and possibly this test file.
Author
Collaborator

Done in #652 (merged as d0ce347; CI run 1110 passed).

Three fixes to the Dashboard tests:

  1. The countdown-link test's findByRole now waits up to 5 s instead of the default 1 s.
  2. The cache-dedup test now asserts fetchNextSession ran at least 4 times, not exactly 4. The global.fetch count of 2 is still what the test actually checks.
  3. Found while verifying: the dedup test crashed when run on its own. listCampaignTrash, which the Dashboard started calling in #644, was never mocked in that suite's beforeEach, so the test only passed if an earlier test had left that mock set.

Mutation check: with the client GET cache disabled, the dedup test run alone fails on the fetch count (expected 2, got 4).

Renovate #639 didn't need a manual retry: Renovate rebased it and auto-merged it at 06:41 on a green run.

Done in #652 (merged as d0ce347; CI run 1110 passed). Three fixes to the Dashboard tests: 1. The countdown-link test's `findByRole` now waits up to 5 s instead of the default 1 s. 2. The cache-dedup test now asserts `fetchNextSession` ran at least 4 times, not exactly 4. The `global.fetch` count of 2 is still what the test actually checks. 3. **Found while verifying:** the dedup test crashed when run on its own. `listCampaignTrash`, which the Dashboard started calling in #644, was never mocked in that suite's `beforeEach`, so the test only passed if an earlier test had left that mock set. Mutation check: with the client GET cache disabled, the dedup test run alone fails on the fetch count (`expected 2, got 4`). Renovate #639 didn't need a manual retry: Renovate rebased it and auto-merged it at 06:41 on a green run.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#645
No description provided.