Fake clocks / freeze time in tests across every mainstream runtime: freezegun (Python), Jest fake timers + Sinon @sinonjs/fake-timers (JS/TS), timecop (Ruby), java.time.Clock / InstantSource injection (JVM), .NET TimeProvider / FakeTimeProvider, and libfaketime (LD_PRELOAD for any native binary). Covers the language-agnostic discipline - inject or patch the clock, freeze vs tick vs advance vs set-system-time semantics, teardown so fake clocks never leak between tests - plus the shared anti-pattern table (real sleep under a frozen clock, leaked clock state, timezone-dependent assertions). Per-library setup, API, and CI recipes live in references/{python,js,ruby,jvm,dotnet,libfaketime}.md. Use when tests need deterministic control of now(), timers, or timeouts in any language, or when choosing the right fake-clock tool for a stack.
93
93%
Does it follow best practices?
Impact
—
Average score across 3 eval scenarios
Passed
No findings from the security scan
Both share one engine: per
jestjs.io/docs/timer-mocks, Jest 27+
uses modern fake timers built on
@sinonjs/fake-timers. Use
Jest's wrapper inside Jest; use the Sinon library directly in Mocha,
Vitest, Jasmine, AVA, node:test, or the browser. The API differs only in
naming: jest.advanceTimersByTime vs clock.tick, jest.setSystemTime
vs clock.setSystemTime.
beforeAll(() => {
jest.useFakeTimers();
jest.setSystemTime(new Date('2026-05-20T14:30:00Z'));
});
afterAll(() => jest.useRealTimers());
test('debounce fires after 300ms', () => {
let fired = false;
setTimeout(() => { fired = true; }, 300);
jest.advanceTimersByTime(299);
expect(fired).toBe(false);
jest.advanceTimersByTime(1);
expect(fired).toBe(true);
});Async chains need the Async variant so microtasks drain between ticks:
await jest.advanceTimersByTimeAsync(100);jest.runAllTimers() drains every pending timer (recursion included);
jest.runOnlyPendingTimers() runs the currently-queued set only - use it
for self-rescheduling code to avoid infinite loops.
import FakeTimers from '@sinonjs/fake-timers'; // npm i -D @sinonjs/fake-timers
const clock = FakeTimers.install({ now: new Date('2026-05-20T14:30:00Z').getTime() });
clock.tick(1000); // sync advance
await clock.tickAsync(300); // advance + drain microtasks
clock.setSystemTime(new Date('2027-01-01T00:00:00Z')); // jump, no timers fire
clock.uninstall(); // ALWAYS in afterEachKeep real performance.now() / nextTick while faking timers and Date:
// Jest
jest.useFakeTimers({ doNotFake: ['nextTick', 'queueMicrotask'],
now: new Date('2026-05-20T14:30:00Z').getTime() });
// Sinon
const clock = FakeTimers.install({ toFake: ['setTimeout', 'setInterval', 'Date'] });Both fake UTC time; for local-zone DST behaviour set the runtime zone first, then position the clock at the transition's UTC instant:
process.env.TZ = 'America/New_York';
jest.useFakeTimers();
jest.setSystemTime(new Date('2026-03-08T06:30:00Z')); // 02:30 local - non-existent
expect(new Date().toString()).toMatch(/03:30/); // Node normalisesReset process.env.TZ per test - it is process-global.
A real fetch resolves on the real clock and races faked timers - mock it
and await an async advance:
test('debounce + fetch', async () => {
global.fetch = jest.fn().mockResolvedValue({ json: () => ({ ok: true }) });
myDebouncedFetch();
await jest.advanceTimersByTimeAsync(300);
expect(fetch).toHaveBeenCalled();
});| Anti-pattern | Why it fails | Fix |
|---|---|---|
jest.useFakeTimers('legacy') | Deprecated; doesn't fake Date | Modern is the default since Jest 27 |
Forget useRealTimers / clock.uninstall | Later tests inherit the fake clock | afterEach hook |
Sync tick / advanceTimersByTime for promise chains | Microtasks don't drain | tickAsync / advanceTimersByTimeAsync |
Skip setSystemTime, then read Date | Date.now() returns real time | Always position the clock |
tick(86400 * 365 * 1000) to "advance a year" | Every timer fires one-by-one; crawls | setSystemTime jump |
DST test without process.env.TZ | UTC-only; the local-zone branch never runs | Set TZ explicitly per test |
performance.now, process.hrtime) are only faked
when requested (toFake / defaults vary) - check before asserting.doNotFake is fragile: some helpers internally read Date.now().__mocks__/):
js-unit-tests in the qa-unit-tests-js plugin