Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fake-timers)!: allow jest.useFakeTimers() and projectConfig.fakeTimers to take an options bag #12572

Merged
merged 73 commits into from Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
6b663c8
feat!: allow useFakeTimers to take an options bag
mrazauskas Mar 12, 2022
344fda7
name `timersConfig` consistently
mrazauskas Mar 12, 2022
c42e93d
tweak defaults
mrazauskas Mar 12, 2022
d828b55
tweak error message
mrazauskas Mar 12, 2022
b6d30db
docs
mrazauskas Mar 13, 2022
3e487fc
add note on "strategy"
mrazauskas Mar 13, 2022
fa2c75f
add example lines
mrazauskas Mar 13, 2022
f480a6e
prettier
mrazauskas Mar 13, 2022
44fffd8
rename `timerLimit`
mrazauskas Mar 13, 2022
39b27f9
rename `fakeTimersConfig` and `FakeTimersConfig`
mrazauskas Mar 13, 2022
e4b0dc0
rethinking API
mrazauskas Mar 13, 2022
4ccc5bb
implement `enableGlobally` and `legacyFakeTimers`
mrazauskas Mar 14, 2022
5ccdff4
group e2e tests
mrazauskas Mar 14, 2022
e17d545
more docs
mrazauskas Mar 14, 2022
a671c6a
more cli docs
mrazauskas Mar 14, 2022
bb38197
clean up e2e tests
mrazauskas Mar 15, 2022
e3ec932
rename `fakeTimers`
mrazauskas Mar 15, 2022
1e33ec0
fix resetAllMocks and resetMocks e2e tests
mrazauskas Mar 15, 2022
8df6ae5
legacyFakeTimers test
mrazauskas Mar 15, 2022
78225a5
add timerLimit test
mrazauskas Mar 15, 2022
c61f4da
fix timerLimit
mrazauskas Mar 15, 2022
f9c511f
Merge branch 'main'
mrazauskas Mar 15, 2022
c96a4c9
add deprecation warning
mrazauskas Mar 15, 2022
3726701
implement advanceTimers option
mrazauskas Mar 15, 2022
84a2a0c
allow clearing not faked timers
mrazauskas Mar 15, 2022
5fef5ce
fix type tests
mrazauskas Mar 15, 2022
aa8d7a9
implement doNotFake option
mrazauskas Mar 16, 2022
f4758c5
fix messages
mrazauskas Mar 16, 2022
a1bc0f6
clean up CLI docs
mrazauskas Mar 16, 2022
4171178
even more docs
mrazauskas Mar 16, 2022
a3c7e4c
better errors
mrazauskas Mar 16, 2022
cd01710
add unit test
mrazauskas Mar 17, 2022
2b8ed49
changelog entry
mrazauskas Mar 17, 2022
0eabf14
better changelog entry
mrazauskas Mar 17, 2022
ebed0c1
remove performance from unit test
mrazauskas Mar 17, 2022
8b5d6b0
fix unit test
mrazauskas Mar 17, 2022
ef1434a
better Date.now() (?)
mrazauskas Mar 17, 2022
5ad74f4
expect.any(Number)
mrazauskas Mar 17, 2022
4ec6cce
mock Date.now()
mrazauskas Mar 17, 2022
7fb3de3
clean up
mrazauskas Mar 19, 2022
947ad20
fix config examples
mrazauskas Mar 19, 2022
268febd
clean up
mrazauskas Mar 19, 2022
5ba69dd
Update docs/JestObjectAPI.md
mrazauskas Mar 21, 2022
2b0a6fe
one more backticks
mrazauskas Mar 21, 2022
6c7e24c
clean up
mrazauskas Mar 22, 2022
a2dfb22
bump @types/sinonjs__fake-timers
mrazauskas Mar 23, 2022
1995027
rebase
mrazauskas Mar 24, 2022
01fabf4
docs
mrazauskas Mar 24, 2022
9e3d7bf
tweak types
mrazauskas Mar 24, 2022
73e092b
prettier
mrazauskas Mar 24, 2022
23196dd
fix docs
mrazauskas Mar 24, 2022
4354da8
now must be a number
mrazauskas Mar 24, 2022
8cc5b8c
true conditions first
mrazauskas Mar 24, 2022
c78df2e
more type tests
mrazauskas Mar 24, 2022
2168c49
more docs
mrazauskas Mar 25, 2022
d183309
refactor toSinonFakeTimersConfig
mrazauskas Mar 26, 2022
ca52b59
fix lint errors
mrazauskas Mar 26, 2022
fb61d57
tweak types
mrazauskas Mar 27, 2022
7113374
Merge branch 'main' into useFakeTimers-bag-of-options
mrazauskas Mar 28, 2022
aec5053
better mock
mrazauskas Mar 28, 2022
5c1daec
rework test
mrazauskas Mar 28, 2022
4fb53fd
fix bug
mrazauskas Apr 2, 2022
459b551
tweak docs
mrazauskas Apr 2, 2022
1009ff1
remove CLI option
mrazauskas Apr 3, 2022
72a6565
improve description
mrazauskas Apr 3, 2022
8ff79fa
snap
mrazauskas Apr 3, 2022
6d1c0d1
default configuration
mrazauskas Apr 4, 2022
cb6bede
fix resetMocks test
mrazauskas Apr 4, 2022
1b29f9e
fix resetMocks test again
mrazauskas Apr 4, 2022
20f1d34
fix logic as suggested
mrazauskas Apr 4, 2022
0c8402c
add migration guide
mrazauskas Apr 5, 2022
07ef70c
Revert "add migration guide"
SimenB Apr 5, 2022
e9e5cfa
Merge branch 'main' into useFakeTimers-bag-of-options
SimenB Apr 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@
- `[jest-circus, jest-jasmine2]` Allowed classes and functions as `describe` and `it`/`test` names ([#12484](https://github.com/facebook/jest/pull/12484))
- `[jest-cli, jest-config]` [**BREAKING**] Remove `testURL` config, use `testEnvironmentOptions.url` instead ([#10797](https://github.com/facebook/jest/pull/10797))
- `[jest-cli, jest-core]` Add `--shard` parameter for distributed parallel test execution ([#12546](https://github.com/facebook/jest/pull/12546))
- `[jest-cli]` [**BREAKING**] Remove undocumented `--timers` option ([#12572](https://github.com/facebook/jest/pull/12572))
- `[jest-config]` [**BREAKING**] Stop shipping `jest-environment-jsdom` by default ([#12354](https://github.com/facebook/jest/pull/12354))
- `[jest-config]` [**BREAKING**] Stop shipping `jest-jasmine2` by default ([#12355](https://github.com/facebook/jest/pull/12355))
- `[jest-config, @jest/types]` Add `ci` to `GlobalConfig` ([#12378](https://github.com/facebook/jest/pull/12378))
Expand All @@ -24,6 +25,8 @@
- `[jest-environment-node]` [**BREAKING**] Second argument `context` to constructor is mandatory ([#12469](https://github.com/facebook/jest/pull/12469))
- `[@jest/expect]` New module which extends `expect` with `jest-snapshot` matchers ([#12404](https://github.com/facebook/jest/pull/12404), [#12410](https://github.com/facebook/jest/pull/12410), [#12418](https://github.com/facebook/jest/pull/12418))
- `[@jest/expect-utils]` New module exporting utils for `expect` ([#12323](https://github.com/facebook/jest/pull/12323))
- `[@jest/fake-timers]` [**BREAKING**] Rename `timers` configuration option to `fakeTimers` ([#12572](https://github.com/facebook/jest/pull/12572))
- `[@jest/fake-timers]` [**BREAKING**] Allow `jest.useFakeTimers()` and `projectConfig.fakeTimers` to take an options bag ([#12572](https://github.com/facebook/jest/pull/12572))
- `[jest-haste-map]` [**BREAKING**] `HasteMap.create` now returns a promise ([#12008](https://github.com/facebook/jest/pull/12008))
- `[jest-haste-map]` Add support for `dependencyExtractor` written in ESM ([#12008](https://github.com/facebook/jest/pull/12008))
- `[jest-mock]` [**BREAKING**] Rename exported utility types `ClassLike`, `FunctionLike`, `ConstructorLikeKeys`, `MethodLikeKeys`, `PropertyLikeKeys`; remove exports of utility types `ArgumentsOf`, `ArgsType`, `ConstructorArgumentsOf` - TS builtin utility types `ConstructorParameters` and `Parameters` should be used instead ([#12435](https://github.com/facebook/jest/pull/12435), [#12489](https://github.com/facebook/jest/pull/12489))
Expand Down
110 changes: 102 additions & 8 deletions docs/Configuration.md
Expand Up @@ -395,6 +395,108 @@ Jest's ESM support is still experimental, see [its docs for more details](ECMASc
}
```

### `fakeTimers` \[object]
mrazauskas marked this conversation as resolved.
Show resolved Hide resolved

Default: `{}`

The fake timers may be useful when a piece of code sets a long timeout that we don't want to wait for in a test. For additional details see [Fake Timers guide](TimerMocks.md) and [API documentation](JestObjectAPI.md#fake-timers).

This option provides the default configuration of fake timers for all tests. Calling `jest.useFakeTimers()` in a test file will use these options or will override them if a configuration object is passed. For example, you can tell Jest to keep the original implementation of `process.nextTick()` and adjust the limit of recursive timers that will be run:

```json
{
"fakeTimers": {
"doNotFake": ["nextTick"],
"timerLimit": 1000
}
}
```

```js title="fakeTime.test.js"
// install fake timers for this file using the options from Jest configuration
jest.useFakeTimers();

test('increase the limit of recursive timers for this and following tests', () => {
jest.useFakeTimers({timerLimit: 5000});
// ...
});
```

:::tip

Instead of including `jest.useFakeTimers()` in each test file, you can enable fake timers globally for all tests:

```json
{
"fakeTimers": {
"enableGlobally": true
}
}
```

:::

Configuration options:

```ts
type FakeableAPI =
| 'Date'
| 'hrtime'
| 'nextTick'
| 'performance'
| 'queueMicrotask'
| 'requestAnimationFrame'
| 'cancelAnimationFrame'
| 'requestIdleCallback'
| 'cancelIdleCallback'
| 'setImmediate'
| 'clearImmediate'
| 'setInterval'
| 'clearInterval'
| 'setTimeout'
| 'clearTimeout';

type ModernFakeTimersConfig = {
/**
* If set to `true` all timers will be advanced automatically by 20 milliseconds
* every 20 milliseconds. A custom time delta may be provided by passing a number.
* The default is `false`.
*/
advanceTimers?: boolean | number;
/**
* List of names of APIs that should not be faked. The default is `[]`, meaning
* all APIs are faked.
*/
doNotFake?: Array<FakeableAPI>;
/** Whether fake timers should be enabled for all test files. The default is `false`. */
enableGlobally?: boolean;
/**
* Use the old fake timers implementation instead of one backed by `@sinonjs/fake-timers`.
* The default is `false`.
*/
legacyFakeTimers?: boolean;
/** Sets current system time to be used by fake timers. The default is `Date.now()`. */
now?: number;
/** Maximum number of recursive timers that will be run. The default is `100_000` timers. */
timerLimit?: number;
};
```

:::info Legacy Fake Timers

For some reason you might have to use legacy implementation of fake timers. Here is how to enable it globally (additional options are not supported):

```json
{
"fakeTimers": {
"enableGlobally": true,
"legacyFakeTimers": true
}
}
```

:::

### `forceCoverageMatch` \[array&lt;string&gt;]

Default: `['']`
Expand Down Expand Up @@ -1458,14 +1560,6 @@ Default: `5000`

Default timeout of a test in milliseconds.

### `timers` \[string]

Default: `real`

Setting this value to `fake` or `modern` enables fake timers for all tests by default. Fake timers are useful when a piece of code sets a long timeout that we don't want to wait for in a test. You can learn more about fake timers [here](JestObjectAPI.md#jestusefaketimersimplementation-modern--legacy).

If the value is `legacy`, the old implementation will be used as implementation instead of one backed by [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers).

### `transform` \[object&lt;string, pathToTransformer | \[pathToTransformer, object]&gt;]

Default: `{"\\.[jt]sx?$": "babel-jest"}`
Expand Down
127 changes: 119 additions & 8 deletions docs/JestObjectAPI.md
Expand Up @@ -628,19 +628,118 @@ test('direct', () => {
});
```

## Mock Timers
## Fake Timers

### `jest.useFakeTimers(implementation?: 'modern' | 'legacy')`
### `jest.useFakeTimers(fakeTimersConfig?)`

Instructs Jest to use fake versions of the standard timer functions (`setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `nextTick`, `setImmediate` and `clearImmediate` as well as `Date`).
Instructs Jest to use fake versions of the global date, performance, time and timer APIs. Fake timers implementation is backed by [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers).

If you pass `'legacy'` as an argument, Jest's legacy implementation will be used rather than one based on [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers).
Fake timers will swap out `Date`, `performance.now()`, `queueMicrotask()`, `setImmediate()`, `clearImmediate()`, `setInterval()`, `clearInterval()`, `setTimeout()`, `clearTimeout()` with an implementation that gets its time from the fake clock.

In Node environment `process.hrtime`, `process.nextTick()` and in JSDOM environment `requestAnimationFrame()`, `cancelAnimationFrame()`, `requestIdleCallback()`, `cancelIdleCallback()` will be replaced as well.

Configuration options:

```ts
type FakeableAPI =
| 'Date'
| 'hrtime'
| 'nextTick'
| 'performance'
| 'queueMicrotask'
| 'requestAnimationFrame'
| 'cancelAnimationFrame'
| 'requestIdleCallback'
| 'cancelIdleCallback'
| 'setImmediate'
| 'clearImmediate'
| 'setInterval'
| 'clearInterval'
| 'setTimeout'
| 'clearTimeout';

type FakeTimersConfig = {
/**
* If set to `true` all timers will be advanced automatically by 20 milliseconds
* every 20 milliseconds. A custom time delta may be provided by passing a number.
* The default is `false`.
*/
advanceTimers?: boolean | number;
/**
* List of names of APIs that should not be faked. The default is `[]`, meaning
* all APIs are faked.
*/
doNotFake?: Array<FakeableAPI>;
/**
* Use the old fake timers implementation instead of one backed by `@sinonjs/fake-timers`.
* The default is `false`.
*/
legacyFakeTimers?: boolean;
/** Sets current system time to be used by fake timers. The default is `Date.now()`. */
now?: number | Date;
/**
* The maximum number of recursive timers that will be run when calling `jest.runAllTimers()`.
* The default is `100_000` timers.
*/
timerLimit?: number;
};
```

Calling `jest.useFakeTimers()` will use fake timers for all tests within the file, until original timers are restored with `jest.useRealTimers()`.

You can call `jest.useFakeTimers()` or `jest.useRealTimers()` from anywhere: top level, inside an `test` block, etc. Keep in mind that this is a **global operation** and will affect other tests within the same file. Calling `jest.useFakeTimers()` once again in the same test file would reset the internal state (e.g. timer count) and reinstall fake timers using the provided options:

```js
test('advance the timers automatically', () => {
jest.useFakeTimers({advanceTimers: true});
// ...
});

test('do not advance the timers and do not fake `performance`', () => {
jest.useFakeTimers({doNotFake: ['performance']});
// ...
});

test('uninstall fake timers for the rest of tests in the file', () => {
jest.useRealTimers();
// ...
});
```

:::info Legacy Fake Timers

For some reason you might have to use legacy implementation of fake timers. It can be enabled like this (additional options are not supported):

```js
jest.useFakeTimers({
legacyFakeTimers: true,
});
```

Legacy fake timers will swap out `setImmediate()`, `clearImmediate()`, `setInterval()`, `clearInterval()`, `setTimeout()`, `clearTimeout()` with Jest [mock functions](MockFunctionAPI.md). In Node environment `process.nextTick()` and in JSDOM environment `requestAnimationFrame()`, `cancelAnimationFrame()` will be also replaced.

:::

Returns the `jest` object for chaining.

### `jest.useRealTimers()`

Instructs Jest to use the real versions of the standard timer functions.
Instructs Jest to restore the original implementations of the global date, performance, time and timer APIs. For example, you may call `jest.useRealTimers()` inside `afterEach` hook to restore timers after each test:

```js
afterEach(() => {
jest.useRealTimers();
});

test('do something with fake timers', () => {
jest.useFakeTimers();
// ...
});

test('do something with real timers', () => {
// ...
});
```

Returns the `jest` object for chaining.

Expand All @@ -662,7 +761,11 @@ This is often useful for synchronously executing setTimeouts during a test in or

Exhausts all tasks queued by `setImmediate()`.

> Note: This function is not available when using modern fake timers implementation
:::info

This function is only available when using legacy fake timers implementation.

:::

### `jest.advanceTimersByTime(msToRun)`

Expand Down Expand Up @@ -696,13 +799,21 @@ Returns the number of fake timers still left to run.

Set the current system time used by fake timers. Simulates a user changing the system clock while your program is running. It affects the current time but it does not in itself cause e.g. timers to fire; they will fire exactly as they would have done without the call to `jest.setSystemTime()`.

> Note: This function is only available when using modern fake timers implementation
:::info

This function is not available when using legacy fake timers implementation.

:::

### `jest.getRealSystemTime()`

When mocking time, `Date.now()` will also be mocked. If you for some reason need access to the real current time, you can invoke this function.

> Note: This function is only available when using modern fake timers implementation
:::info

This function is not available when using legacy fake timers implementation.

:::

## Misc

Expand Down