patterntypescriptModerate
Mocking time with fake timers: control Date.now, setTimeout, and setInterval in tests
Viewed 0 times
fake timersjest.useFakeTimersjest.advanceTimersByTimemock datesetTimeout testing
Problem
Tests that depend on
Date.now(), setTimeout, setInterval, or new Date() are slow, non-deterministic, or require real wall-clock waiting. A test for a 24-hour cache expiry should not wait 24 hours.Solution
Use Jest's
jest.useFakeTimers() or Sinon's sinon.useFakeTimers() to replace global time functions with controllable stubs. Advance time with jest.advanceTimersByTime(ms) or jest.runAllTimers(). Mock Date to a fixed value with jest.setSystemTime(new Date('2024-01-01')).Why
Fake timers make time-dependent tests instant and deterministic. The entire system clock is frozen or manually advanced, eliminating race conditions between test assertions and async timer callbacks.
Gotchas
- Restore real timers in afterEach with
jest.useRealTimers()— failing to do so leaks fake timers into subsequent tests - Fake timers do not automatically tick; use
jest.runAllTimers()orjest.advanceTimersByTime()explicitly - Node's built-in
--experimental-vm-modulescan conflict with fake timer implementations in ESM mode - If testing code that uses
Promise+setTimeouttogether, usejest.runAllTimersAsync()(Jest 29.1+) to correctly interleave microtasks and timers
Code Snippets
Fake timer cache expiry test
beforeEach(() => {
jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01T00:00:00Z'));
});
afterEach(() => {
jest.useRealTimers();
});
it('expires the cache after 5 minutes', () => {
const cache = new Cache(300_000);
cache.set('key', 'value');
expect(cache.get('key')).toBe('value');
jest.advanceTimersByTime(300_001);
expect(cache.get('key')).toBeUndefined();
});Revisions (0)
No revisions yet.