test(audit-fixes): de-flake TimeoutError test (closes #120)#122
Conversation
…rt rejection (closes #120)
Bench results
Local Node HTTP server, Apple-class GitHub runner. Numbers fluctuate ±2-3% from runner heat alone — only sustained >5% deltas are signal. |
|
Verified: synthetic |
Summary
Fixes the long-standing flake in
test/audit-fixes.test.ts > 'TimeoutError carries the configured timeout' > 'error.timeout reflects the option, not 0'(issue #120, observed across cycles 5/6/7/8).Root cause
The test wired a driver whose
requestreturned a Promise that only rejected oncereq.signalaborted. The signal aborted via the misina-builtAbortSignal.timeout(25). On a saturated runner (full suite, threads pool, ~118 parallel test files) the 25 ms native timer can drift well past the inner test's vitest budget, plus the per-attempt overhead of waiting for the abort listener to fire and propagate. Locally the test took 27-29 ms — only ~3 ms of headroom over the 25 ms timer, so any scheduling jitter on CI under load tipped it past whatever inner deadline Vitest was using and produced the intermittent failure.Fix approach
The contract under test is purely the shape of the resulting
TimeoutError(err.timeout === 25,err.messageincludes"25ms") — not the wall-clock behavior ofAbortSignal.timeout. ThemapTransportErrorpath insrc/misina.tstriggers the configured-timeout branch whenevercause.name === "TimeoutError", so the test now drives that path synchronously by having the driver reject withnew DOMException("...", "TimeoutError"). No real timer fires, no wall-clock dependency, runtime drops from ~28 ms to ~2 ms.Rationale vs alternatives:
vi.useFakeTimers()— would not help here.AbortSignal.timeoutis implemented by the host (Node), not via the timer functions Vitest replaces, so faking timers does not advance it.timeout: 100+ 5 s test budget — works but keeps the wall-clock dependency and inflates test duration without reason.it.retry(2)— masks the symptom, explicitly discouraged by the issue.Verification
pnpm exec vitest run --pool=threads --maxConcurrency=205 consecutive times: 5/5 clean, 932/932 tests passing each run.pnpm test(lint + typecheck + vitest): green.mapTransportErrorbranch and asserts the same observable contract.Closes #120.