@sinonjs/fake-timers

Deterministic fake implementations of setTimeout, setInterval, Date, and other timer APIs for fast, reliable JavaScript tests.

Library
npm
v15.4.0
859stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
55/100Fair
Development Activity40
Maintenance20
Community72
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture78
Code Quality90
Innovation58
Learning Curve65

@sinonjs/fake-timers replaces the timer and date APIs in JavaScript environments with controllable fakes, letting tests advance the clock manually instead of waiting on real wall-clock time. It reimplements setTimeout, setInterval, setImmediate, requestAnimationFrame, requestIdleCallback, process.nextTick, process.hrtime, performance, and Date, all driven by a single virtual clock that only moves when the test tells it to.

Originally extracted from Sinon.JS and now used as its timer-faking engine, the library also ships as a standalone package with framework-agnostic hooks: install() patches the global object, tick() and tickAsync() advance time synchronously or with the event loop, and newer tick modes (nextAsync, interval) support automatic advancement for code that doesn’t expose an obvious point to call tick().

What You Get

  • A createClock() API for a standalone virtual clock, plus install()/withGlobal() to patch timers onto the global object or an arbitrary context
  • Fakes for setTimeout, setInterval, setImmediate, requestAnimationFrame, requestIdleCallback, queueMicrotask, process.nextTick, process.hrtime, performance.now, and Date
  • Synchronous (tick) and async-aware (tickAsync, runAllAsync, nextAsync tick mode) clock advancement for code with pending promises between timers
  • Built-in TypeScript type definitions generated from JSDoc, with no separate @types package needed
  • Configurable toFake/toNotFake lists so only specific timer APIs are hijacked, leaving the rest native

Common Use Cases

  • Testing debounce/throttle utilities without slowing down the test suite with real delays
  • Verifying retry-with-backoff or polling logic across many simulated intervals in milliseconds of real test time
  • Asserting on animation-frame or idle-callback driven UI code in a headless test environment
  • Snapshotting time-dependent output (e.g. Date.now()-derived IDs or timestamps) with a frozen, reproducible clock

Under The Hood

Architecture The library is built as a single withGlobal(_global) factory (src/fake-timers-src.js) that closes over a target global object and returns createClock/install; every fake (Date, performance, Intl, Temporal) is constructed inside that closure so it can reach back into the owning clock. Timer bookkeeping is split across two structures kept in sync by ensureTimerState: a Map from timer id to timer object for O(1) clearTimeout/clearInterval, and a TimerHeap min-heap ordered by callAt for O(log n) scheduling and O(1) lookup of the next timer to fire via peek(). addTimer, firstTimerInRange, and the heap’s bubbleUp/bubbleDown methods are the core primitives everything else (tick, tickAsync, runAll, next) is built on top of; replacing that heap would mean rewriting most of the scheduling logic that depends on its ordering guarantees.

Tech Stack The runtime dependency surface is minimal: only @sinonjs/commons (for a safe reference to the global object) at ^3.0.1. Browser distribution goes through esbuild via @mochify/cli, which also drives cross-browser testing (Chrome via puppeteer, Edge/Firefox/Safari through mochify.webdriver.js). TypeScript consumers get types generated straight from JSDoc using @typescript/native-preview (tsgo) rather than a hand-maintained .d.ts or a parallel TypeScript source tree. Tooling is ESLint (via @sinonjs/eslint-config) plus Prettier, wired into husky/lint-staged pre-commit hooks and a GitHub Actions workflow that separately runs lint, prettier, node tests, and a watch-mode sanity check.

Code Quality The test suite (test/fake-timers-test.js plus per-issue regression files under test/) contains roughly 540 describe/it blocks run via Mocha, with coverage enforced through nyc thresholds (85% branches, 92% lines/functions/statements) and a dedicated test-check-coverage script. Source is annotated throughout with JSDoc @typedef/@callback/@param blocks that double as the type-generation input, and the few catch { // ignored } blocks are narrowly scoped, commented feature-detection fallbacks rather than swallowed errors. Naming is consistent and the heap implementation carries explanatory comments on why two data structures (Map + heap) are maintained together.

What Makes It Unique Most fake-timer libraries stop at setTimeout/setInterval; this one additionally fakes process.hrtime, performance.now, Intl, and (on supporting runtimes) the Temporal API, all synchronized to the same virtual clock. Its scheduler uses an explicit min-heap rather than a sorted array or naive scan, and it offers multiple tick strategies — synchronous tick, promise-aware tickAsync/nextAsync tick mode, and a real-interval-driven shouldAdvanceTime mode — to fit different async code shapes rather than forcing one ticking model on every consumer.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search