Jest · Unit tests that survive refactors

How do you test code that uses timers?

Mediumfake timerstimersasyncUpdated Oct 2026
Quiz this track

Short answer

Call jest.useFakeTimers() to replace timer functions with controllable fakes, advance them with jest.advanceTimersByTime, and switch back to real timers in afterEach.

Real timers make tests slow and flaky: a debounce of one second would freeze the suite, and a background interval can fire after the test finishes. Fake timers replace setTimeout, setInterval, Date and related APIs with a virtual clock that the test controls.

ts
beforeEach(() => {
  jest.useFakeTimers();
});

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

test("shows the saved indicator after the debounce", () => {
  const onSave = jest.fn();
  const save = debounce(onSave, 500);

  save("draft");
  expect(onSave).not.toHaveBeenCalled();

  jest.advanceTimersByTime(500);
  expect(onSave).toHaveBeenCalledWith("draft");
});
The debounce is tested without waiting half a second of real time.

The timer API

  • jest.advanceTimersByTime(ms) moves the virtual clock forward
  • jest.runAllTimers() drains the queue, which can loop on recursive timers
  • jest.runOnlyPendingTimers() runs what is currently queued
  • jest.setSystemTime(date) fixes Date.now for deterministic dates
  • jest.useFakeTimers() can be scoped with jest.useFakeTimers({ doNotFake: [...] })

Modern fake timers also fake Date and performance, which is usually what you want for deterministic snapshots and time-based logic. They also affect queueMicrotask and process.nextTick depending on configuration. If a test only needs a fixed date, jest.setSystemTime is often simpler than faking every timer.

Fake timers and real network or promise timing interact badly. Advance timers inside act for React, and finish pending microtasks before asserting. Always restore real timers so a later test does not inherit a frozen clock.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1What is the difference between runAllTimers and runOnlyPendingTimers?
  2. 2How do you test a debounce without waiting?
  3. 3Why should fake timers be restored in afterEach?
  4. 4How do you freeze the current date in a test?

Say it in the interview

I switch to fake timers before a test that involves setTimeout, setInterval or Date, then advance the virtual clock to trigger the callback. advanceTimersByTime is my default because it is explicit and does not accidentally drain recursive timers. I set the system time when the value of Date matters. In afterEach I always return to real timers, otherwise the next test inherits a frozen clock.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Jest mock interview and get scored feedback on depth, clarity and confidence.