sinon-fake-timers-js
Wraps Sinon's @sinonjs/fake-timers library for JS/TS testing: install(), tick() / tickAsync(), setSystemTime(), restore(); covers timers (setTimeout / setInterval / requestAnimationFrame), Date / performance.now() / hrtime, and the toFake option for selective override. Use when testing JS/TS code with deterministic timer + clock behaviour. Composes dst-transition-reference + iso-8601-vs-rfc-3339-reference.
sinon-fake-timers-js
Overview
Sinon's @sinonjs/fake-timers is the canonical fake-timer + fake- clock library for JavaScript / TypeScript. Per sinonjs.org/releases/latest/fake-timers, it replaces the global timer functions and the Date constructor with controllable fakes.
This skill is for tests outside Jest (Jest has its own per jest-fake-timers).
When to use
Authoring
Install
npm install --save-dev @sinonjs/fake-timersBasic install
import FakeTimers from '@sinonjs/fake-timers';
const clock = FakeTimers.install({ now: new Date('2026-05-20T14:30:00Z').getTime() });
// Test code that calls Date.now() / new Date() / setTimeout / etc.
expect(new Date().toISOString()).toBe('2026-05-20T14:30:00.000Z');
clock.uninstall();Tick forward
clock.tick(1000); // Advance 1000ms
expect(new Date().toISOString()).toBe('2026-05-20T14:30:01.000Z');Async tick (for promise-based timers)
test('debounce fires after 300ms', async () => {
let fired = false;
setTimeout(() => { fired = true; }, 300);
await clock.tickAsync(299);
expect(fired).toBe(false);
await clock.tickAsync(1);
expect(fired).toBe(true);
});Selectively fake
const clock = FakeTimers.install({
now: new Date('2026-05-20T14:30:00Z').getTime(),
toFake: ['setTimeout', 'setInterval', 'Date'], // not 'performance', 'hrtime'
});Useful when you want real performance.now() for benchmarking but fake Date.
setSystemTime
clock.setSystemTime(new Date('2027-01-01T00:00:00Z'));
expect(new Date().toISOString()).toBe('2027-01-01T00:00:00.000Z');Jumps the clock without ticking any in-flight timers.
DST tests
// Spring-forward simulation requires careful zone setup
// Note: @sinonjs/fake-timers fakes UTC time; for local-zone DST
// behaviour, combine with process.env.TZ
process.env.TZ = 'America/New_York';
const clock = FakeTimers.install({
now: new Date('2026-03-08T06:30:00Z').getTime(), // 02:30 EDT — invalid local
});
// ... test that scheduling at 02:30 local degrades gracefullyPer dst-transition-reference: the test verifies behaviour at the transition; the fake clock makes it reproducible.
Teardown
afterEach(() => clock.uninstall());Critical - leaked clocks contaminate subsequent tests.
Running
npx mocha
npx vitest runCI integration
jobs:
time-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
- run: npm ci && npx vitest runAnti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Forget clock.uninstall() | Leaked fake clock contaminates next tests | afterEach(clock.uninstall) |
| Mix real + fake timers in same test | Race conditions | Either fake everything or fake nothing |
Use tick() for promise-resolving timers | Promises don't resolve synchronously | Use tickAsync |
| Hardcode Unix timestamps | Brittle to system tz | Use new Date(iso-string) |
Test DST without process.env.TZ | UTC-only; DST tests degenerate | Set TZ explicitly |
Fake hrtime / performance always | Loses real-perf measurement when needed | Use toFake option |
Long tick(86400 * 365 * 1000) to "advance 1 year" | Timers fire one-by-one; slow | Use setSystemTime instead |