Repository navigation
Description
Background
During the Wave-1 smoke/audit sweep, multiple independent runs of clients/web npm run test:coverage intermittently failed — anywhere from 2 to 12 failures per run — in a recurring set of unrelated files:
ServerConfigModal.test.tsxInspectorView.test.tsx(localStorage persistence / History)PromptArgumentsForm.test.tsxServerImportJsonModal.test.tsx/ServerImportConfigModal.test.tsxuseServers.test.tsxResourcesScreen.test.tsxinspectorClientintegration message-matching test
Every failure clustered at the default 5s waitFor/userEvent timeout under v8-instrumented load; re-running unloaded, in isolation, or with --testTimeout=30000 passes clean. These are environmental timing flakes, not logic bugs — but they suppress the coverage table (forcing scoped reruns), erode the CI signal, and violate the project's zero-flake bar.
Two adjacent tooling papercuts observed in the same sweep (fold in if cheap):
- Passing any
--coverage.*CLI override crashes the Storybook addon-vitest plugin (Cannot create property … on boolean 'true'); only the bare--coverageboolean works. npx vitest --coveragepulls in the Storybook project and errors; the project's own scoped bin is required.
Requirement
Zero test-flakiness — the web suite (test, test:coverage, test:integration) must pass deterministically and repeatedly, including under concurrent load and v8 instrumentation. Do not merely raise a global timeout to hide the races.
Scope
- Root-cause each flaky test and make it deterministic: use fake timers with explicit advancement where timers drive the assertion; give
userEventanadvanceTimers/{delay:null}setup where it interacts with fake timers; replace arbitrary sleeps and wall-clock dependence with awaited conditions; scope justified per-test timeouts only where a legitimately slow async settle needs it. - Eliminate any reliance on real-timer debounce windows in the modals/forms listed above.
- Investigate the
inspectorClientintegration message-matching race and stabilize it. - Address the two Storybook/vitest
--coveragetooling papercuts if within reach.
Acceptance
npm run validate(web),npm run test:coverage(web), andnpm run test:integration(web) each pass green on N consecutive full-suite runs (target N ≥ 5), including at least one run under simulated load, with zero intermittent failures.- No test was disabled/skipped to achieve this; fixes are deterministic, not timeout-inflation band-aids.
- Per-file coverage gate still holds (≥90 on all four dimensions) for any files touched.
Refs: tracking #1579.
Activity
cliffhall commentedon Jul 2, 2026
Smoke test & AGENTS.md audit — PR #1597
Independent verification (fresh detached checkout of
origin/v2/1596-test-stability@dd781206, cleannpm installat root). Goal: independently confirm zero test-content flakiness rather than trust the implementer's runs.Test-only confirmation
git diff origin/v2/main...HEAD --name-only— 7 files, all tests, no product source touched (clients/web/src/**non-test andcore/untouched):clients/web/src/components/groups/PromptArgumentsForm/PromptArgumentsForm.test.tsxclients/web/src/components/groups/ServerConfigModal/ServerConfigModal.test.tsxclients/web/src/components/groups/ServerImportConfigModal/ServerImportConfigModal.test.tsxclients/web/src/components/groups/ServerImportJsonModal/ServerImportJsonModal.test.tsxclients/web/src/components/screens/ResourcesScreen/ResourcesScreen.test.tsxclients/web/src/components/views/InspectorView/InspectorView.test.tsxclients/web/src/test/integration/mcp/inspectorClient.test.tsRun-by-run evidence (
clients/web)npm run test:coveragenpm run test:coverage(A)npm run test:coverage(B)npm run test:coveragenpm run test:coveragenpm run validate(web)npm run test:integrationTargeted stress on the previously-flaky files:
PromptArgumentsForm.test.tsx(debounce/completions, most timing-sensitive) — 12/12 runs green (20 tests each).InspectorView.test.tsx— 5/5 green (44 tests each).Test-content failures reproduced across every run above: ZERO. ✅
¹ Concurrent-coverage note (not a flake): running two
test:coverageinvocations in the same working dir simultaneously produced coverage-gate errors on files not touched by this PR (AppRenderer.tsx,ContentViewer.tsx,ResourceLink.tsx) — while all 3237 tests still passed in both. This is a v8 coverage-temp-dir collision (two collectors clobbering the samecoverage/output), a known measurement artifact, not test flakiness. The isolated form of "under load" — a solo coverage run against 8 CPU burners (row 5) — passed the gate clean, so the load dimension is covered without the collision.Mutation check (proves the test is load-bearing) ✅
Temporarily removed the
clearTimeout(existing)inPromptArgumentsForm.tsxhandleFocus, then ran"cancels a pending debounce timer when the input is re-focused":The un-cancelled debounce fired during the fake-timer advance → test failed exactly as intended. Source restored; working tree verified clean (
git status --porcelainempty).AGENTS.md compliance
any, no.skip/.only/.todo/xit/xdescribe, noeslint-disable, no@ts-ignore/@ts-expect-errorin the diff.userEvent.setup({ delay: null })(94 sites), awaited conditions (findBy/waitFor, 10 sites),vi.useFakeTimers()for the debounce-cancel test, andvi.waitForaround the out-of-bandgetStderrLogs()in the integration test. 12 wall-clocksetTimeoutsleeps removed. No globaltestTimeout/hookTimeoutinflation — the only timeout literal is a scopedSETTLE = { timeout: 3000 }passed to individualwaitForcalls.test:coveragepasses solo and under 8-core CPU load with 0 threshold errors (≥90 on all four dimensions holds). Touched files are test files (not themselves gate targets); the components they exercise stayed ≥90.Verdict: PASS ✅
Zero test-content flakes reproduced across 5 independent full-suite green runs (2 concurrent + 1 under 8-core CPU load) plus validate, integration, and 17+ targeted stress iterations. The debounce-cancel test is verified load-bearing. Diff is test-only, deterministic, and AGENTS.md-compliant.
Helper: under-load coverage harness (saved to /tmp, not committed)
cliffhall commentedon Jul 2, 2026
🔗 Implemented by PR #1597. Its code is already integrated into the Wave 1 rollup branch
1579-wave-1(see rollup PR #1601 / verification #1600). #1597 currently targetsv2/mainand will auto-show as Merged once the rollup lands inv2/main. The Development panel doesn't link it now because the closing keyword is on a non-default base branch.test(web): eliminate timeout flakiness in the web test suite (closes m…
fix: address Copilot review round 4
fix: address Copilot review round 4
test: address Copilot review — tighten progress-token guard and de-fl…
fix: state every test-gate timeout instead of inheriting a library de…
Wait for the asserted count, not the first match, in SkillsScreen ver…