fix: state every test-gate timeout instead of inheriting a library default
Three of the six Vitest projects ran on Vitest's own testTimeout: 5000 and five on its hookTimeout/teardownTimeout: 10000, and all 788 Testing Library waits in the web unit project ran on asyncUtilTimeout: 1000. None of those numbers was chosen here, and all of them were sized for an idle machine rather than for three or four concurrent worktree sessions each running a full local:gate on eight cores. #2292, #2278, #2250, #1942 and #1742 were each that class, diagnosed one site at a time. This is the complement of #1596, not a retreat from it: every fix that issue produced stands, and no race is hidden here. What changes is that a correct, deterministic test is no longer cut off by a budget nobody picked. - vitest.shared.mts exports frozen TIMEOUTS / INTEGRATION_TIMEOUTS; all six projects spread one of them, clients/launcher importing the shared module for the first time to do so. - Both web projects configure Testing Library's asyncUtilTimeout. The storybook one needs its own setup file, deliberately outside .storybook/ and free of setProjectAnnotations so the automatic preview-annotation provisioning (#1898) is untouched. - 28 per-suite restatements of the integration project's own budget are gone, so raising the shared value now moves every site under it. The handful that genuinely differ — cross-process lock contention, a full OAuth round trip — keep their budget as a named constant that says why. - AppRenderer's waitFor no longer asks for exactly its enclosing budget, which it could never win (#2292's shape); cli's e2e child timer drops below the project budget so the bound carrying the diagnostic is the one that fires. - The transition auto-settle's slack term is named RAF_SLACK_MS and raised; the term derived from HEADER_ANIM_MS is untouched. The two answer to different things and must not be scaled as one number. - The 19 Playwright budgets scattered across three web smokes become four named constants in scripts/lib/browser-timeouts.mjs. scripts/verify-test-timeouts.mjs resolves each project through Vitest itself and asserts the budgets, the asyncUtilTimeout sites, and that retry stays unset. It was observed red against the pre-change config: unit/tui/launcher at testTimeout 5000, five projects at hookTimeout 10000, both asyncUtilTimeout sites unmet. Closes #2323 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PsmUAZ6aLUAFqenjJKSSRp Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
336e045210
commit
58e53d5a92
1 changed files with 1276 additions and 394 deletions
44
AGENTS.md
44
AGENTS.md
|
|
@ -396,6 +396,50 @@ diagnose a failing gate — is the `testing` skill. These are the rules.
|
|||
- **Render React components through `renderWithMantine`** (`src/test/renderWithMantine.tsx`); do not hand-roll a bare `MantineProvider`, which skips the project theme and the helper's options and drifts from every other test. Pass the `colorScheme` option to exercise a forced scheme rather than hand-rolling `defaultColorScheme`. Use `renderWithMantineTransitions` **only** when a test must assert mid-flight transition state, and read the long comment on the helper before changing anything about it.
|
||||
- **The web coverage `include` is a whitelist.** It names `components`/`hooks`/`theme`/`lib`/`utils`/`server` plus the browser-consumed `core/*` runtime, so a module placed **outside** those directories falls out of the gate entirely, silently. Place new modules inside a gated directory. The documented exceptions — `src/App.tsx` and the `src/main.tsx` / `src/index.ts` bootstraps — are called out in a comment on the `include` array itself.
|
||||
|
||||
### Test-gate timeouts are chosen values, stated once
|
||||
|
||||
**Every wall-clock budget a test gate runs under is a value somebody picked,
|
||||
and it lives in one place (#2323).** The shared budgets are `TIMEOUTS` and
|
||||
`INTEGRATION_TIMEOUTS` in `vitest.shared.mts`; all six Vitest projects spread
|
||||
one of them, and Testing Library's `asyncUtilTimeout` — which no Vitest config
|
||||
can see — is configured in each web project's setup file
|
||||
(`src/test/setup.ts`, `src/test/storybookSetup.ts`).
|
||||
`npm run verify:test-timeouts` resolves each project through Vitest itself and
|
||||
enforces all of it.
|
||||
|
||||
This is not a licence to relax the bar. #1596 settled that: **a test that races
|
||||
is fixed with fake timers or an awaited condition, never with headroom.** The
|
||||
complementary case is what these budgets exist for — a test that is correct and
|
||||
deterministic and is simply cut off, because the number bounding it was a
|
||||
library default sized for an idle machine rather than for the one this repo is
|
||||
worked on (three or four concurrent agent sessions in separate worktrees, each
|
||||
free to run a full `local:gate`). Raising a budget nobody chose hides no race.
|
||||
|
||||
- **Raise a budget in the shared object, not at a suite.** A per-suite
|
||||
`}, 30_000)` moves one site and leaves every future file where it was — which
|
||||
is how five of the six projects came to have no stated budget at all. Delete a
|
||||
restatement of the project's own value rather than keeping it in sync.
|
||||
- **A per-suite raise is right only where the work is genuinely different**, and
|
||||
then it says so: real cross-process lock contention (`file-lock.test.ts`), a
|
||||
full interactive OAuth round trip (`oauth-interactive.test.ts`). Name the
|
||||
constant and state the reason at the site.
|
||||
- **Never nest a budget inside an equal-or-larger one.** `waitFor({ timeout: N })`
|
||||
inside a test whose own budget is `N` can never win, and it reports as a
|
||||
timeout naming neither the wait nor its subject (#2292). Two bounds on the
|
||||
same work must differ, and the one carrying the useful diagnostic must be the
|
||||
tighter (`clients/cli/__tests__/e2e.test.ts`).
|
||||
- **`retry` stays unset.** A retry turns a load-induced red into a silent green
|
||||
on the only pre-push gate this repo has, and hides a real race behind a second
|
||||
attempt. The guard enforces this.
|
||||
- **Do not scale a fixed sleep.** A `setTimeout(r, N)` with no condition is not
|
||||
a timeout: it always waits the full window, so raising it slows every passing
|
||||
run and still races on a loaded one. Replace one with a condition wait when it
|
||||
actually flakes (#2250). The single exception is the transition auto-settle in
|
||||
`clients/web/src/test/renderWithMantine.tsx`, whose failure is silent and
|
||||
displaced rather than loud and local — and there only its `RAF_SLACK_MS` term
|
||||
moves, never the term derived from the component's own animation constant.
|
||||
|
||||
|
||||
## Mandatory pre-push gate
|
||||
|
||||
- **ALWAYS run `npm run format` before committing.** The **root** `format` auto-fixes `core/`, the root `scripts/` tooling, the root shared surface, and every client's scope in one shot. `validate` runs the non-fixing `format:check` and will fail in CI on any unformatted file, so run the auto-fixer first rather than letting `format:check` catch it.
|
||||
|
|
|
|||
Loading…
Reference in a new issue