Skip to content

Fix the Dashboard CI job's two flakes - #3

Merged
sadeqabuhattem merged 2 commits into
mainfrom
fix/dashboard-ci-flakes
Nov 6, 2026
Merged

sadeqabuhattem merged 2 commits into
mainfrom
fix/dashboard-ci-flakes

Conversation

@sadeqabuhattem

Copy link
Copy Markdown
Member

The Dashboard job has been red on main since the Oct 28 merge, and flaked on #2, which doesn't touch the dashboard. There were two separate causes, one commit each.

Vitest: expected [ 3, 4 ] to deeply equal [ 1, 3 ] (run 40786866495)

useProductList.spec.ts waited for the fake endpoint to record the search request, then read the rows. The endpoint records before it answers, so the page could still hold the previous page 2, [3, 4]. The category test had the same race, and its clear waited on rows that are [1, 2] both before and after. Each step now waits on what the answer changes. Assertions are unchanged.

  • A 100 ms delay in the fake endpoint reproduces CI's failure every time before the fix. After it, all tests pass at 100 ms and 400 ms.

Playwright: nine "renders its title" tests failing on both attempts (run 42091746069)

The dev server compiles each module on first request. A cold runner took longer than the 5 s toHaveText wait. Each failure then replaced the worker, which started a new Nuxt, and Vite re-optimized and started cold again. One slow page became every page failing.

A production build isn't an option, because Vue only warns in development and the suite asserts no [Vue warn]. So test/e2e/fixtures.ts adds a worker-scoped auto fixture. Once Nuxt is up, it visits every page with the API stubbed and waits for its title. No assertion or timeout in smoke.e2e.ts changes.

  • Locally under taskpolicy -b (throttled CPU), cold cache. Before: 9 failed, 3 passed, 8.2 min (CI's exact pattern). After: 12 passed, 2.7 min.
  • At normal priority, from cold: 12/12 pass in 25 s.
  • Removing vue-sonner's stylesheet still fails the toast test.

npm run lint, npm run typecheck, npm test and npm run test:e2e all pass locally.

🤖 Generated with Claude Code

sadeqabuhattem and others added 2 commits November 6, 2026 20:27
… tests

The search test waited until the fake endpoint had recorded `search=desk` and
then read the rows. The endpoint records a request before it answers, so at
that moment the page still held page 2 of everything, [3, 4], until the answer
landed — which is the AssertionError main's CI failed with on Oct 28
(`expected [ 3, 4 ] to deeply equal [ 1, 3 ]`). The category test had the same
race on the same rows, and its clear waited for rows that are [1, 2] on both
sides of it, so that wait proved nothing.

Each step now waits on what the answer changes: the rows, or for the clear,
the page count (two pages of category 1, three of everything). The page-2
setup steps wait on page 2's rows too, so each change starts from a settled
page. What the tests assert is unchanged.

Verified by adding a 100 ms delay to the fake endpoint: before, the search and
category tests fail every time with exactly CI's [3, 4]; after, all five pass
at 100 ms and at 400 ms, and `npm test` passes 15 of 15 three runs running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…passes

The smoke test runs against the dev server, which compiles each module the
first time a browser asks for it. On a GitHub runner a page's first visit took
longer than the five seconds `toHaveText` waits, so its test failed with the
page still on its loading screen. And it never recovered: a failed test makes
Playwright replace its worker, the new worker starts a new Nuxt, and Vite
("Re-optimizing dependencies because vite config has changed") starts cold
again. In run 42091746069 that was all nine page tests failing on both
attempts, while the three tests after them, on a server the toast test had
warmed, passed in about 3 s each.

A production build would remove the compiling, but it would also remove what
half the page tests look for: Vue only warns in development. So the dev server
stays, and `test/e2e/fixtures.ts` extends @nuxt/test-utils' `test` with a
worker-scoped auto fixture that, once the worker's Nuxt is up, opens each page
in a browser of its own with the API stubbed and waits for its title. It
asserts nothing and swallows nothing a test would see: a page that never draws
here is left for its own test to report. The page list moves there, so the
warm-up and the tests visit the same pages. No assertion or timeout in
smoke.e2e.ts changes.

Verified locally with the Vite cache removed, and with the run put on macOS's
background QoS (`taskpolicy -b`) to stand in for a slow runner. Before: 9
failed, 3 passed in 8.2 minutes, CI's exact pattern. After: 12 passed (one
needed its retry at that throttle) in 2.7 minutes. At normal priority 12 of 12
pass from cold in 25 s. Taking vue-sonner's stylesheet out still fails the
toast test with "viewport ratio 0". Lint and the typecheck pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sadeqabuhattem
sadeqabuhattem merged commit a2ae16d into main Nov 6, 2026
4 checks passed
@sadeqabuhattem
sadeqabuhattem deleted the fix/dashboard-ci-flakes branch November 6, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant