Repository navigation
Description
Observed on PR #561, which changes no web/ files at all (10 files, all src/Cluckwork.Infrastructure and tests/Cluckwork.Api.IntegrationTests).
What happened
Web typecheck, test, and build failed:
FAIL src/routes/ExpensesPage.test.tsx > ExpensesPage pagination
> appends the next page when 'load more' is clicked (offset advances by a full page)
Error: Test timed out in 5000ms.
❯ src/routes/ExpensesPage.test.tsx:265:3
Test Files 1 failed | 82 passed (83)
Tests 1 failed | 1778 passed (1779)
Re-run of the same commit, with no code change, passed — and finished faster (1m45s vs 2m6s). Non-deterministic by definition.
Why it is fragile
The test builds a 100-row first page:
const page1: Expense[] = Array.from({ length: 100 }, (_, i) => ({ ... }));then does two findByRole("row", { name: /…/ }) lookups against it. A role query with a name regex walks the accessibility tree across every row, and it runs twice (once before the click, once after). That is a lot of work under Vitest's default 5000ms timeout.
The failing run's own totals show how loaded the suite is: tests 188.49s, environment 72.27s, wall clock 105s for 1779 tests. On a busy runner, that query exceeding 5s does not require anything to be wrong.
Why this matters beyond one red run
It is a coverage-gated job, so a flake here blocks unrelated PRs — this one is a tenancy slice that touches no frontend code. The failure mode is also the least informative kind: a timeout, with no assertion to point at, so the first instinct is to go looking for a regression that is not there.
Options
- Give the test an explicit timeout — smallest change, but it treats the symptom and the next slow runner moves the goalposts again.
- Shrink the fixture. The assertion needs
items.length === PAGEto make the component sethasMore; ifPAGEis a constant the test can import, a smaller page size in the test would exercise the same branch with a fraction of the DOM. This is the fix worth pricing first. - Query by something cheaper than a row-name regex — e.g.
findByTexton the sentinel, then assert row membership — so the a11y-tree walk is not on the hot path twice.
Option 2 keeps the guarantee the test exists for (offset advances by a full page, rows append rather than replace) while removing the reason it is slow.
Not fixed in #561
Deliberately. It is a frontend test unrelated to that PR's tenancy work and outside its file allow-list; patching an unrelated flake inside a tenant-isolation change is how scope leaks. Filed here so the re-run does not simply bury it.
Related: Playwright prefill-wipe race territory — async UI assertions that pass locally and fail on a loaded CI runner.
Activity
mforce commentedon Aug 31, 2026
Duplicate of #557, which reports the same test (
ExpensesPage pagination > appends the next page when 'load more' is clicked) timing out at 5000ms under CI load, and was filed first.The root-cause analysis in this body — the 100-row first page making each name-filtered
findByRolewalk a large accessibility tree — has been copied into #557 so it is not lost. Track the fix there.test(web): resolve paged-list rows by cell text, not accessible name (#…