test(web): eliminate timeout flakiness in the web test suite#1597
Conversation
|
@claude review |
|
Claude finished @cliffhall's task in 2m 29s —— View job Code Review
I reviewed all 7 changed files against I have one substantive observation and a couple of minor notes. Nothing blocking. 🟡 The "cancels a pending debounce timer" test now passes trivially
await user.type(textInput, "h"); // schedules a 300ms debounce for "text"
await user.click(siblingInput);
await user.click(textInput); // handleFocus clears the pending timer + fires immediately
onCompleteArgument.mockClear();
const textCalls = onCompleteArgument.mock.calls.filter(([n]) => n === "text");
expect(textCalls.length).toBe(0);In the source, the keystroke debounce calls (Note: the old assertion The deterministic way to keep this test meaningful is fake timers — advance past the debounce and assert nothing fired, no wall-clock dependence: vi.useFakeTimers();
const user = userEvent.setup({ delay: null, advanceTimers: vi.advanceTimersByTime });
// … type "h", click away, click back, mockClear() …
await vi.advanceTimersByTimeAsync(400); // debounce window elapses
expect(onCompleteArgument.mock.calls.filter(([n]) => n === "text").length).toBe(0);
vi.useRealTimers();The same reasoning applies mildly to the negative assertions in "clears stale dropdown options" and "does not call onCompleteArgument when completions are unsupported" — but those genuinely test synchronous teardown / never-scheduled paths, so asserting immediately is correct and deterministic there. Only the cancellation test relies on a timer that would need to elapse. Minor notes (non-blocking)
Overall: 👍 The mechanical |
|
@claude review |
|
Claude finished @cliffhall's task in 1m 16s —— View job Code Review
This review covers both commits, including ✅ Round-1 point resolved — the cancellation test is now load-bearing
✅ The remaining
|
|
📋 Smoke test & AGENTS.md audit for this PR: #1596 (comment) (posted on the linked issue #1596). |
…ase change; tree unchanged)
Closes #1596
What
Deterministically fixes the recurring 5s-timeout flakes in the
clients/websuite that surfaced under v8-instrumented, concurrent load. Test-only — no product source changed. No test was skipped/disabled, no global timeout was inflated, and the per-file coverage gate (≥90 on all four dimensions) still holds for every touched file.Per-test root cause + fix
Common root cause (modals/forms/screens):
userEvent.setup()schedules a realsetTimeoutbetween keystrokes. Under CPU contention those event-loop yields balloon, so multi-field interactions accumulated past the 5s per-test timeout — exactly the "clustered at the default 5s timeout under load" symptom. Fix:userEvent.setup({ delay: null })removes the per-keystroke real-timer dependence (keystrokes dispatch synchronously), making the suites load-independent.delay: nullon everyuserEvent.setup(). The debounced validation in the import modals was already awaited viafindBy/waitFor, so it needed no change beyond fast typing.await new Promise(r => setTimeout(r, 400))), which races the debounce timer under load. Replaced every such sleep with awaited conditions (findBy/waitFor) on the real rendered outcome plusdelay: null; they now resolve as soon as the debounce fires and the response settles, and never depend on machine speed. Negative assertions (stale-option clearing, cancelled debounce) rely on the component's synchronous state/timer teardown rather than a timed window, so they're deterministic. A scoped 3swaitFortimeout (commented) covers the legitimate debounce + async settle under heavy load.getStderrLogs()synchronously right aftercallToolresolved raced the stderr chunk. Wrapped the assertion invi.waitForso it polls until the line lands.Verification
All green with zero intermittent failures:
npm run validate(web) — 191 files / 2438 tests.npm run test:coverage(web) — run 6×: 4 sequential + 2 concurrent under load (two full coverage runs in parallel, the issue's suggested load harness). Every run: 229 files / 3237 tests passed, coverage gate clean (0 threshold errors).npm run test:integration(web) standalone — 38 files / 799 tests.🤖 Generated with Claude Code
https://claude.ai/code/session_01S3fTN8H3R8YV4yUGvZjYnX