Adetayo Akinsanya unkletayo.dev

Fake Timers, Microtasks, and Event Loop Time Manipulation

Manipulating timers, requestAnimationFrame, and system clocks without time drift.

Adetayo Akinsanya (unkletayo) 2026-10-02

Part 7 in Series — Catch up on the previous article: Mocking Mechanics: vi.fn, vi.spyOn, and Module Hoisting Mechanics (Part 6) before diving into this post.

Testing asynchronous time-dependent code (debounce functions, polling loops, timeout retries) using real delays makes test suites slow and flaky.

Vitest integrates @sinonjs/fake-timers to replace native global timing functions (setTimeout, setInterval, clearTimeout, Date, requestAnimationFrame) with a deterministic virtual clock.

import { test, expect, vi, beforeEach, afterEach } from 'vitest';

function debounce(fn: Function, delay: number) {
  let timer: any;
  return (...args: any[]) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

beforeEach(() => {
  vi.useFakeTimers();
});

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

test('debounces function calls over 500ms', () => {
  const func = vi.fn();
  const debounced = debounce(func, 500);

  debounced();
  debounced();
  debounced();

  // Function shouldn't be called immediately
  expect(func).not.toHaveBeenCalled();

  # Advance virtual clock by 500ms
  vi.advanceTimersByTime(500);

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

Advancing Time: advanceTimersByTime vs runAllTimers

  • vi.advanceTimersByTime(ms): Moves the virtual clock forward by exact milliseconds, executing scheduled callbacks within that interval.
  • vi.runAllTimers(): Exhausts all currently queued timers in the event loop queue.
  • vi.setSystemTime(date): Sets the global system Date.now() to a fixed timestamp for testing time-sensitive logic.
test('sets system date deterministically', () => {
  const date = new Date(2026, 8, 8); // Sep 8, 2026
  vi.setSystemTime(date);

  expect(new Date().getFullYear()).toBe(2026);
});
Up Next in Series →

Part 8: Snapshot Testing Engine: AST Serializers, File Formatting, and Inline Snapshots

Continue to Part 8 →