Jest Date Mock
jest-date-mock is a lightweight utility library for mocking the global `Date` object within Jest unit tests, simplifying the testing of time-sensitive logic. Currently at version 1.0.10, the library provides a minimalistic API to control the current time, allowing users to advance time by milliseconds (`advanceBy`), set the time to a specific timestamp (`advanceTo`), and clear the mock (`clear`). It also provides `Date.current()` to access the true system time while mocked. Releases are frequent for minor fixes and improvements, with version 1.0.9 adding support for `performance.now()` and version 1.0.8 ensuring `Date.name` remains 'Date' for compatibility with other libraries. Its key differentiator is its focused scope on `Date` and `performance.now()` mocking without interfering with other timers, contrasting with Jest's built-in `useFakeTimers` which handles a broader set of time-related APIs.
Common errors
-
TypeError: Date.now is not a function
cause `jest-date-mock` was not correctly configured in Jest's `setupFiles`, or the setup file itself was not properly loaded.fixVerify that `jest-date-mock` is listed in `jest.setupFiles` in your `package.json` or that the custom setup file requiring it is correctly path-referenced. -
Expected date to be ... but received ... (time difference)
cause The `Date` object was not mocked or was reset unexpectedly, causing tests to use the actual system time. This can also happen if `clear()` was called without a subsequent `advanceTo()` in a later test.fixEnsure `jest-date-mock` is correctly set up globally, and use `advanceTo(new Date(someValue))` at the beginning of each test or in a `beforeEach` hook to ensure a consistent starting date for every test. Explicitly use `clear()` in an `afterEach` only if you re-initialize the mock in `beforeEach`. -
The value of `Date.name` is not 'Date'.
cause Using an older version of `jest-date-mock` (prior to v1.0.8) which incorrectly altered the `Date.name` property, affecting libraries that check this for type validation.fixUpgrade `jest-date-mock` to version `1.0.8` or newer to resolve the `Date.name` inconsistency. -
performance.now() returns real time or is undefined.
cause `performance.now()` mocking was added in version 1.0.9. Older versions do not mock this API. Alternatively, `performance` might not be defined in the test environment.fixUpgrade `jest-date-mock` to version `1.0.9` or higher. If `performance` is still an issue, ensure your test environment (e.g., JSDOM in Jest) supports `window.performance`.
Warnings
- gotcha Forgetting to add `jest-date-mock` to Jest's `setupFiles` configuration will prevent `Date` from being mocked, leading to tests failing due to incorrect time values.
- gotcha `jest-date-mock` specifically mocks `Date` and `performance.now()`. It does not mock other time-related functions like `setTimeout`, `setInterval`, or `requestAnimationFrame`. For these, Jest's built-in `jest.useFakeTimers()` is typically required.
- breaking Prior to version 1.0.8, `jest-date-mock` incorrectly set `Date.name` to an empty string, which could break third-party libraries (e.g., Mongoose) that rely on `Date.name === 'Date'`. This was a silent behavior change.
- gotcha Calling `clear()` permanently shuts down the mock system for the current test scope. If not properly managed (e.g., by calling `advanceTo()` or reloading the mock in subsequent tests or `beforeEach` blocks), subsequent tests may unexpectedly receive real date values or encounter errors.
- gotcha Timezone differences can cause inconsistent date test results across different environments (local machine vs. CI/CD).
Install
-
npm install jest-date-mock -
yarn add jest-date-mock -
pnpm add jest-date-mock
Imports
- advanceTo
const { advanceTo } = require('jest-date-mock');import { advanceTo } from 'jest-date-mock'; - advanceBy
require('jest-date-mock').advanceBy;import { advanceBy } from 'jest-date-mock'; - setupFiles
require('jest-date-mock');import 'jest-date-mock';
Quickstart
import { advanceBy, advanceTo, clear } from 'jest-date-mock';
describe('Date mocking', () => {
// Set the date to a fixed point in time
beforeEach(() => {
advanceTo(new Date(2023, 10, 21, 10, 0, 0)); // November 21, 2023, 10:00:00 AM
});
// Clear the mock after each test to ensure isolation
afterEach(() => {
clear();
});
test('should return the mocked date and allow advancing time', () => {
const initialTimestamp = Date.now();
expect(new Date().getFullYear()).toBe(2023);
expect(new Date().getMonth()).toBe(10); // November is month 10
expect(new Date().getDate()).toBe(21);
expect(Date.current()).not.toBe(initialTimestamp); // Date.current() gets the actual system time
advanceBy(5000); // Advance time by 5 seconds
expect(Date.now() - initialTimestamp).toBe(5000);
advanceBy(60 * 1000); // Advance time by 1 minute
expect(new Date().getMinutes()).toBe(1);
advanceTo(new Date(2024, 0, 1, 0, 0, 0)); // Reset to Jan 1, 2024
expect(new Date().getFullYear()).toBe(2024);
});
test('performance.now() should also be mocked and advance', () => {
const initialPerformanceNow = performance.now();
advanceBy(100);
expect(performance.now() - initialPerformanceNow).toBe(100);
});
});