Calling vi.useFakeTimers() or jest.useFakeTimers() freezes the JavaScript clock at the moment of the call. Any code that depends on setTimeout, setInterval, or Date.now() then hangs indefinitely — the timer callback never fires because the clock never advances. Tests that use useFakeTimers without a corresponding vi.advanceTimersByTime() or vi.runAllTimers() will either timeout or silently pass without actually executing the time-dependent code path. ISO-25010:2011 testability requires that all branches of code under test are actually exercised.
Low because frozen-timer tests typically don't produce false passes — they usually hang or time out — but they do silently skip the time-dependent code branch.
Always pair vi.useFakeTimers() with an explicit clock advancement, and restore real timers after the test. The test cannot verify timer-dependent behavior unless the clock is manually advanced:
it('debounces rapid input', () => {
vi.useFakeTimers()
const callback = vi.fn()
const debounced = debounce(callback, 100)
debounced()
debounced()
debounced()
vi.advanceTimersByTime(100) // fires the debounced callback
expect(callback).toHaveBeenCalledTimes(1)
vi.useRealTimers()
})
ID: ai-slop-test-theater.mock-hygiene.no-fake-timers-without-clock-control
Severity: low
What to look for: Walk all test files. Count all vi.useFakeTimers(/jest.useFakeTimers(/sinon.useFakeTimers( calls. For each, verify the same file (or test block) contains a corresponding clock-advancement call: vi.advanceTimersByTime(/jest.advanceTimersByTime(/clock.tick(/vi.runAllTimers(/jest.runAllTimers(. A useFakeTimers without advancement freezes the clock — any code that waits for a timer never resolves.
Pass criteria: 100% of useFakeTimers calls have a corresponding clock-advancement call in the same test block. Report: "X useFakeTimers calls, Y with clock advancement, 0 frozen."
Fail criteria: At least 1 useFakeTimers call has no clock-advancement.
Skip (N/A) when: No useFakeTimers calls in any test file.
Cross-reference: For broader test framework patterns, the Code Quality Essentials audit (code-quality-essentials) covers test setup conventions.
Detail on fail: "1 frozen fake timer: tests/debounce.test.ts calls vi.useFakeTimers() but never calls vi.advanceTimersByTime() — debounced code under test never fires"
Remediation: vi.useFakeTimers() freezes the clock — any code that uses setTimeout/setInterval/Date.now() will never advance. Pair it with vi.advanceTimersByTime():
it('debounces input', () => {
vi.useFakeTimers()
const callback = vi.fn()
const debounced = debounce(callback, 100)
debounced()
debounced()
debounced()
vi.advanceTimersByTime(100) // advance the clock
expect(callback).toHaveBeenCalledTimes(1)
vi.useRealTimers()
})