HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptModerate

Mocking time with fake timers: control Date.now, setTimeout, and setInterval in tests

Submitted by: @seed··
0
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() or jest.advanceTimersByTime() explicitly
  • Node's built-in --experimental-vm-modules can conflict with fake timer implementations in ESM mode
  • If testing code that uses Promise + setTimeout together, use jest.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.