Vitest fake timers not advancing (test hangs) in CI
After vi.useFakeTimers(), real timers are replaced with controllable ones. Code that awaits a setTimeout will hang forever unless you advance the fake clock. In CI this shows as a test timing out rather than a clear error.
What this error means
A test using fake timers stalls until it hits the test timeout ("Test timed out in 5000ms"), because nothing advanced the clock so a pending timer never fired.
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument.
❯ src/debounce.test.ts:9:3Common causes
Fake timers were enabled but never advanced
A pending setTimeout/setInterval is frozen until you advance the fake clock, so an awaited promise chained to it never settles.
Real timers were not restored between tests
Leaving fake timers on leaks into later tests, which then hang on timers they expected to run for real.
How to fix it
Advance the fake clock
- Call
vi.advanceTimersByTime(ms)orvi.runAllTimers()to fire pending timers. - Restore real timers in an afterEach so state does not leak.
- Re-run so awaited timers resolve promptly.
vi.useFakeTimers()
const p = debounced()
vi.advanceTimersByTime(300)
await p
afterEach(() => vi.useRealTimers())Use runAllTimersAsync for promise-based timers
When timers schedule microtasks, advance them with the async variant so awaited chains complete.
await vi.runAllTimersAsync()How to prevent it
- Always advance fake timers explicitly in the test.
- Restore real timers in afterEach.
- Prefer
runAllTimersAsyncwhen timers resolve promises.