Skip to content

Jest Fake Timers

Code that uses setTimeout() or setInterval() is hard to test quickly — waiting for real timers makes your suite slow. This lesson covers Jest's fake timers, which let you fast-forward time instantly and deterministically.

Enabling Fake Timers

jest.useFakeTimers() replaces the global timer functions (setTimeout, setInterval, Date, etc.) with controllable fake versions. Time doesn't pass automatically anymore — you advance it explicitly using functions like jest.advanceTimersByTime().

This means a test for code that waits 10 seconds can run in milliseconds, since Jest simulates the passage of time instead of actually waiting.

jest.useFakeTimers();

test('calls the callback after 1 second', () => {
  const callback = jest.fn();
  setTimeout(callback, 1000);

  expect(callback).not.toHaveBeenCalled();

  jest.advanceTimersByTime(1000);

  expect(callback).toHaveBeenCalledTimes(1);
});

No real second passes; jest.advanceTimersByTime(1000) simulates it instantly.

Fake Timer API

jest.useFakeTimers();          // enable fake timers
jest.advanceTimersByTime(ms);  // fast-forward by a specific duration
jest.runAllTimers();           // run every pending timer to completion
jest.runOnlyPendingTimers();   // run only currently-queued timers (safer with intervals)
jest.useRealTimers();          // restore real timers
  • jest.advanceTimersByTime(ms) simulates exactly ms milliseconds passing.
  • jest.runAllTimers() runs every timer repeatedly until none remain — risky with setInterval (can loop forever).
  • jest.runOnlyPendingTimers() runs only timers already queued, safer for intervals.
  • Always call jest.useRealTimers() afterward (commonly in afterEach()) to avoid leaking fake timers into other tests.

Fake Timers Cheat Sheet

Every fake timer function you'll commonly use.

Function Effect
jest.useFakeTimers() Enables fake timers for the current test file
jest.advanceTimersByTime(ms) Simulates ms milliseconds passing
jest.advanceTimersByTimeAsync(ms) Same, but awaits any triggered microtasks
jest.runAllTimers() Runs every pending and newly-created timer
jest.runOnlyPendingTimers() Runs only currently-queued timers, once
jest.clearAllTimers() Cancels all pending fake timers
jest.useRealTimers() Restores real setTimeout/setInterval

Testing Debounce and Throttle Functions

Debounce and throttle utilities are classic fake timer use cases: you need to verify a function is delayed, cancelled, or rate-limited correctly, which is nearly impossible to test reliably with real timers due to timing flakiness.

test('debounce delays execution until the wait time passes', () => {
  jest.useFakeTimers();
  const fn = jest.fn();
  const debounced = debounce(fn, 300);

  debounced();
  expect(fn).not.toHaveBeenCalled();

  jest.advanceTimersByTime(299);
  expect(fn).not.toHaveBeenCalled();

  jest.advanceTimersByTime(1);
  expect(fn).toHaveBeenCalledTimes(1);
});

Testing setInterval Safely

setInterval timers repeat indefinitely, so jest.runAllTimers() can loop forever if the interval is never cleared. Use jest.advanceTimersByTime() with a specific duration, or jest.runOnlyPendingTimers(), to safely test interval-based code.

afterEach(() => {
  jest.clearAllTimers();
  jest.useRealTimers();
});

test('polls every 5 seconds, 3 times in 15 seconds', () => {
  jest.useFakeTimers();
  const poll = jest.fn();
  setInterval(poll, 5000);

  jest.advanceTimersByTime(15000);

  expect(poll).toHaveBeenCalledTimes(3);
});

Common Mistakes

  • Calling jest.runAllTimers() on code using setInterval, causing an infinite loop.
  • Forgetting to call jest.useRealTimers() after a test, leaking fake timers into later tests.
  • Not enabling fake timers before the code under test schedules its setTimeout/setInterval call.
  • Mixing real async waits (await new Promise(r => setTimeout(r, 100))) with fake timers in the same test.

Key Takeaways

  • jest.useFakeTimers() replaces real timers with controllable fake ones.
  • jest.advanceTimersByTime() simulates time passing instantly and deterministically.
  • Prefer jest.runOnlyPendingTimers() over jest.runAllTimers() for interval-based code.
  • Always restore real timers with jest.useRealTimers() after tests that enable fake ones.

Pro Tip

Add jest.useFakeTimers() in a beforeEach() and jest.useRealTimers() in an afterEach() for any test file that touches timers — it keeps timer state from leaking between tests without remembering to do it in every single test.