UNPKG

12.5 kBMarkdownView Raw
1# Lolex [![Build Status](https://travis-ci.org/sinonjs/lolex.svg?branch=master)](https://travis-ci.org/sinonjs/lolex)
2
3JavaScript implementation of the timer APIs; `setTimeout`, `clearTimeout`, `setImmediate`, `clearImmediate`, `setInterval`, `clearInterval`, `requestAnimationFrame`, and `cancelAnimationFrame`, along with a clock instance that controls the flow of time. Lolex also provides a `Date` implementation that gets its time from the clock.
4
5In addition in browser environment lolex provides a `performance` implementation that gets its time from the clock. In Node environments lolex provides a `nextTick` implementation that is synchronized with the clock - and a `process.hrtime` shim that works with the clock.
6
7Lolex can be used to simulate passing time in automated tests and other
8situations where you want the scheduling semantics, but don't want to actually
9wait (however, from version 2.0 lolex supports those of you who would like to wait too).
10
11Lolex is extracted from [Sinon.JS](https://github.com/sinonjs/sinon.js).
12
13## Installation
14
15Lolex can be used in both Node and browser environments. Installation is as easy as
16
17```sh
18npm install lolex
19```
20
21If you want to use Lolex in a browser you can use [the pre-built
22version](https://github.com/sinonjs/lolex/blob/master/lolex.js) available in the repo
23and the npm package. Using npm you only need to reference `./node_modules/lolex/lolex.js` in your `<script>` tags.
24
25You are always free to [build it yourself](https://github.com/sinonjs/lolex/blob/53ea4d9b9e5bcff53cc7c9755dc9aa340368cf1c/package.json#L22), of course.
26
27## Usage
28
29To use lolex, create a new clock, schedule events on it using the timer
30functions and pass time using the `tick` method.
31
32```js
33// In the browser distribution, a global `lolex` is already available
34var lolex = require("lolex");
35var clock = lolex.createClock();
36
37clock.setTimeout(function () {
38 console.log("The poblano is a mild chili pepper originating in the state of Puebla, Mexico.");
39}, 15);
40
41// ...
42
43clock.tick(15);
44```
45
46Upon executing the last line, an interesting fact about the
47[Poblano](http://en.wikipedia.org/wiki/Poblano) will be printed synchronously to
48the screen. If you want to simulate asynchronous behavior, you have to use your
49imagination when calling the various functions.
50
51The `next`, `runAll`, `runToFrame`, and `runToLast` methods are available to advance the clock. See the
52API Reference for more details.
53
54### Faking the native timers
55
56When using lolex to test timers, you will most likely want to replace the native
57timers such that calling `setTimeout` actually schedules a callback with your
58clock instance, not the browser's internals.
59
60Calling `install` with no arguments achieves this. You can call `uninstall`
61later to restore things as they were again.
62
63```js
64// In the browser distribution, a global `lolex` is already available
65var lolex = require("lolex");
66
67var clock = lolex.install();
68// Equivalent to
69// var clock = lolex.install(typeof global !== "undefined" ? global : window);
70
71setTimeout(fn, 15); // Schedules with clock.setTimeout
72
73clock.uninstall();
74// setTimeout is restored to the native implementation
75```
76
77To hijack timers in another context pass it to the `install` method.
78
79```js
80var lolex = require("lolex");
81var context = {
82 setTimeout: setTimeout // By default context.setTimeout uses the global setTimeout
83}
84var clock = lolex.install({target: context});
85
86context.setTimeout(fn, 15); // Schedules with clock.setTimeout
87
88clock.uninstall();
89// context.setTimeout is restored to the original implementation
90```
91
92Usually you want to install the timers onto the global object, so call `install`
93without arguments.
94
95#### Automatically incrementing mocked time
96Since version 2.0 Lolex supports the possibility to attach the faked timers
97to any change in the real system time. This basically means you no longer need
98to `tick()` the clock in a situation where you won't know **when** to call `tick()`.
99
100Please note that this is achieved using the original setImmediate() API at a certain
101configurable interval `config.advanceTimeDelta` (default: 20ms). Meaning time would
102be incremented every 20ms, not in real time.
103
104An example would be:
105
106```js
107var lolex = require("lolex");
108var clock = lolex.install({shouldAdvanceTime: true, advanceTimeDelta: 40});
109
110setTimeout(() => {
111 console.log('this just timed out'); //executed after 40ms
112}, 30);
113
114setImmediate(() => {
115 console.log('not so immediate'); //executed after 40ms
116});
117
118setTimeout(() => {
119 console.log('this timed out after'); //executed after 80ms
120 clock.uninstall();
121}, 50);
122```
123
124## API Reference
125
126### `var clock = lolex.createClock([now[, loopLimit]])`
127
128Creates a clock. The default
129[epoch](https://en.wikipedia.org/wiki/Epoch_%28reference_date%29) is `0`.
130
131The `now` argument may be a number (in milliseconds) or a Date object.
132
133The `loopLimit` argument sets the maximum number of timers that will be run when calling `runAll()` before assuming that we have an infinite loop and throwing an error. The default is `1000`.
134
135### `var clock = lolex.install([config])`
136Installs lolex using the specified config (otherwise with epoch `0` on the global scope). The following configuration options are available
137
138Parameter | Type | Default | Description
139--------- | ---- | ------- | ------------
140`config.target`| Object | global | installs lolex onto the specified target context
141`config.now` | Number/Date | 0 | installs lolex with the specified unix epoch
142`config.toFake` | String[] | ["setTimeout", "clearTimeout", "setImmediate", "clearImmediate","setInterval", "clearInterval", "Date", "requestAnimationFrame", "cancelAnimationFrame", "hrtime"] | an array with explicit function names to hijack. *When not set, lolex will automatically fake all methods **except** `nextTick`* e.g., `lolex.install({ toFake: ["setTimeout","nextTick"]})` will fake only `setTimeout` and `nextTick`
143`config.loopLimit` | Number | 1000 | the maximum number of timers that will be run when calling runAll()
144`config.shouldAdvanceTime` | Boolean | false | tells lolex to increment mocked time automatically based on the real system time shift (e.g. the mocked time will be incremented by 20ms for every 20ms change in the real system time)
145`config.advanceTimeDelta` | Number | 20 | relevant only when using with `shouldAdvanceTime: true`. increment mocked time by `advanceTimeDelta` ms every `advanceTimeDelta` ms change in the real system time.
146
147### `var id = clock.setTimeout(callback, timeout)`
148
149Schedules the callback to be fired once `timeout` milliseconds have ticked by.
150
151In Node.js `setTimeout` returns a timer object. Lolex will do the same, however
152its `ref()` and `unref()` methods have no effect.
153
154In browsers a timer ID is returned.
155
156### `clock.clearTimeout(id)`
157
158Clears the timer given the ID or timer object, as long as it was created using
159`setTimeout`.
160
161### `var id = clock.setInterval(callback, timeout)`
162
163Schedules the callback to be fired every time `timeout` milliseconds have ticked
164by.
165
166In Node.js `setInterval` returns a timer object. Lolex will do the same, however
167its `ref()` and `unref()` methods have no effect.
168
169In browsers a timer ID is returned.
170
171### `clock.clearInterval(id)`
172
173Clears the timer given the ID or timer object, as long as it was created using
174`setInterval`.
175
176### `var id = clock.setImmediate(callback)`
177
178Schedules the callback to be fired once `0` milliseconds have ticked by. Note
179that you'll still have to call `clock.tick()` for the callback to fire. If
180called during a tick the callback won't fire until `1` millisecond has ticked
181by.
182
183In Node.js `setImmediate` returns a timer object. Lolex will do the same,
184however its `ref()` and `unref()` methods have no effect.
185
186In browsers a timer ID is returned.
187
188### `clock.clearImmediate(id)`
189
190Clears the timer given the ID or timer object, as long as it was created using
191`setImmediate`.
192
193### `clock.requestAnimationFrame(callback)`
194
195Schedules the callback to be fired on the next animation frame, which runs every
19616 ticks. Returns an `id` which can be used to cancel the callback. This is
197available in both browser & node environments.
198
199### `clock.cancelAnimationFrame(id)`
200
201Cancels the callback scheduled by the provided id.
202
203### `clock.hrtime(prevTime?)`
204Only available in Node.js, mimicks process.hrtime().
205
206### `clock.nextTick(callback)`
207
208Only available in Node.js, mimics `process.nextTick` to enable completely synchronous testing flows.
209
210### `clock.performance.now()`
211Only available in browser environments, mimicks performance.now().
212
213
214### `clock.tick(time)`
215
216Advance the clock, firing callbacks if necessary. `time` may be the number of
217milliseconds to advance the clock by or a human-readable string. Valid string
218formats are `"08"` for eight seconds, `"01:00"` for one minute and `"02:34:10"`
219for two hours, 34 minutes and ten seconds.
220
221`time` may be negative, which causes the clock to change but won't fire any
222callbacks.
223
224### `clock.next()`
225
226Advances the clock to the the moment of the first scheduled timer, firing it.
227
228### `clock.reset()`
229
230Removes all timers and ticks without firing them, and sets `now` to `config.now`
231that was provided to `lolex.install` or to `0` if `config.now` was not provided.
232Useful to reset the state of the clock without having to `uninstall` and `install` it.
233
234### `clock.runAll()`
235
236This runs all pending timers until there are none remaining. If new timers are added while it is executing they will be run as well.
237
238This makes it easier to run asynchronous tests to completion without worrying about the number of timers they use, or the delays in those timers.
239
240It runs a maximum of `loopLimit` times after which it assumes there is an infinite loop of timers and throws an error.
241
242### `clock.runMicrotasks()`
243
244This runs all pending microtasks scheduled with `nextTick` but none of the timers and is mostly useful for libraries using lolex underneath and for running `nextTick` items without any timers.
245
246### `clock.runToFrame()`
247
248Advances the clock to the next frame, firing all scheduled animation frame callbacks,
249if any, for that frame as well as any other timers scheduled along the way.
250
251### `clock.runToLast()`
252
253This takes note of the last scheduled timer when it is run, and advances the
254clock to that time firing callbacks as necessary.
255
256If new timers are added while it is executing they will be run only if they
257would occur before this time.
258
259This is useful when you want to run a test to completion, but the test recursively
260sets timers that would cause `runAll` to trigger an infinite loop warning.
261
262### `clock.setSystemTime([now])`
263
264This simulates a user changing the system clock while your program is running.
265It affects the current time but it does not in itself cause e.g. timers to fire;
266they will fire exactly as they would have done without the call to
267setSystemTime().
268
269### `clock.uninstall()`
270
271Restores the original methods on the `target` that was passed to
272`lolex.install`, or the native timers if no `target` was given.
273
274### `Date`
275
276Implements the `Date` object but using the clock to provide the correct time.
277
278### `Performance`
279
280Implements the `now` method of the [`Performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) object but using the clock to provide the correct time. Only available in environments that support the Performance object (browsers mostly).
281
282### `lolex.withGlobal`
283
284In order to support creating clocks based on separate or sandboxed environments (such as JSDOM), Lolex exports a factory method which takes single argument `global`, which it inspects to figure out what to mock and what features to support. When invoking this function with a global, you will get back an object with `timers`, `createClock` and `install` - same as the regular Lolex exports only based on the passed in global instead of the global environment.
285
286## Running tests
287
288Lolex has a comprehensive test suite. If you're thinking of contributing bug
289fixes or suggesting new features, you need to make sure you have not broken any
290tests. You are also expected to add tests for any new behavior.
291
292### On node:
293
294```sh
295npm test
296```
297
298Or, if you prefer more verbose output:
299
300```
301$(npm bin)/mocha ./test/lolex-test.js
302```
303
304### In the browser
305
306[Mochify](https://github.com/mantoni/mochify.js) is used to run the tests in
307PhantomJS. Make sure you have `phantomjs` installed. Then:
308
309```sh
310npm test-headless
311```
312
313## License
314
315BSD 3-clause "New" or "Revised" License (see LICENSE file)