Easy testing of time-dependent code with time freezing and travel functionality.
npx @tessl/cli install tessl/npm-timekeeper@2.3.00
# Timekeeper
1
2
Timekeeper is a JavaScript time mocking library that provides comprehensive functionality for testing time-dependent code. It allows developers to freeze time, travel to specific dates, and control time flow during test execution, working seamlessly in both Node.js and browser environments.
3
4
## Package Information
5
6
- **Package Name**: timekeeper
7
- **Package Type**: npm
8
- **Language**: JavaScript (with TypeScript definitions)
9
- **Installation**: `npm install --save-dev timekeeper`
10
11
## Core Imports
12
13
```javascript
14
const timekeeper = require('timekeeper');
15
```
16
17
For ES modules:
18
19
```javascript
20
import * as timekeeper from 'timekeeper';
21
```
22
23
In browser environments:
24
25
```html
26
<script src="path/to/timekeeper.js"></script>
27
<!-- Available as global: window.timekeeper -->
28
```
29
30
## Basic Usage
31
32
```javascript
33
const timekeeper = require('timekeeper');
34
35
// Freeze time to a specific moment
36
const frozenTime = new Date('2023-01-01T00:00:00Z');
37
timekeeper.freeze(frozenTime);
38
39
// All Date operations now return the frozen time
40
console.log(new Date()); // 2023-01-01T00:00:00.000Z
41
console.log(Date.now()); // 1672531200000
42
43
// Travel to a different time (time continues flowing)
44
const travelTime = new Date('2030-01-01T00:00:00Z');
45
timekeeper.travel(travelTime);
46
47
// Time flows from the travel point
48
setTimeout(() => {
49
console.log(new Date()); // Approximately 2030-01-01T00:00:00.100Z
50
}, 100);
51
52
// Reset to normal time behavior
53
timekeeper.reset();
54
```
55
56
## Architecture
57
58
Timekeeper works by replacing the native JavaScript `Date` constructor and `Date.now()` method with custom implementations that respect the frozen or travel states. Key components include:
59
60
- **Date Replacement**: Swaps native Date with FakeDate during active mocking
61
- **Time State Management**: Tracks frozen time, travel time, and travel start points
62
- **UMD Compatibility**: Works across CommonJS, AMD, and browser global environments
63
- **Safe Cleanup**: Ensures native Date functionality is properly restored
64
65
## Capabilities
66
67
### Time Freezing
68
69
Freezes time to a specific moment, making all Date operations return the same time.
70
71
```javascript { .api }
72
/**
73
* Set current Date Time and freeze it
74
* @param date - Date object, timestamp number, or date string. Defaults to current time if undefined
75
*/
76
function freeze(date?: Date | number | string): void;
77
```
78
79
**Usage Examples:**
80
81
```javascript
82
const timekeeper = require('timekeeper');
83
84
// Freeze to current time
85
timekeeper.freeze();
86
87
// Freeze to specific date
88
timekeeper.freeze(new Date('2023-06-15T10:30:00Z'));
89
90
// Freeze using timestamp
91
timekeeper.freeze(1687000000000);
92
93
// Freeze using date string
94
timekeeper.freeze('2023-06-15T10:30:00Z');
95
```
96
97
### Time Travel
98
99
Sets the current time to a specific moment and allows time to continue flowing from that point.
100
101
```javascript { .api }
102
/**
103
* Set current DateTime and allow time to continue flowing
104
* @param date - Date object, timestamp number, or date string. Defaults to current time if undefined
105
*/
106
function travel(date?: Date | number | string): void;
107
```
108
109
**Usage Examples:**
110
111
```javascript
112
const timekeeper = require('timekeeper');
113
114
// Travel to future date
115
timekeeper.travel(new Date('2030-01-01T00:00:00Z'));
116
117
// Time continues flowing from travel point
118
setTimeout(() => {
119
console.log(Date.now()); // Will be greater than 1893456000000
120
}, 100);
121
122
// Travel using timestamp
123
timekeeper.travel(1893456000000);
124
125
// Travel using date string
126
timekeeper.travel('2030-01-01T00:00:00Z');
127
```
128
129
**Note**: If time is already frozen when `travel()` is called, the time will be frozen to the new travel date instead of allowing it to flow.
130
131
### Time Reset
132
133
Resets timekeeper behavior and restores native Date functionality.
134
135
```javascript { .api }
136
/**
137
* Reset the timekeeper behavior and restore native Date
138
*/
139
function reset(): void;
140
```
141
142
**Usage Examples:**
143
144
```javascript
145
const timekeeper = require('timekeeper');
146
147
// After using freeze or travel
148
timekeeper.freeze(new Date('2023-01-01'));
149
console.log(new Date()); // 2023-01-01T00:00:00.000Z
150
151
// Reset to normal behavior
152
timekeeper.reset();
153
console.log(new Date()); // Current actual time
154
```
155
156
### Time State Reflection
157
158
Checks whether timekeeper is currently modifying the native Date object.
159
160
```javascript { .api }
161
/**
162
* Reflection method to check if timekeeper is currently active
163
* @returns true if timekeeper is modifying Date, false if using native Date
164
*/
165
function isKeepingTime(): boolean;
166
```
167
168
**Usage Examples:**
169
170
```javascript
171
const timekeeper = require('timekeeper');
172
173
console.log(timekeeper.isKeepingTime()); // false
174
175
timekeeper.freeze(new Date('2023-01-01'));
176
console.log(timekeeper.isKeepingTime()); // true
177
178
timekeeper.reset();
179
console.log(timekeeper.isKeepingTime()); // false
180
```
181
182
### Scoped Time Freezing
183
184
Executes a callback with time frozen to a specific date, then automatically resets afterwards. Supports both synchronous and asynchronous callbacks.
185
186
```javascript { .api }
187
/**
188
* Execute callback with time frozen to specific date, then reset automatically
189
* @param date - Date object, timestamp number, date string, or undefined
190
* @param callback - Function to execute with frozen time
191
* @returns The return value of the callback
192
*/
193
function withFreeze<T>(date: Date | number | string | undefined, callback: () => T): T;
194
```
195
196
**Usage Examples:**
197
198
```javascript
199
const timekeeper = require('timekeeper');
200
201
// Synchronous callback
202
const result = timekeeper.withFreeze(new Date('2023-01-01'), () => {
203
console.log(new Date()); // 2023-01-01T00:00:00.000Z
204
return 'test completed';
205
});
206
console.log(result); // 'test completed'
207
console.log(timekeeper.isKeepingTime()); // false (automatically reset)
208
209
// Asynchronous callback
210
const asyncResult = timekeeper.withFreeze(new Date('2023-01-01'), async () => {
211
console.log(new Date()); // 2023-01-01T00:00:00.000Z
212
await new Promise(resolve => setTimeout(resolve, 100));
213
return 'async test completed';
214
});
215
// timekeeper automatically resets when promise resolves or rejects
216
217
// Error handling - reset happens even if callback throws
218
try {
219
timekeeper.withFreeze(new Date('2023-01-01'), () => {
220
throw new Error('Something went wrong');
221
});
222
} catch (error) {
223
// timekeeper is automatically reset even on error
224
console.log(timekeeper.isKeepingTime()); // false
225
}
226
```
227
228
## Types
229
230
```javascript { .api }
231
// TypeScript interface for the timekeeper object
232
interface Timekeeper {
233
freeze(date?: Date | number | string): void;
234
travel(date?: Date | number | string): void;
235
reset(): void;
236
isKeepingTime(): boolean;
237
withFreeze<T>(date: Date | number | string | undefined, callback: () => T): T;
238
}
239
```
240
241
## Error Handling
242
243
- **Invalid Date Inputs**: Timekeeper passes invalid date inputs to the native Date constructor, which handles parsing and validation
244
- **Exception Safety**: The `withFreeze` method includes proper exception handling to ensure `reset()` is called even if the callback throws an error
245
- **Promise Handling**: For Promise-returning callbacks in `withFreeze`, both success and error cases trigger automatic reset
246
- **State Consistency**: All methods maintain internal state consistency and properly restore native Date functionality
247
248
## Testing Framework Integration
249
250
Timekeeper works with any JavaScript testing framework. Common patterns include:
251
252
```javascript
253
// Mocha example
254
describe('Time-dependent tests', function() {
255
afterEach(function() {
256
timekeeper.reset(); // Clean up after each test
257
});
258
259
it('should handle future dates', function() {
260
timekeeper.travel(new Date('2030-01-01'));
261
// Test time-dependent logic
262
});
263
});
264
265
// Jest example
266
afterEach(() => {
267
timekeeper.reset();
268
});
269
270
test('frozen time behavior', () => {
271
timekeeper.freeze(new Date('2023-01-01'));
272
expect(Date.now()).toBe(1672531200000);
273
});
274
```