JavaScript test spies, stubs and mocks for framework-agnostic unit testing.
—
Fake timers allow you to control time-dependent code by mocking JavaScript's timing functions and Date constructor. They're essential for testing timeouts, intervals, animations, and any code that depends on the passage of time.
Replace native timing functions with controllable fake implementations.
/**
* Install fake timers to control time-dependent code
* @param config - Configuration options for fake timers
* @returns Clock object for controlling time
*/
function useFakeTimers(config?: FakeTimerConfig): SinonClock;
interface FakeTimerConfig {
/** Starting time for the fake clock (default: 0) */
now?: number | Date;
/** Array of global functions to fake */
toFake?: ("setTimeout" | "clearTimeout" | "setInterval" | "clearInterval" |
"Date" | "setImmediate" | "clearImmediate" | "nextTick" |
"requestAnimationFrame" | "cancelAnimationFrame" |
"requestIdleCallback" | "cancelIdleCallback")[];
/** Whether time should advance automatically (default: false) */
shouldAdvanceTime?: boolean;
/** How much time advances per automatic tick in ms (default: 20) */
advanceTimeDelta?: number;
/** Target object to install timers on (default: global) */
target?: object;
}Usage Examples:
import { useFakeTimers } from "sinon";
// Basic fake timers
const clock = useFakeTimers();
// Start from specific time
const clock = useFakeTimers({ now: new Date("2023-01-01") });
// Only fake specific functions
const clock = useFakeTimers({
toFake: ["setTimeout", "Date"]
});
// Automatic time advancement
const clock = useFakeTimers({
shouldAdvanceTime: true,
advanceTimeDelta: 50 // 50ms per tick
});Methods for controlling the fake clock and advancing time.
interface SinonClock {
/**
* Advance the clock by specified milliseconds
* @param milliseconds - Time to advance in milliseconds
*/
tick(milliseconds: number): void;
/**
* Advance to the next scheduled timer
*/
next(): void;
/**
* Run all pending timers (timeouts and intervals)
*/
runAll(): void;
/**
* Run timers until there are no more scheduled
*/
runToLast(): void;
/**
* Advance to the next animation frame
*/
runToFrame(): void;
/**
* Get the current fake time in milliseconds
* @returns Current time
*/
now(): number;
/**
* Get Date representation of current fake time
* @returns Current date
*/
Date(): Date;
/**
* Restore all native timing functions
*/
restore(): void;
}Usage Examples:
const clock = sinon.useFakeTimers();
// Schedule some timers
setTimeout(() => console.log("timeout 1"), 100);
setTimeout(() => console.log("timeout 2"), 200);
setInterval(() => console.log("interval"), 50);
// Advance time manually
clock.tick(50); // Logs: "interval"
clock.tick(50); // Logs: "timeout 1", "interval"
clock.tick(100); // Logs: "timeout 2", "interval", "interval"
// Or run all at once
clock.runAll(); // Executes all pending timers
// Clean up
clock.restore();The fake implementations of native timing functions available on the clock.
interface SinonClock {
/** Fake setTimeout implementation */
setTimeout: typeof setTimeout;
/** Fake clearTimeout implementation */
clearTimeout: typeof clearTimeout;
/** Fake setInterval implementation */
setInterval: typeof setInterval;
/** Fake clearInterval implementation */
clearInterval: typeof clearInterval;
/** Fake setImmediate implementation (Node.js) */
setImmediate: typeof setImmediate;
/** Fake clearImmediate implementation (Node.js) */
clearImmediate: typeof clearImmediate;
/** Fake Date constructor */
Date: DateConstructor;
/** Fake requestAnimationFrame implementation */
requestAnimationFrame: typeof requestAnimationFrame;
/** Fake cancelAnimationFrame implementation */
cancelAnimationFrame: typeof cancelAnimationFrame;
/** Fake performance.now implementation */
performance: { now(): number };
}Common patterns for testing setTimeout-based code.
Usage Examples:
// Function that uses timeout
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Test the debounced function
const clock = sinon.useFakeTimers();
const spy = sinon.spy();
const debouncedSpy = debounce(spy, 100);
// Call multiple times quickly
debouncedSpy("arg1");
debouncedSpy("arg2");
debouncedSpy("arg3");
// No calls yet
console.log(spy.called); // false
// Advance past debounce delay
clock.tick(100);
// Now the function is called once with the last arguments
console.log(spy.calledOnce); // true
console.log(spy.calledWith("arg3")); // true
clock.restore();Testing setInterval-based functionality.
Usage Examples:
// Function that uses interval
function startPolling(callback, interval = 1000) {
return setInterval(callback, interval);
}
// Test polling behavior
const clock = sinon.useFakeTimers();
const callback = sinon.spy();
const intervalId = startPolling(callback, 500);
// Advance time to trigger interval
clock.tick(500);
console.log(callback.calledOnce); // true
clock.tick(500);
console.log(callback.calledTwice); // true
// Stop and cleanup
clearInterval(intervalId);
clock.restore();Testing code that depends on the current date/time.
Usage Examples:
// Function that uses current date
function isBusinessDay() {
const day = new Date().getDay();
return day >= 1 && day <= 5; // Monday-Friday
}
// Test with specific date
const clock = sinon.useFakeTimers(new Date("2023-12-25")); // Monday
console.log(isBusinessDay()); // true (Monday is business day)
// Change to weekend
clock.tick(1000 * 60 * 60 * 24 * 5); // Advance 5 days to Saturday
console.log(isBusinessDay()); // false (Saturday is weekend)
clock.restore();Combining fake timers with Promise-based code.
Usage Examples:
// Function that returns Promise with delay
function delayedPromise(value, delay) {
return new Promise(resolve => {
setTimeout(() => resolve(value), delay);
});
}
// Test Promise timing
async function testDelayedPromise() {
const clock = sinon.useFakeTimers();
const promise = delayedPromise("result", 1000);
// Promise is pending
let resolved = false;
promise.then(value => {
resolved = true;
console.log(value); // "result"
});
console.log(resolved); // false
// Advance time to resolve Promise
clock.tick(1000);
// Allow Promise to resolve
await Promise.resolve();
console.log(resolved); // true
clock.restore();
}Testing requestAnimationFrame-based animations.
Usage Examples:
// Animation function
function animate() {
const start = performance.now();
function frame(timestamp) {
const elapsed = timestamp - start;
if (elapsed < 1000) {
// Continue animation
requestAnimationFrame(frame);
}
// Update animation based on elapsed time
updateAnimation(elapsed);
}
requestAnimationFrame(frame);
}
// Test animation
const clock = sinon.useFakeTimers();
const updateSpy = sinon.spy(window, 'updateAnimation');
animate();
// Advance through several frames
clock.runToFrame(); // First frame
clock.tick(16); // ~60fps
clock.runToFrame(); // Second frame
clock.tick(16);
clock.runToFrame(); // Third frame
console.log(updateSpy.callCount); // 3
// Jump to end of animation
clock.tick(1000);
clock.runToFrame();
clock.restore();
updateSpy.restore();Using fake timers with sandboxes for automatic cleanup.
Usage Examples:
// Automatic fake timer management
const sandbox = sinon.createSandbox({
useFakeTimers: true
});
// Clock is available on sandbox
setTimeout(() => console.log("timeout"), 100);
sandbox.clock.tick(100); // Logs: "timeout"
// Automatic restoration
sandbox.restore(); // Restores timers automaticallyManual sandbox integration:
const sandbox = sinon.createSandbox();
// Install fake timers in sandbox
const clock = sandbox.useFakeTimers({ now: Date.now() });
// Use clock for testing...
clock.tick(1000);
// Restore via sandbox
sandbox.restore(); // Also restores timersComplex timer setups and configurations.
Usage Examples:
// Custom timer configuration
const clock = useFakeTimers({
now: Date.parse("2023-01-01"),
toFake: ["setTimeout", "Date", "performance"],
shouldAdvanceTime: false,
target: window // Specific target object
});
// Multiple timer operations
setTimeout(() => console.log("timeout 1"), 100);
setTimeout(() => console.log("timeout 2"), 50);
const interval = setInterval(() => console.log("interval"), 25);
// Selective advancement
clock.next(); // Runs next timer (50ms timeout 2)
clock.next(); // Runs next timer (25ms interval)
clock.next(); // Runs next timer (75ms interval again)
clock.next(); // Runs next timer (100ms timeout 1)
clearInterval(interval);
clock.restore();interface SinonClock {
// Time control
tick(milliseconds: number): void;
next(): void;
runAll(): void;
runToLast(): void;
runToFrame(): void;
// Current time
now(): number;
Date(): Date;
// Fake timer functions
setTimeout: typeof setTimeout;
clearTimeout: typeof clearTimeout;
setInterval: typeof setInterval;
clearInterval: typeof clearInterval;
setImmediate: typeof setImmediate;
clearImmediate: typeof clearImmediate;
Date: DateConstructor;
requestAnimationFrame: typeof requestAnimationFrame;
cancelAnimationFrame: typeof cancelAnimationFrame;
performance: { now(): number };
// Lifecycle
restore(): void;
}
interface FakeTimerConfig {
now?: number | Date;
toFake?: string[];
shouldAdvanceTime?: boolean;
advanceTimeDelta?: number;
target?: object;
}Install with Tessl CLI
npx tessl i tessl/npm-sinon