diff --git a/CHANGELOG.md b/CHANGELOG.md index af484a94a4f1..ce5503c5fcf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) @@ -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)) diff --git a/docs/Configuration.md b/docs/Configuration.md index 74ab2248e05e..277cf0b8f990 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -395,6 +395,108 @@ Jest's ESM support is still experimental, see [its docs for more details](ECMASc } ``` +### `fakeTimers` \[object] + +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; + /** 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<string>] Default: `['']` @@ -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<string, pathToTransformer | \[pathToTransformer, object]>] Default: `{"\\.[jt]sx?$": "babel-jest"}` diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index aff9a86b5ff6..23df34442ba0 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -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; + /** + * 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. @@ -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)` @@ -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 diff --git a/docs/TimerMocks.md b/docs/TimerMocks.md index 6f811abee6b4..1e0260c7def6 100644 --- a/docs/TimerMocks.md +++ b/docs/TimerMocks.md @@ -3,11 +3,19 @@ id: timer-mocks title: Timer Mocks --- -The native timer functions (i.e., `setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`) are less than ideal for a testing environment since they depend on real time to elapse. Jest can swap out timers with functions that allow you to control the passage of time. [Great Scott!](https://www.youtube.com/watch?v=QZoJ2Pt27BY) +The native timer functions (i.e., `setTimeout()`, `setInterval()`, `clearTimeout()`, `clearInterval()`) are less than ideal for a testing environment since they depend on real time to elapse. Jest can swap out timers with functions that allow you to control the passage of time. [Great Scott!](https://www.youtube.com/watch?v=QZoJ2Pt27BY) -```javascript title="timerGame.js" -'use strict'; +:::info + +Also see [Fake Timers API](JestObjectAPI.md#fake-timers) documentation. + +::: + +## Enable Fake Timers + +In the following example we enable fake timers by calling `jest.useFakeTimers()`. This is replacing the original implementation of `setTimeout()` and other timer functions. Timers can be restored to their normal behavior with `jest.useRealTimers()`. +```javascript title="timerGame.js" function timerGame(callback) { console.log('Ready....go!'); setTimeout(() => { @@ -20,8 +28,6 @@ module.exports = timerGame; ``` ```javascript title="__tests__/timerGame-test.js" -'use strict'; - jest.useFakeTimers(); jest.spyOn(global, 'setTimeout'); @@ -34,27 +40,6 @@ test('waits 1 second before ending the game', () => { }); ``` -Here we enable fake timers by calling `jest.useFakeTimers()`. This mocks out `setTimeout` and other timer functions with mock functions. Timers can be restored to their normal behavior with `jest.useRealTimers()`. - -While you can call `jest.useFakeTimers()` or `jest.useRealTimers()` from anywhere (top level, inside an `it` block, etc.), it is a **global operation** and will affect other tests within the same file. Additionally, you need to call `jest.useFakeTimers()` to reset internal counters before each test. If you plan to not use fake timers in all your tests, you will want to clean up manually, as otherwise the faked timers will leak across tests: - -```javascript -afterEach(() => { - jest.useRealTimers(); -}); - -test('do something with fake timers', () => { - jest.useFakeTimers(); - // ... -}); - -test('do something with real timers', () => { - // ... -}); -``` - -Currently, two implementations of the fake timers are included - `modern` and `legacy`, where `modern` is the default one. See [configuration](Configuration.md#timers-string) for how to configure it. - ## Run All Timers Another test we might want to write for this module is one that asserts that the callback is called after 1 second. To do this, we're going to use Jest's timer control APIs to fast-forward time right in the middle of the test: @@ -81,17 +66,11 @@ test('calls the callback after 1 second', () => { ## Run Pending Timers -There are also scenarios where you might have a recursive timer -- that is a timer that sets a new timer in its own callback. For these, running all the timers would be an endless loop, throwing the following error: +There are also scenarios where you might have a recursive timer – that is a timer that sets a new timer in its own callback. For these, running all the timers would be an endless loop, throwing the following error: "Aborting after running 100000 timers, assuming an infinite loop!" -``` -Ran 100000 timers, and there are still more! Assuming we've hit an infinite recursion and bailing out... -``` - -So something like `jest.runAllTimers()` is not desirable. For these cases you might use `jest.runOnlyPendingTimers()`: +If that is your case, using `jest.runOnlyPendingTimers()` will solve the problem: ```javascript title="infiniteTimerGame.js" -'use strict'; - function infiniteTimerGame(callback) { console.log('Ready....go!'); @@ -110,8 +89,6 @@ module.exports = infiniteTimerGame; ``` ```javascript title="__tests__/infiniteTimerGame-test.js" -'use strict'; - jest.useFakeTimers(); jest.spyOn(global, 'setTimeout'); @@ -142,13 +119,21 @@ describe('infiniteTimerGame', () => { }); ``` +:::note + +For debugging or any other reason you can change the limit of timers that will be run before throwing an error: + +```js +jest.useFakeTimers({timerLimit: 100}); +``` + +::: + ## Advance Timers by Time Another possibility is use `jest.advanceTimersByTime(msToRun)`. When this API is called, all timers are advanced by `msToRun` milliseconds. All pending "macro-tasks" that have been queued via setTimeout() or setInterval(), and would be executed during this time frame, will be executed. Additionally, if those macro-tasks schedule new macro-tasks that would be executed within the same time frame, those will be executed until there are no more macro-tasks remaining in the queue that should be run within msToRun milliseconds. ```javascript title="timerGame.js" -'use strict'; - function timerGame(callback) { console.log('Ready....go!'); setTimeout(() => { @@ -182,4 +167,21 @@ it('calls the callback after 1 second via advanceTimersByTime', () => { Lastly, it may occasionally be useful in some tests to be able to clear all of the pending timers. For this, we have `jest.clearAllTimers()`. -The code for this example is available at [examples/timer](https://github.com/facebook/jest/tree/main/examples/timer). +## Selective Faking + +Sometimes your code may require to avoid overwriting the original implementation of one or another API. If that is the case, you can use `doNotFake` option. For example, here is how you could provide a custom mock function for `performance.mark()` in jsdom environment: + +```js +/** + * @jest-environment jsdom + */ + +const mockPerformanceMark = jest.fn(); +window.performance.mark = mockPerformanceMark; + +test('allows mocking `performance.mark()`', () => { + jest.useFakeTimers({doNotFake: ['performance']}); + + expect(window.performance.mark).toBe(mockPerformanceMark); +}); +``` diff --git a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap index cd1ac20b6546..dd05871f8ae6 100644 --- a/e2e/__tests__/__snapshots__/showConfig.test.ts.snap +++ b/e2e/__tests__/__snapshots__/showConfig.test.ts.snap @@ -16,6 +16,9 @@ exports[`--showConfig outputs config info and exits 1`] = ` "detectOpenHandles": false, "errorOnDeprecated": false, "extensionsToTreatAsEsm": [], + "fakeTimers": { + "enableGlobally": false + }, "forceCoverageMatch": [], "globals": {}, "haste": { @@ -68,7 +71,6 @@ exports[`--showConfig outputs config info and exits 1`] = ` ], "testRegex": [], "testRunner": "<>/jest-circus/runner.js", - "timers": "real", "transform": [ [ "\\\\.[jt]sx?$", diff --git a/e2e/__tests__/fakeTimers.test.ts b/e2e/__tests__/fakeTimers.test.ts index ce1afb178804..4adefe0f056c 100644 --- a/e2e/__tests__/fakeTimers.test.ts +++ b/e2e/__tests__/fakeTimers.test.ts @@ -19,13 +19,24 @@ describe('useFakeTimers', () => { const result = runJest('fake-timers/use-fake-timers'); expect(result.exitCode).toBe(0); }); -}); -describe('requestAnimationFrame', () => { - test('fakes requestAnimationFrame', () => { - const result = runJest('fake-timers/request-animation-frame'); + test('allows to pass advanceTimers option', () => { + const result = runJest('fake-timers/advance-timers'); + expect(result.exitCode).toBe(0); + }); - expect(result.stderr).toMatch('requestAnimationFrame test'); + test('allows to pass doNotFake option', () => { + const result = runJest('fake-timers/do-not-fake'); + expect(result.exitCode).toBe(0); + }); + + test('allows to pass timerLimit option', () => { + const result = runJest('fake-timers/timer-limit'); + expect(result.exitCode).toBe(0); + }); + + test('allows clearing not faked timers', () => { + const result = runJest('fake-timers/clear-real-timers'); expect(result.exitCode).toBe(0); }); }); @@ -39,10 +50,19 @@ describe('setImmediate', () => { }); }); +describe('requestAnimationFrame', () => { + test('fakes requestAnimationFrame', () => { + const result = runJest('fake-timers/request-animation-frame'); + + expect(result.stderr).toMatch('requestAnimationFrame test'); + expect(result.exitCode).toBe(0); + }); +}); + describe('useRealTimers', () => { test('restores timers to the native implementation', () => { const result = runJest('fake-timers/use-real-timers'); - expect(result.stdout).toMatch('API is not mocked with fake timers.'); + expect(result.stdout).toMatch('APIs are not replaced with fake timers.'); expect(result.exitCode).toBe(0); }); }); diff --git a/e2e/__tests__/fakeTimersLegacy.test.ts b/e2e/__tests__/fakeTimersLegacy.test.ts index dbc612382ba3..52571da9d4d0 100644 --- a/e2e/__tests__/fakeTimersLegacy.test.ts +++ b/e2e/__tests__/fakeTimersLegacy.test.ts @@ -8,15 +8,22 @@ import runJest from '../runJest'; describe('enableGlobally', () => { - test('enables fake timers from Jest config', () => { + test('enables legacy fake timers from Jest config', () => { const result = runJest('fake-timers-legacy/enable-globally'); expect(result.exitCode).toBe(0); }); }); +describe('legacyFakeTimers', () => { + test('toggles legacy fake timers from Jest config', () => { + const result = runJest('fake-timers-legacy/enable-legacy-fake-timers'); + expect(result.exitCode).toBe(0); + }); +}); + describe('useFakeTimers', () => { - test('enables fake timers from Jest object', () => { - const result = runJest('fake-timers-legacy/use-fake-timers'); + test('enables legacy fake timers from Jest object', () => { + const result = runJest('fake-timers-legacy/use-legacy-fake-timers'); expect(result.exitCode).toBe(0); }); }); @@ -42,7 +49,7 @@ describe('setImmediate', () => { describe('useRealTimers', () => { test('restores timers to the native implementation', () => { const result = runJest('fake-timers-legacy/use-real-timers'); - expect(result.stdout).toMatch('API is not mocked with fake timers.'); + expect(result.stdout).toMatch('APIs are not mocked with fake timers.'); expect(result.exitCode).toBe(0); }); }); diff --git a/e2e/fake-promises/asap/package.json b/e2e/fake-promises/asap/package.json index 0f50640514e1..b873db8ccbb8 100644 --- a/e2e/fake-promises/asap/package.json +++ b/e2e/fake-promises/asap/package.json @@ -1,9 +1,10 @@ { "jest": { - "timers": "fake", + "fakeTimers": { + "enableGlobally": true + }, "setupFiles": [ "/fake-promises" - ], - "testEnvironment": "node" + ] } } diff --git a/e2e/fake-promises/immediate/package.json b/e2e/fake-promises/immediate/package.json index 0f50640514e1..b873db8ccbb8 100644 --- a/e2e/fake-promises/immediate/package.json +++ b/e2e/fake-promises/immediate/package.json @@ -1,9 +1,10 @@ { "jest": { - "timers": "fake", + "fakeTimers": { + "enableGlobally": true + }, "setupFiles": [ "/fake-promises" - ], - "testEnvironment": "node" + ] } } diff --git a/e2e/fake-timers-legacy/enable-globally/__tests__/enableGlobally.test.js b/e2e/fake-timers-legacy/enable-globally/__tests__/enableGlobally.test.js index c02789c9bd43..674b8cb3810c 100644 --- a/e2e/fake-timers-legacy/enable-globally/__tests__/enableGlobally.test.js +++ b/e2e/fake-timers-legacy/enable-globally/__tests__/enableGlobally.test.js @@ -9,12 +9,6 @@ test('getRealSystemTime', () => { expect(() => jest.getRealSystemTime()).toThrow( - 'getRealSystemTime is not available when not using modern timers', - ); -}); - -test('setSystemTime', () => { - expect(() => jest.setSystemTime(0)).toThrow( - 'setSystemTime is not available when not using modern timers', + '`jest.getRealSystemTime()` is not available when using legacy fake timers.', ); }); diff --git a/e2e/fake-timers-legacy/enable-globally/package.json b/e2e/fake-timers-legacy/enable-globally/package.json index ad49f336e7a7..3cd8baba5623 100644 --- a/e2e/fake-timers-legacy/enable-globally/package.json +++ b/e2e/fake-timers-legacy/enable-globally/package.json @@ -1,6 +1,9 @@ { "name": "enable-globally-legacy", "jest": { - "timers": "legacy" + "fakeTimers": { + "enableGlobally": true, + "legacyFakeTimers": true + } } } diff --git a/e2e/fake-timers-legacy/enable-legacy-fake-timers/__tests__/legacyFakeTimers.test.js b/e2e/fake-timers-legacy/enable-legacy-fake-timers/__tests__/legacyFakeTimers.test.js new file mode 100644 index 000000000000..c781899e02dc --- /dev/null +++ b/e2e/fake-timers-legacy/enable-legacy-fake-timers/__tests__/legacyFakeTimers.test.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +test('fake timers', () => { + jest.useFakeTimers(); + const f = jest.fn(); + setTimeout(f, 0); + jest.runAllTimers(); + expect(f).toHaveBeenCalledTimes(1); +}); + +test('getRealSystemTime', () => { + expect(() => jest.getRealSystemTime()).toThrow( + '`jest.getRealSystemTime()` is not available when using legacy fake timers.', + ); +}); + +test('setSystemTime', () => { + expect(() => jest.setSystemTime(0)).toThrow( + '`jest.setSystemTime()` is not available when using legacy fake timers.', + ); +}); diff --git a/e2e/fake-timers-legacy/enable-legacy-fake-timers/package.json b/e2e/fake-timers-legacy/enable-legacy-fake-timers/package.json new file mode 100644 index 000000000000..9935c2240d23 --- /dev/null +++ b/e2e/fake-timers-legacy/enable-legacy-fake-timers/package.json @@ -0,0 +1,8 @@ +{ + "name": "enable-legacy-fake-timers", + "jest": { + "fakeTimers": { + "legacyFakeTimers": true + } + } +} diff --git a/e2e/fake-timers-legacy/request-animation-frame/__tests__/requestAnimationFrame.test.js b/e2e/fake-timers-legacy/request-animation-frame/__tests__/requestAnimationFrame.test.js index 502ce365a3c6..0dd9668303ea 100644 --- a/e2e/fake-timers-legacy/request-animation-frame/__tests__/requestAnimationFrame.test.js +++ b/e2e/fake-timers-legacy/request-animation-frame/__tests__/requestAnimationFrame.test.js @@ -10,7 +10,10 @@ 'use strict'; test('requestAnimationFrame test', () => { - jest.useFakeTimers('legacy'); + jest.useFakeTimers({ + legacyFakeTimers: true, + }); + let frameTimestamp = -1; requestAnimationFrame(timestamp => { frameTimestamp = timestamp; diff --git a/e2e/fake-timers-legacy/reset-all-mocks/package.json b/e2e/fake-timers-legacy/reset-all-mocks/package.json index 3d15b9a19778..9859a3b1aacb 100644 --- a/e2e/fake-timers-legacy/reset-all-mocks/package.json +++ b/e2e/fake-timers-legacy/reset-all-mocks/package.json @@ -1,7 +1,9 @@ { "name": "reset-all-mocks", "jest": { - "resetMocks": false, - "timers": "legacy" + "fakeTimers": { + "legacyFakeTimers": true + }, + "resetMocks": false } } diff --git a/e2e/fake-timers-legacy/reset-mocks/__tests__/resetMock.test.js b/e2e/fake-timers-legacy/reset-mocks/__tests__/resetMocks.test.js similarity index 94% rename from e2e/fake-timers-legacy/reset-mocks/__tests__/resetMock.test.js rename to e2e/fake-timers-legacy/reset-mocks/__tests__/resetMocks.test.js index 2710469e093e..05d594015029 100644 --- a/e2e/fake-timers-legacy/reset-mocks/__tests__/resetMock.test.js +++ b/e2e/fake-timers-legacy/reset-mocks/__tests__/resetMocks.test.js @@ -8,7 +8,6 @@ 'use strict'; test('works when resetMocks is set in Jest config', () => { - jest.useFakeTimers(); const f = jest.fn(); setTimeout(f, 0); jest.runAllTimers(); diff --git a/e2e/fake-timers-legacy/reset-mocks/package.json b/e2e/fake-timers-legacy/reset-mocks/package.json index 2a41b1e6782d..d999103bf1d1 100644 --- a/e2e/fake-timers-legacy/reset-mocks/package.json +++ b/e2e/fake-timers-legacy/reset-mocks/package.json @@ -1,7 +1,10 @@ { "name": "reset-mocks", "jest": { - "resetMocks": true, - "timers": "legacy" + "fakeTimers": { + "enableGlobally": true, + "legacyFakeTimers": true + }, + "resetMocks": true } } diff --git a/e2e/fake-timers-legacy/set-immediate/package.json b/e2e/fake-timers-legacy/set-immediate/package.json index 88cb67703874..d9c70d1fd4e5 100644 --- a/e2e/fake-timers-legacy/set-immediate/package.json +++ b/e2e/fake-timers-legacy/set-immediate/package.json @@ -1,6 +1,9 @@ { "name": "set-immediate-legacy", "jest": { - "timers": "legacy" + "fakeTimers": { + "enableGlobally": true, + "legacyFakeTimers": true + } } } diff --git a/e2e/fake-timers-legacy/use-fake-timers/__tests__/useFakeTimers.test.js b/e2e/fake-timers-legacy/use-fake-timers/__tests__/useFakeTimers.test.js index 982b23cbf809..843dace7b7af 100644 --- a/e2e/fake-timers-legacy/use-fake-timers/__tests__/useFakeTimers.test.js +++ b/e2e/fake-timers-legacy/use-fake-timers/__tests__/useFakeTimers.test.js @@ -8,9 +8,11 @@ 'use strict'; test('fake timers', () => { - jest.useFakeTimers('legacy'); + jest.useFakeTimers({ + legacyFakeTimers: true, + }); expect(() => jest.setSystemTime(0)).toThrow( - 'setSystemTime is not available when not using modern timers', + '`jest.setSystemTime()` is not available when using legacy fake timers.', ); }); diff --git a/e2e/fake-timers-legacy/use-legacy-fake-timers/__tests__/useFakeTimers.test.js b/e2e/fake-timers-legacy/use-legacy-fake-timers/__tests__/useFakeTimers.test.js new file mode 100644 index 000000000000..843dace7b7af --- /dev/null +++ b/e2e/fake-timers-legacy/use-legacy-fake-timers/__tests__/useFakeTimers.test.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +test('fake timers', () => { + jest.useFakeTimers({ + legacyFakeTimers: true, + }); + + expect(() => jest.setSystemTime(0)).toThrow( + '`jest.setSystemTime()` is not available when using legacy fake timers.', + ); +}); diff --git a/e2e/fake-timers-legacy/use-legacy-fake-timers/package.json b/e2e/fake-timers-legacy/use-legacy-fake-timers/package.json new file mode 100644 index 000000000000..2223ef489425 --- /dev/null +++ b/e2e/fake-timers-legacy/use-legacy-fake-timers/package.json @@ -0,0 +1,3 @@ +{ + "name": "use-legacy-fake-timers" +} diff --git a/e2e/fake-timers-legacy/use-real-timers/package.json b/e2e/fake-timers-legacy/use-real-timers/package.json index e0052f4b506f..9f83a4f4086f 100644 --- a/e2e/fake-timers-legacy/use-real-timers/package.json +++ b/e2e/fake-timers-legacy/use-real-timers/package.json @@ -1,6 +1,9 @@ { "name": "use-real-timers-legacy", "jest": { - "timers": "legacy" + "fakeTimers": { + "enableGlobally": true, + "legacyFakeTimers": true + } } } diff --git a/e2e/fake-timers/advance-timers/__tests__/advanceTimers.test.js b/e2e/fake-timers/advance-timers/__tests__/advanceTimers.test.js new file mode 100644 index 000000000000..c62b7cda7260 --- /dev/null +++ b/e2e/fake-timers/advance-timers/__tests__/advanceTimers.test.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +test('advances timers if true is passed', done => { + jest.useFakeTimers({advanceTimers: true}); + + const start = Date.now(); + + setTimeout(() => { + done(); + expect(Date.now() - start).toEqual(45); + }, 45); +}); + +test('advances timers if a number is passed', done => { + jest.useFakeTimers({advanceTimers: 40}); + + const start = Date.now(); + + setTimeout(() => { + done(); + expect(Date.now() - start).toEqual(35); + }, 35); +}); + +test('works with `now` option', done => { + jest.useFakeTimers({advanceTimers: 30, now: new Date('2015-09-25')}); + + expect(Date.now()).toEqual(1443139200000); + + const start = Date.now(); + + setTimeout(() => { + done(); + expect(Date.now() - start).toEqual(25); + }, 25); +}); diff --git a/e2e/fake-timers/advance-timers/package.json b/e2e/fake-timers/advance-timers/package.json new file mode 100644 index 000000000000..19979034fc88 --- /dev/null +++ b/e2e/fake-timers/advance-timers/package.json @@ -0,0 +1,3 @@ +{ + "name": "advance-timers" +} diff --git a/e2e/fake-timers/clear-real-timers/__tests__/clearRealTimers.test.js b/e2e/fake-timers/clear-real-timers/__tests__/clearRealTimers.test.js new file mode 100644 index 000000000000..0e5ebdc640a0 --- /dev/null +++ b/e2e/fake-timers/clear-real-timers/__tests__/clearRealTimers.test.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +test('allows clearing not faked timers', () => { + const timer = setTimeout(() => { + throw new Error('Should not throw'); + }, 1000); + + jest.useFakeTimers(); + + clearTimeout(timer); +}); diff --git a/e2e/fake-timers/clear-real-timers/package.json b/e2e/fake-timers/clear-real-timers/package.json new file mode 100644 index 000000000000..7c7d151e8229 --- /dev/null +++ b/e2e/fake-timers/clear-real-timers/package.json @@ -0,0 +1,3 @@ +{ + "name": "clear-real-timers" +} diff --git a/e2e/fake-timers/do-not-fake/__tests__/doNotFake.test.js b/e2e/fake-timers/do-not-fake/__tests__/doNotFake.test.js new file mode 100644 index 000000000000..8d4f5f149a78 --- /dev/null +++ b/e2e/fake-timers/do-not-fake/__tests__/doNotFake.test.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* global window */ + +'use strict'; + +const mockPerformanceMark = jest.fn(); +window.performance.mark = mockPerformanceMark; + +test('fakes all APIs', () => { + jest.useFakeTimers(); + + expect(window.performance.mark).toBeUndefined(); +}); + +test('does not fake `performance` instance', () => { + jest.useFakeTimers({doNotFake: ['performance']}); + + expect(window.performance.mark).toBe(mockPerformanceMark); +}); diff --git a/e2e/fake-timers/do-not-fake/package.json b/e2e/fake-timers/do-not-fake/package.json new file mode 100644 index 000000000000..eed48bf98af2 --- /dev/null +++ b/e2e/fake-timers/do-not-fake/package.json @@ -0,0 +1,6 @@ +{ + "name": "do-not-fake", + "jest": { + "testEnvironment": "jsdom" + } +} diff --git a/e2e/fake-timers/enable-globally/__tests__/enableGlobally.test.js b/e2e/fake-timers/enable-globally/__tests__/enableGlobally.test.js index 1d488f487a17..d5dbdc8878bd 100644 --- a/e2e/fake-timers/enable-globally/__tests__/enableGlobally.test.js +++ b/e2e/fake-timers/enable-globally/__tests__/enableGlobally.test.js @@ -29,6 +29,6 @@ test('fake timers with Date argument', () => { test('runAllImmediates', () => { expect(() => jest.runAllImmediates()).toThrow( - 'runAllImmediates is not available when using modern timers', + '`jest.runAllImmediates()` is only available when using legacy fake timers.', ); }); diff --git a/e2e/fake-timers/enable-globally/package.json b/e2e/fake-timers/enable-globally/package.json index 6bc480418b0d..8d75224d03c3 100644 --- a/e2e/fake-timers/enable-globally/package.json +++ b/e2e/fake-timers/enable-globally/package.json @@ -1,6 +1,8 @@ { "name": "enable-globally", "jest": { - "timers": "modern" + "fakeTimers": { + "enableGlobally": true + } } } diff --git a/e2e/fake-timers/request-animation-frame/__tests__/requestAnimationFrame.test.js b/e2e/fake-timers/request-animation-frame/__tests__/requestAnimationFrame.test.js index 6f4316230a0b..5548e95b0005 100644 --- a/e2e/fake-timers/request-animation-frame/__tests__/requestAnimationFrame.test.js +++ b/e2e/fake-timers/request-animation-frame/__tests__/requestAnimationFrame.test.js @@ -10,7 +10,8 @@ 'use strict'; test('requestAnimationFrame test', () => { - jest.useFakeTimers('modern'); + jest.useFakeTimers(); + let frameTimestamp = -1; requestAnimationFrame(timestamp => { frameTimestamp = timestamp; diff --git a/e2e/fake-timers/set-immediate/package.json b/e2e/fake-timers/set-immediate/package.json index b0c2eeea2314..2826715e9705 100644 --- a/e2e/fake-timers/set-immediate/package.json +++ b/e2e/fake-timers/set-immediate/package.json @@ -1,6 +1,8 @@ { "name": "set-immediate", "jest": { - "timers": "fake" + "fakeTimers": { + "enableGlobally": true + } } } diff --git a/e2e/fake-timers/timer-limit/__tests__/timerLimit.test.js b/e2e/fake-timers/timer-limit/__tests__/timerLimit.test.js new file mode 100644 index 000000000000..7f326e93f54c --- /dev/null +++ b/e2e/fake-timers/timer-limit/__tests__/timerLimit.test.js @@ -0,0 +1,50 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +test('reads timerLimit from Jest config', () => { + jest.useFakeTimers(); + + setTimeout(function infinitelyRecursingCallback() { + setTimeout(infinitelyRecursingCallback, 0); + }, 0); + + expect(() => { + jest.runAllTimers(); + }).toThrow( + new Error('Aborting after running 10 timers, assuming an infinite loop!'), + ); +}); + +test('allows to override timerLimit set via Jest config', () => { + jest.useFakeTimers({timerLimit: 100}); + + setTimeout(function infinitelyRecursingCallback() { + setTimeout(infinitelyRecursingCallback, 0); + }, 0); + + expect(() => { + jest.runAllTimers(); + }).toThrow( + new Error('Aborting after running 100 timers, assuming an infinite loop!'), + ); +}); + +test('allows to override timerLimit set via Jest object', () => { + jest.useFakeTimers({timerLimit: 1000}); + + setTimeout(function infinitelyRecursingCallback() { + setTimeout(infinitelyRecursingCallback, 0); + }, 0); + + expect(() => { + jest.runAllTimers(); + }).toThrow( + new Error('Aborting after running 1000 timers, assuming an infinite loop!'), + ); +}); diff --git a/e2e/fake-timers/timer-limit/package.json b/e2e/fake-timers/timer-limit/package.json new file mode 100644 index 000000000000..81b4c8e4fb99 --- /dev/null +++ b/e2e/fake-timers/timer-limit/package.json @@ -0,0 +1,9 @@ +{ + "name": "timer-limit", + "jest": { + "fakeTimers": { + "enableGlobally": true, + "timerLimit": 10 + } + } +} diff --git a/e2e/fake-timers/use-fake-timers/__tests__/useFakeTimers.test.js b/e2e/fake-timers/use-fake-timers/__tests__/useFakeTimers.test.js index 6fd28535c2bd..fd294d2323e3 100644 --- a/e2e/fake-timers/use-fake-timers/__tests__/useFakeTimers.test.js +++ b/e2e/fake-timers/use-fake-timers/__tests__/useFakeTimers.test.js @@ -8,7 +8,7 @@ 'use strict'; test('fake timers with number argument', () => { - jest.useFakeTimers('modern'); + jest.useFakeTimers(); jest.setSystemTime(0); @@ -20,7 +20,7 @@ test('fake timers with number argument', () => { }); test('fake timers with Date argument', () => { - jest.useFakeTimers('modern'); + jest.useFakeTimers(); jest.setSystemTime(new Date(0)); diff --git a/e2e/fake-timers/use-real-timers/package.json b/e2e/fake-timers/use-real-timers/package.json index 56af25025716..9e31cf9ea744 100644 --- a/e2e/fake-timers/use-real-timers/package.json +++ b/e2e/fake-timers/use-real-timers/package.json @@ -1,6 +1,8 @@ { "name": "use-real-timers", "jest": { - "timers": "fake" + "fakeTimers": { + "enableGlobally": true + } } } diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index dc8059b39acf..9df215a6d5b3 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -38,11 +38,13 @@ const jestAdapter = async ( testPath, }); - if (config.timers === 'fake' || config.timers === 'modern') { - // during setup, this cannot be null (and it's fine to explode if it is) - environment.fakeTimersModern!.useFakeTimers(); - } else if (config.timers === 'legacy') { - environment.fakeTimers!.useFakeTimers(); + if (config.fakeTimers.enableGlobally) { + if (config.fakeTimers.legacyFakeTimers) { + // during setup, this cannot be null (and it's fine to explode if it is) + environment.fakeTimers!.useFakeTimers(); + } else { + environment.fakeTimersModern!.useFakeTimers(); + } } globals.beforeEach(() => { @@ -57,7 +59,10 @@ const jestAdapter = async ( if (config.resetMocks) { runtime.resetAllMocks(); - if (config.timers === 'legacy') { + if ( + config.fakeTimers.enableGlobally && + config.fakeTimers.legacyFakeTimers + ) { // during setup, this cannot be null (and it's fine to explode if it is) environment.fakeTimers!.useFakeTimers(); } diff --git a/packages/jest-cli/src/cli/args.ts b/packages/jest-cli/src/cli/args.ts index 2a1b1797db6f..da80102fc9c9 100644 --- a/packages/jest-cli/src/cli/args.ts +++ b/packages/jest-cli/src/cli/args.ts @@ -637,12 +637,6 @@ export const options: {[key: string]: Options} = { description: 'This option sets the default timeouts of test cases.', type: 'number', }, - timers: { - description: - 'Setting this value to fake allows the use of fake timers ' + - 'for functions such as setTimeout.', - type: 'string', - }, transform: { description: 'A JSON string which maps from regular expressions to paths ' + diff --git a/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.js.snap b/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.js.snap index 2c5c94dd9d4b..31cca289857e 100644 --- a/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.js.snap +++ b/packages/jest-cli/src/init/__tests__/__snapshots__/init.test.js.snap @@ -168,6 +168,11 @@ module.exports = { // Make calling deprecated APIs throw helpful error messages // errorOnDeprecated: false, + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + // Force coverage collection from ignored files using an array of glob patterns // forceCoverageMatch: [], @@ -285,9 +290,6 @@ module.exports = { // This option allows use of a custom test runner // testRunner: "jest-circus/runner", - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - // A map from regular expressions to paths to transformers // transform: undefined, diff --git a/packages/jest-config/src/Defaults.ts b/packages/jest-config/src/Defaults.ts index 45cd6b7481d8..cb85437b3593 100644 --- a/packages/jest-config/src/Defaults.ts +++ b/packages/jest-config/src/Defaults.ts @@ -31,6 +31,7 @@ const defaultOptions: Config.DefaultOptions = { errorOnDeprecated: false, expand: false, extensionsToTreatAsEsm: [], + fakeTimers: {enableGlobally: false}, forceCoverageMatch: [], globals: {}, haste: { @@ -81,7 +82,6 @@ const defaultOptions: Config.DefaultOptions = { testRegex: [], testRunner: 'jest-circus/runner', testSequencer: '@jest/test-sequencer', - timers: 'real', transformIgnorePatterns: [NODE_MODULES_REGEXP, `\\.pnp\\.[^\\${sep}]+$`], useStderr: false, watch: false, diff --git a/packages/jest-config/src/Deprecated.ts b/packages/jest-config/src/Deprecated.ts index 4568d7fed3c0..905d3ebdde5b 100644 --- a/packages/jest-config/src/Deprecated.ts +++ b/packages/jest-config/src/Deprecated.ts @@ -94,6 +94,12 @@ const deprecatedOptions: DeprecatedOptions = { )}. Please update your configuration.`, + + timers: (_options: {timers?: string}) => ` Option ${chalk.bold( + '"timers"', + )} was replaced by ${chalk.bold('"fakeTimers"')}. + + Please update your configuration.`, }; export default deprecatedOptions; diff --git a/packages/jest-config/src/Descriptions.ts b/packages/jest-config/src/Descriptions.ts index 9f4549e5fb22..cd5ecb00cef1 100644 --- a/packages/jest-config/src/Descriptions.ts +++ b/packages/jest-config/src/Descriptions.ts @@ -31,6 +31,7 @@ const descriptions: {[key in keyof Config.InitialOptions]: string} = { dependencyExtractor: 'A path to a custom dependency extractor', errorOnDeprecated: 'Make calling deprecated APIs throw helpful error messages', + fakeTimers: 'The default configuration for fake timers', forceCoverageMatch: 'Force coverage collection from ignored files using an array of glob patterns', globalSetup: @@ -84,8 +85,6 @@ const descriptions: {[key in keyof Config.InitialOptions]: string} = { testResultsProcessor: 'This option allows the use of a custom results processor', testRunner: 'This option allows use of a custom test runner', - timers: - 'Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"', transform: 'A map from regular expressions to paths to transformers', transformIgnorePatterns: 'An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation', diff --git a/packages/jest-config/src/ValidConfig.ts b/packages/jest-config/src/ValidConfig.ts index 53e833d76ff2..4cac317e0971 100644 --- a/packages/jest-config/src/ValidConfig.ts +++ b/packages/jest-config/src/ValidConfig.ts @@ -49,6 +49,30 @@ const initialOptions: Config.InitialOptions = { errorOnDeprecated: false, expand: false, extensionsToTreatAsEsm: [], + fakeTimers: { + advanceTimers: multipleValidOptions(40, true), + doNotFake: [ + 'Date', + 'hrtime', + 'nextTick', + 'performance', + 'queueMicrotask', + 'requestAnimationFrame', + 'cancelAnimationFrame', + 'requestIdleCallback', + 'cancelIdleCallback', + 'setImmediate', + 'clearImmediate', + 'setInterval', + 'clearInterval', + 'setTimeout', + 'clearTimeout', + ], + enableGlobally: true, + legacyFakeTimers: false, + now: 1483228800000, + timerLimit: 1000, + }, filter: '/filter.js', forceCoverageMatch: ['**/*.t.js'], forceExit: false, @@ -141,7 +165,6 @@ const initialOptions: Config.InitialOptions = { testRunner: 'circus', testSequencer: '@jest/test-sequencer', testTimeout: 5000, - timers: 'real', transform: { '\\.js$': '/preprocessor.js', }, diff --git a/packages/jest-config/src/__tests__/__snapshots__/normalize.test.ts.snap b/packages/jest-config/src/__tests__/__snapshots__/normalize.test.ts.snap index 46538f039b17..a3d700f5b943 100644 --- a/packages/jest-config/src/__tests__/__snapshots__/normalize.test.ts.snap +++ b/packages/jest-config/src/__tests__/__snapshots__/normalize.test.ts.snap @@ -301,6 +301,30 @@ exports[`testURL logs a deprecation warning when \`testURL\` is used 1`] = ` } `; +exports[`timers logs a deprecation warning when \`timers\` is used 1`] = ` +[MockFunction] { + "calls": Array [ + Array [ + " Deprecation Warning: + + Option "timers" was replaced by "fakeTimers". + + Please update your configuration. + + Configuration Documentation: + https://jestjs.io/docs/configuration +", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], +} +`; + exports[`watchPlugins throw error when a watch plugin is not found 1`] = ` "Validation Error: diff --git a/packages/jest-config/src/__tests__/normalize.test.ts b/packages/jest-config/src/__tests__/normalize.test.ts index 5139b873215c..077b3be65d02 100644 --- a/packages/jest-config/src/__tests__/normalize.test.ts +++ b/packages/jest-config/src/__tests__/normalize.test.ts @@ -1939,6 +1939,24 @@ describe('testURL', () => { }); }); +describe('timers', () => { + beforeEach(() => { + jest.mocked(console.warn).mockImplementation(() => {}); + }); + + it('logs a deprecation warning when `timers` is used', async () => { + await normalize( + { + rootDir: '/root/', + timers: 'real', + }, + {} as Config.Argv, + ); + + expect(console.warn).toMatchSnapshot(); + }); +}); + describe('extraGlobals', () => { beforeEach(() => { jest.mocked(console.warn).mockImplementation(() => {}); diff --git a/packages/jest-config/src/index.ts b/packages/jest-config/src/index.ts index 229bdf750921..e44d23bc5f23 100644 --- a/packages/jest-config/src/index.ts +++ b/packages/jest-config/src/index.ts @@ -185,6 +185,7 @@ const groupOptions = ( displayName: options.displayName, errorOnDeprecated: options.errorOnDeprecated, extensionsToTreatAsEsm: options.extensionsToTreatAsEsm, + fakeTimers: options.fakeTimers, filter: options.filter, forceCoverageMatch: options.forceCoverageMatch, globalSetup: options.globalSetup, @@ -223,7 +224,6 @@ const groupOptions = ( testPathIgnorePatterns: options.testPathIgnorePatterns, testRegex: options.testRegex, testRunner: options.testRunner, - timers: options.timers, transform: options.transform, transformIgnorePatterns: options.transformIgnorePatterns, unmockedModulePathPatterns: options.unmockedModulePathPatterns, diff --git a/packages/jest-config/src/normalize.ts b/packages/jest-config/src/normalize.ts index 6a09c510435f..a07ec04a372a 100644 --- a/packages/jest-config/src/normalize.ts +++ b/packages/jest-config/src/normalize.ts @@ -980,6 +980,7 @@ export default async function normalize( case 'expand': case 'extensionsToTreatAsEsm': case 'globals': + case 'fakeTimers': case 'findRelatedTests': case 'forceCoverageMatch': case 'forceExit': @@ -1014,7 +1015,6 @@ export default async function normalize( case 'testFailureExitCode': case 'testLocationInResults': case 'testNamePattern': - case 'timers': case 'useStderr': case 'verbose': case 'watch': diff --git a/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap b/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap index dea4afbba9ef..fb42e183f896 100644 --- a/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap +++ b/packages/jest-core/src/lib/__tests__/__snapshots__/logDebugMessages.test.ts.snap @@ -13,6 +13,9 @@ exports[`prints the config object 1`] = ` "detectOpenHandles": false, "errorOnDeprecated": false, "extensionsToTreatAsEsm": [], + "fakeTimers": { + "enableGlobally": false + }, "forceCoverageMatch": [], "globals": {}, "haste": {}, @@ -52,7 +55,6 @@ exports[`prints the config object 1`] = ` "\\\\.test\\\\.js$" ], "testRunner": "myRunner", - "timers": "real", "transform": [], "transformIgnorePatterns": [], "watchPathIgnorePatterns": [] diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index 6a96143ada73..67b57c37fa03 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -140,7 +140,7 @@ export interface Jest { * need access to the real current time, you can invoke this function. * * @remarks - * Only available when using 'modern' fake timers implementation. + * Not available when using legacy fake timers implementation. */ getRealSystemTime(): number; /** @@ -236,7 +236,7 @@ export interface Jest { * Exhausts tasks queued by `setImmediate()`. * * @remarks - * Not available when using 'modern' timers implementation. + * Only available when using legacy fake timers implementation. */ runAllImmediates(): void; /** @@ -272,7 +272,7 @@ export interface Jest { * as they would have done without the call to `jest.setSystemTime()`. * * @remarks - * Only available when using 'modern' fake timers implementation. + * Not available when using legacy fake timers implementation. */ setSystemTime(now?: number | Date): void; /** @@ -302,11 +302,20 @@ export interface Jest { */ unmock(moduleName: string): Jest; /** - * Instructs Jest to use fake versions of the standard timer functions. + * 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). + * + * @remarks + * Calling `jest.useFakeTimers()` once again in the same test file would reinstall + * fake timers using the provided options. */ - useFakeTimers(implementation?: 'modern' | 'legacy'): Jest; + useFakeTimers( + fakeTimersConfig?: Config.FakeTimersConfig | Config.LegacyFakeTimersConfig, + ): Jest; /** - * 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. */ useRealTimers(): Jest; } diff --git a/packages/jest-fake-timers/package.json b/packages/jest-fake-timers/package.json index 264beaa4f5b0..b029cb30b8ab 100644 --- a/packages/jest-fake-timers/package.json +++ b/packages/jest-fake-timers/package.json @@ -25,7 +25,8 @@ "jest-util": "^28.0.0-alpha.7" }, "devDependencies": { - "@types/sinonjs__fake-timers": "^8.1.1" + "@jest/test-utils": "^28.0.0-alpha.7", + "@types/sinonjs__fake-timers": "^8.1.2" }, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.13.0 || >=17.0.0" diff --git a/packages/jest-fake-timers/src/__tests__/__snapshots__/legacyFakeTimers.test.ts.snap b/packages/jest-fake-timers/src/__tests__/__snapshots__/legacyFakeTimers.test.ts.snap index 035160d483e5..4a1286a87aed 100644 --- a/packages/jest-fake-timers/src/__tests__/__snapshots__/legacyFakeTimers.test.ts.snap +++ b/packages/jest-fake-timers/src/__tests__/__snapshots__/legacyFakeTimers.test.ts.snap @@ -1,7 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FakeTimers runAllTimers warns when trying to advance timers while real timers are used 1`] = ` -"A function to advance timers was called but the timers API is not mocked with fake timers. Call \`jest.useFakeTimers()\` in this test or enable fake timers globally by setting \`"timers": "fake"\` in the configuration file. This warning is likely a result of a default configuration change in Jest 15. - -Release Blog Post: https://jestjs.io/blog/2016/09/01/jest-15" -`; +exports[`FakeTimers runAllTimers warns when trying to advance timers while real timers are used 1`] = `"A function to advance timers was called but the timers APIs are not mocked with fake timers. Call \`jest.useFakeTimers({legacyFakeTimers: true})\` in this test file or enable fake timers for all tests by setting {'enableGlobally': true, 'legacyFakeTimers': true} in Jest configuration file."`; diff --git a/packages/jest-fake-timers/src/__tests__/__snapshots__/modernFakeTimers.test.ts.snap b/packages/jest-fake-timers/src/__tests__/__snapshots__/modernFakeTimers.test.ts.snap index 8b00458786e1..daf980ad8701 100644 --- a/packages/jest-fake-timers/src/__tests__/__snapshots__/modernFakeTimers.test.ts.snap +++ b/packages/jest-fake-timers/src/__tests__/__snapshots__/modernFakeTimers.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FakeTimers runAllTimers warns when trying to advance timers while real timers are used 1`] = `"A function to advance timers was called but the timers API is not mocked with fake timers. Call \`jest.useFakeTimers()\` in this test or enable fake timers globally by setting \`"timers": "fake"\` in the configuration file"`; +exports[`FakeTimers runAllTimers warns when trying to advance timers while real timers are used 1`] = `"A function to advance timers was called but the timers APIs are not replaced with fake timers. Call \`jest.useFakeTimers()\` in this test file or enable fake timers for all tests by setting 'fakeTimers': {'enableGlobally': true} in Jest configuration file."`; diff --git a/packages/jest-fake-timers/src/__tests__/modernFakeTimers.test.ts b/packages/jest-fake-timers/src/__tests__/modernFakeTimers.test.ts index 36b14aecc128..a2cddb4a871d 100644 --- a/packages/jest-fake-timers/src/__tests__/modernFakeTimers.test.ts +++ b/packages/jest-fake-timers/src/__tests__/modernFakeTimers.test.ts @@ -6,6 +6,7 @@ * */ +import {makeProjectConfig} from '@jest/test-utils'; import FakeTimers from '../modernFakeTimers'; describe('FakeTimers', () => { @@ -17,7 +18,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.setTimeout).not.toBe(undefined); }); @@ -29,7 +30,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.clearTimeout).not.toBe(undefined); }); @@ -41,7 +42,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.setInterval).not.toBe(undefined); }); @@ -53,7 +54,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.clearInterval).not.toBe(undefined); }); @@ -68,7 +69,7 @@ describe('FakeTimers', () => { }, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.process.nextTick).not.toBe(origNextTick); }); @@ -82,7 +83,7 @@ describe('FakeTimers', () => { setImmediate: origSetImmediate, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.setImmediate).not.toBe(origSetImmediate); }); @@ -98,7 +99,7 @@ describe('FakeTimers', () => { setImmediate: origSetImmediate, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); expect(global.clearImmediate).not.toBe(origClearImmediate); }); @@ -115,7 +116,7 @@ describe('FakeTimers', () => { setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder = []; @@ -146,7 +147,7 @@ describe('FakeTimers', () => { setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); timers.runAllTicks(); @@ -163,7 +164,7 @@ describe('FakeTimers', () => { setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const mock1 = jest.fn(); @@ -187,7 +188,10 @@ describe('FakeTimers', () => { setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global, maxLoops: 100}); + const timers = new FakeTimers({ + config: makeProjectConfig({fakeTimers: {timerLimit: 100}}), + global, + }); timers.useFakeTimers(); @@ -211,7 +215,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder = []; @@ -247,9 +251,7 @@ describe('FakeTimers', () => { const consoleWarn = console.warn; console.warn = jest.fn(); const timers = new FakeTimers({ - config: { - rootDir: __dirname, - }, + config: makeProjectConfig({rootDir: __dirname}), global: globalThis, }); timers.runAllTimers(); @@ -268,7 +270,7 @@ describe('FakeTimers', () => { setTimeout: nativeSetTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); timers.runAllTimers(); }); @@ -280,7 +282,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const fn = jest.fn(); @@ -301,7 +303,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const fn = jest.fn(); @@ -322,7 +324,7 @@ describe('FakeTimers', () => { setTimeout: nativeSetTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); // @sinonjs/fake-timers uses `setTimeout` during init to figure out if it's in Node or // browser env. So clear its calls before we install them into the env nativeSetTimeout.mockClear(); @@ -343,7 +345,10 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global, maxLoops: 100}); + const timers = new FakeTimers({ + config: makeProjectConfig({fakeTimers: {timerLimit: 1000}}), + global, + }); timers.useFakeTimers(); global.setTimeout(function infinitelyRecursingCallback() { @@ -354,7 +359,7 @@ describe('FakeTimers', () => { timers.runAllTimers(); }).toThrow( new Error( - 'Aborting after running 100 timers, assuming an infinite loop!', + 'Aborting after running 1000 timers, assuming an infinite loop!', ), ); }); @@ -366,7 +371,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const fn = jest.fn(); @@ -388,7 +393,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder = []; @@ -432,7 +437,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); timers.advanceTimersByTime(100); @@ -447,7 +452,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder: Array = []; @@ -487,7 +492,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder: Array = []; @@ -526,7 +531,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder: Array = []; @@ -554,7 +559,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); timers.advanceTimersToNextTimer(); @@ -569,7 +574,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const mock1 = jest.fn(); @@ -587,7 +592,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const mock1 = jest.fn(); @@ -608,7 +613,7 @@ describe('FakeTimers', () => { setImmediate: () => {}, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const mock1 = jest.fn(); @@ -627,7 +632,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const mock1 = jest.fn(); @@ -654,7 +659,7 @@ describe('FakeTimers', () => { setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const runOrder = []; @@ -719,7 +724,7 @@ describe('FakeTimers', () => { process, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); const fn = jest.fn(); @@ -748,7 +753,7 @@ describe('FakeTimers', () => { setInterval: nativeSetInterval, setTimeout: nativeSetTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); // Ensure that timers has overridden the native timer APIs @@ -775,7 +780,7 @@ describe('FakeTimers', () => { process: {nextTick: nativeProcessNextTick}, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); // Ensure that timers has overridden the native timer APIs @@ -799,7 +804,7 @@ describe('FakeTimers', () => { setImmediate: nativeSetImmediate, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useFakeTimers(); // Ensure that timers has overridden the native timer APIs @@ -829,7 +834,7 @@ describe('FakeTimers', () => { setInterval: nativeSetInterval, setTimeout: nativeSetTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useRealTimers(); // Ensure that the real timers are installed at this point @@ -856,7 +861,7 @@ describe('FakeTimers', () => { process: {nextTick: nativeProcessNextTick}, setTimeout, } as unknown as typeof globalThis; - const timers = new FakeTimers({global}); + const timers = new FakeTimers({config: makeProjectConfig(), global}); timers.useRealTimers(); // Ensure that the real timers are installed at this point @@ -880,7 +885,7 @@ describe('FakeTimers', () => { setImmediate: nativeSetImmediate, setTimeout, } as unknown as typeof globalThis; - const fakeTimers = new FakeTimers({global}); + const fakeTimers = new FakeTimers({config: makeProjectConfig(), global}); fakeTimers.useRealTimers(); // Ensure that the real timers are installed at this point @@ -897,7 +902,10 @@ describe('FakeTimers', () => { describe('getTimerCount', () => { it('returns the correct count', () => { - const timers = new FakeTimers({global: globalThis}); + const timers = new FakeTimers({ + config: makeProjectConfig(), + global: globalThis, + }); timers.useFakeTimers(); @@ -917,7 +925,10 @@ describe('FakeTimers', () => { }); it('includes immediates and ticks', () => { - const timers = new FakeTimers({global: globalThis}); + const timers = new FakeTimers({ + config: makeProjectConfig(), + global: globalThis, + }); timers.useFakeTimers(); @@ -929,7 +940,10 @@ describe('FakeTimers', () => { }); it('not includes cancelled immediates', () => { - const timers = new FakeTimers({global: globalThis}); + const timers = new FakeTimers({ + config: makeProjectConfig(), + global: globalThis, + }); timers.useFakeTimers(); diff --git a/packages/jest-fake-timers/src/__tests__/sinon-integration.test.ts b/packages/jest-fake-timers/src/__tests__/sinon-integration.test.ts new file mode 100644 index 000000000000..528e2d15937c --- /dev/null +++ b/packages/jest-fake-timers/src/__tests__/sinon-integration.test.ts @@ -0,0 +1,181 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import {makeProjectConfig} from '@jest/test-utils'; +import FakeTimers from '../modernFakeTimers'; + +jest.spyOn(Date, 'now').mockImplementation(() => 123456); + +const mockInstall = jest.fn(); + +const mockWithGlobal = { + install: mockInstall, + timers: { + Date: jest.fn(), + clearImmediate: jest.fn(), + clearInterval: jest.fn(), + clearTimeout: jest.fn(), + hrtime: jest.fn(), + nextTick: jest.fn(), + performance: jest.fn(), + queueMicrotask: jest.fn(), + setImmediate: jest.fn(), + setInterval: jest.fn(), + setTimeout: jest.fn(), + }, +}; + +jest.mock('@sinonjs/fake-timers', () => { + return { + withGlobal: jest.fn(() => mockWithGlobal), + }; +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('`@sinonjs/fake-timers` integration', () => { + test('uses default global config, when `useFakeTimers()` is called without options', () => { + const timers = new FakeTimers({ + config: makeProjectConfig(), + global: globalThis, + }); + + timers.useFakeTimers(); + + expect(mockInstall).toBeCalledWith({ + advanceTimeDelta: undefined, + loopLimit: 100_000, + now: 123456, + shouldAdvanceTime: false, + shouldClearNativeTimers: true, + toFake: [ + 'Date', + 'clearImmediate', + 'clearInterval', + 'clearTimeout', + 'hrtime', + 'nextTick', + 'performance', + 'queueMicrotask', + 'setImmediate', + 'setInterval', + 'setTimeout', + ], + }); + }); + + test('uses custom global config, when `useFakeTimers()` is called without options', () => { + const timers = new FakeTimers({ + config: makeProjectConfig({ + fakeTimers: { + advanceTimers: true, + doNotFake: ['Date', 'nextTick'], + now: 0, + timerLimit: 100, + }, + }), + global: globalThis, + }); + + timers.useFakeTimers(); + + expect(mockInstall).toBeCalledWith({ + advanceTimeDelta: undefined, + loopLimit: 100, + now: 0, + shouldAdvanceTime: true, + shouldClearNativeTimers: true, + toFake: [ + 'clearImmediate', + 'clearInterval', + 'clearTimeout', + 'hrtime', + 'performance', + 'queueMicrotask', + 'setImmediate', + 'setInterval', + 'setTimeout', + ], + }); + }); + + test('overrides default global config, when `useFakeTimers()` is called with options,', () => { + const timers = new FakeTimers({ + config: makeProjectConfig(), + global: globalThis, + }); + + timers.useFakeTimers({ + advanceTimers: 40, + doNotFake: ['Date', 'queueMicrotask'], + now: new Date('1995-12-17'), + timerLimit: 2000, + }); + + expect(mockInstall).toBeCalledWith({ + advanceTimeDelta: 40, + loopLimit: 2000, + now: new Date('1995-12-17'), + shouldAdvanceTime: true, + shouldClearNativeTimers: true, + toFake: [ + 'clearImmediate', + 'clearInterval', + 'clearTimeout', + 'hrtime', + 'nextTick', + 'performance', + 'setImmediate', + 'setInterval', + 'setTimeout', + ], + }); + }); + + test('overrides custom global config, when `useFakeTimers()` is called with options,', () => { + const timers = new FakeTimers({ + config: makeProjectConfig({ + fakeTimers: { + advanceTimers: 20, + doNotFake: ['Date', 'nextTick'], + now: 0, + timerLimit: 1000, + }, + }), + global: globalThis, + }); + + timers.useFakeTimers({ + advanceTimers: false, + doNotFake: ['hrtime'], + now: 123456, + }); + + expect(mockInstall).toBeCalledWith({ + advanceTimeDelta: undefined, + loopLimit: 1000, + now: 123456, + shouldAdvanceTime: false, + shouldClearNativeTimers: true, + toFake: [ + 'Date', + 'clearImmediate', + 'clearInterval', + 'clearTimeout', + 'nextTick', + 'performance', + 'queueMicrotask', + 'setImmediate', + 'setInterval', + 'setTimeout', + ], + }); + }); +}); diff --git a/packages/jest-fake-timers/src/legacyFakeTimers.ts b/packages/jest-fake-timers/src/legacyFakeTimers.ts index ee957b0444fb..e4b719f5d6b3 100644 --- a/packages/jest-fake-timers/src/legacyFakeTimers.ts +++ b/packages/jest-fake-timers/src/legacyFakeTimers.ts @@ -402,16 +402,15 @@ export default class FakeTimers { // @ts-expect-error: condition always returns 'true' if (this._global.setTimeout !== this._fakeTimerAPIs?.setTimeout) { this._global.console.warn( - 'A function to advance timers was called but the timers API is not ' + - 'mocked with fake timers. Call `jest.useFakeTimers()` in this ' + - 'test or enable fake timers globally by setting ' + - '`"timers": "fake"` in ' + - 'the configuration file. This warning is likely a result of a ' + - 'default configuration change in Jest 15.\n\n' + - 'Release Blog Post: https://jestjs.io/blog/2016/09/01/jest-15\n' + - `Stack Trace:\n${formatStackTrace(new Error().stack!, this._config, { - noStackTrace: false, - })}`, + 'A function to advance timers was called but the timers APIs are not mocked ' + + 'with fake timers. Call `jest.useFakeTimers({legacyFakeTimers: true})` ' + + 'in this test file or enable fake timers for all tests by setting ' + + "{'enableGlobally': true, 'legacyFakeTimers': true} in " + + `Jest configuration file.\nStack Trace:\n${formatStackTrace( + new Error().stack!, + this._config, + {noStackTrace: false}, + )}`, ); } } diff --git a/packages/jest-fake-timers/src/modernFakeTimers.ts b/packages/jest-fake-timers/src/modernFakeTimers.ts index 93abce4dd4c9..f8363388c9ce 100644 --- a/packages/jest-fake-timers/src/modernFakeTimers.ts +++ b/packages/jest-fake-timers/src/modernFakeTimers.ts @@ -7,31 +7,30 @@ import { FakeTimerWithContext, + FakeMethod as FakeableAPI, InstalledClock, + FakeTimerInstallOpts as SinonFakeTimersConfig, withGlobal, } from '@sinonjs/fake-timers'; -import {StackTraceConfig, formatStackTrace} from 'jest-message-util'; +import type {Config} from '@jest/types'; +import {formatStackTrace} from 'jest-message-util'; export default class FakeTimers { private _clock!: InstalledClock; - private _config: StackTraceConfig; + private _config: Config.ProjectConfig; private _fakingTime: boolean; private _global: typeof globalThis; private _fakeTimers: FakeTimerWithContext; - private _maxLoops: number; constructor({ global, config, - maxLoops, }: { global: typeof globalThis; - config: StackTraceConfig; - maxLoops?: number; + config: Config.ProjectConfig; }) { this._global = global; this._config = config; - this._maxLoops = maxLoops || 100000; this._fakingTime = false; this._fakeTimers = withGlobal(global); @@ -93,20 +92,16 @@ export default class FakeTimers { } } - useFakeTimers(): void { - if (!this._fakingTime) { - const toFake = Object.keys(this._fakeTimers.timers) as Array< - keyof FakeTimerWithContext['timers'] - >; + useFakeTimers(fakeTimersConfig?: Config.FakeTimersConfig): void { + if (this._fakingTime) { + this._clock.uninstall(); + } - this._clock = this._fakeTimers.install({ - loopLimit: this._maxLoops, - now: Date.now(), - toFake, - }); + this._clock = this._fakeTimers.install( + this._toSinonFakeTimersConfig(fakeTimersConfig), + ); - this._fakingTime = true; - } + this._fakingTime = true; } reset(): void { @@ -138,10 +133,10 @@ export default class FakeTimers { private _checkFakeTimers() { if (!this._fakingTime) { this._global.console.warn( - 'A function to advance timers was called but the timers API is not ' + - 'mocked with fake timers. Call `jest.useFakeTimers()` in this test or ' + - 'enable fake timers globally by setting `"timers": "fake"` in the ' + - `configuration file\nStack Trace:\n${formatStackTrace( + 'A function to advance timers was called but the timers APIs are not replaced ' + + 'with fake timers. Call `jest.useFakeTimers()` in this test file or enable ' + + "fake timers for all tests by setting 'fakeTimers': {'enableGlobally': true} " + + `in Jest configuration file.\nStack Trace:\n${formatStackTrace( new Error().stack!, this._config, {noStackTrace: false}, @@ -151,4 +146,35 @@ export default class FakeTimers { return this._fakingTime; } + + private _toSinonFakeTimersConfig( + fakeTimersConfig: Config.FakeTimersConfig = {}, + ): SinonFakeTimersConfig { + fakeTimersConfig = { + ...this._config.fakeTimers, + ...fakeTimersConfig, + } as Config.FakeTimersConfig; + + const advanceTimeDelta = + typeof fakeTimersConfig.advanceTimers === 'number' + ? fakeTimersConfig.advanceTimers + : undefined; + + const toFake = new Set( + Object.keys(this._fakeTimers.timers) as Array, + ); + + fakeTimersConfig.doNotFake?.forEach(nameOfFakeableAPI => { + toFake.delete(nameOfFakeableAPI); + }); + + return { + advanceTimeDelta, + loopLimit: fakeTimersConfig.timerLimit || 100_000, + now: fakeTimersConfig.now ?? Date.now(), + shouldAdvanceTime: Boolean(fakeTimersConfig.advanceTimers), + shouldClearNativeTimers: true, + toFake: Array.from(toFake), + }; + } } diff --git a/packages/jest-fake-timers/tsconfig.json b/packages/jest-fake-timers/tsconfig.json index 0bdcddc53258..4a4b01562562 100644 --- a/packages/jest-fake-timers/tsconfig.json +++ b/packages/jest-fake-timers/tsconfig.json @@ -10,6 +10,7 @@ {"path": "../jest-message-util"}, {"path": "../jest-mock"}, {"path": "../jest-types"}, - {"path": "../jest-util"} + {"path": "../jest-util"}, + {"path": "../test-utils"} ] } diff --git a/packages/jest-jasmine2/src/index.ts b/packages/jest-jasmine2/src/index.ts index d8f1a14bc4f5..cf7c8bf5b4b1 100644 --- a/packages/jest-jasmine2/src/index.ts +++ b/packages/jest-jasmine2/src/index.ts @@ -88,10 +88,12 @@ export default async function jasmine2( environment.global.describe.skip = environment.global.xdescribe; environment.global.describe.only = environment.global.fdescribe; - if (config.timers === 'fake' || config.timers === 'modern') { - environment.fakeTimersModern!.useFakeTimers(); - } else if (config.timers === 'legacy') { - environment.fakeTimers!.useFakeTimers(); + if (config.fakeTimers.enableGlobally) { + if (config.fakeTimers.legacyFakeTimers) { + environment.fakeTimers!.useFakeTimers(); + } else { + environment.fakeTimersModern!.useFakeTimers(); + } } env.beforeEach(() => { @@ -106,7 +108,10 @@ export default async function jasmine2( if (config.resetMocks) { runtime.resetAllMocks(); - if (config.timers === 'legacy') { + if ( + config.fakeTimers.enableGlobally && + config.fakeTimers.legacyFakeTimers + ) { environment.fakeTimers!.useFakeTimers(); } } diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 7fc8a91f6af3..abc76358872b 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -279,10 +279,9 @@ export default class Runtime { this._shouldUnmockTransitiveDependenciesCache = new Map(); this._transitiveShouldMock = new Map(); - this._fakeTimersImplementation = - config.timers === 'legacy' - ? this._environment.fakeTimers - : this._environment.fakeTimersModern; + this._fakeTimersImplementation = config.fakeTimers.legacyFakeTimers + ? this._environment.fakeTimers + : this._environment.fakeTimersModern; this._unmockList = unmockRegExpCache.get(config); if (!this._unmockList && config.unmockedModulePathPatterns) { @@ -2065,13 +2064,17 @@ export default class Runtime { return this._fakeTimersImplementation!; }; - const useFakeTimers: Jest['useFakeTimers'] = (type = 'modern') => { - if (type === 'legacy') { + const useFakeTimers: Jest['useFakeTimers'] = fakeTimersConfig => { + fakeTimersConfig = { + ...this._config.fakeTimers, + ...fakeTimersConfig, + } as Config.FakeTimersConfig; + if (fakeTimersConfig?.legacyFakeTimers) { this._fakeTimersImplementation = this._environment.fakeTimers; } else { this._fakeTimersImplementation = this._environment.fakeTimersModern; } - this._fakeTimersImplementation!.useFakeTimers(); + this._fakeTimersImplementation!.useFakeTimers(fakeTimersConfig); return jestObject; }; const useRealTimers = () => { @@ -2134,7 +2137,7 @@ export default class Runtime { return fakeTimers.getRealSystemTime(); } else { throw new TypeError( - 'getRealSystemTime is not available when not using modern timers', + '`jest.getRealSystemTime()` is not available when using legacy fake timers.', ); } }, @@ -2156,7 +2159,7 @@ export default class Runtime { fakeTimers.runAllImmediates(); } else { throw new TypeError( - 'runAllImmediates is not available when using modern timers', + '`jest.runAllImmediates()` is only available when using legacy fake timers.', ); } }, @@ -2172,7 +2175,7 @@ export default class Runtime { fakeTimers.setSystemTime(now); } else { throw new TypeError( - 'setSystemTime is not available when not using modern timers', + '`jest.setSystemTime()` is not available when using legacy fake timers.', ); } }, diff --git a/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap b/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap index 7d89d8bbf339..582da17801e8 100644 --- a/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap +++ b/packages/jest-transform/src/__tests__/__snapshots__/ScriptTransformer.test.ts.snap @@ -34,6 +34,9 @@ exports[`ScriptTransformer in async mode, passes expected transform options to g "displayName": undefined, "errorOnDeprecated": false, "extensionsToTreatAsEsm": Array [], + "fakeTimers": Object { + "enableGlobally": false, + }, "filter": undefined, "forceCoverageMatch": Array [], "globalSetup": undefined, @@ -76,7 +79,6 @@ exports[`ScriptTransformer in async mode, passes expected transform options to g "\\.test\\.js$", ], "testRunner": "jest-circus/runner", - "timers": "real", "transform": Array [ Array [ "\\.js$", @@ -92,7 +94,7 @@ exports[`ScriptTransformer in async mode, passes expected transform options to g "unmockedModulePathPatterns": undefined, "watchPathIgnorePatterns": Array [], }, - "configString": "{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_preprocessor",{"configKey":"configValue"}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}", + "configString": "{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_preprocessor",{"configKey":"configValue"}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}", "coverageProvider": "babel", "instrument": true, "supportsDynamicImport": false, @@ -118,7 +120,7 @@ exports[`ScriptTransformer in async mode, uses the supplied async preprocessor 1 "const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_async_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_async_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_async_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"fakeTimers\\":{\\"enableGlobally\\":false},\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_async_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', };" `; @@ -128,7 +130,7 @@ exports[`ScriptTransformer in async mode, uses the supplied preprocessor 1`] = ` "const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"fakeTimers\\":{\\"enableGlobally\\":false},\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', };" `; @@ -165,6 +167,9 @@ exports[`ScriptTransformer passes expected transform options to getCacheKey 1`] "displayName": undefined, "errorOnDeprecated": false, "extensionsToTreatAsEsm": Array [], + "fakeTimers": Object { + "enableGlobally": false, + }, "filter": undefined, "forceCoverageMatch": Array [], "globalSetup": undefined, @@ -207,7 +212,6 @@ exports[`ScriptTransformer passes expected transform options to getCacheKey 1`] "\\.test\\.js$", ], "testRunner": "jest-circus/runner", - "timers": "real", "transform": Array [ Array [ "\\.js$", @@ -223,7 +227,7 @@ exports[`ScriptTransformer passes expected transform options to getCacheKey 1`] "unmockedModulePathPatterns": undefined, "watchPathIgnorePatterns": Array [], }, - "configString": "{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_preprocessor",{"configKey":"configValue"}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}", + "configString": "{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_preprocessor",{"configKey":"configValue"}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}", "coverageProvider": "babel", "instrument": true, "supportsDynamicImport": false, @@ -270,6 +274,9 @@ exports[`ScriptTransformer passes expected transform options to getCacheKeyAsync "displayName": undefined, "errorOnDeprecated": false, "extensionsToTreatAsEsm": Array [], + "fakeTimers": Object { + "enableGlobally": false, + }, "filter": undefined, "forceCoverageMatch": Array [], "globalSetup": undefined, @@ -312,7 +319,6 @@ exports[`ScriptTransformer passes expected transform options to getCacheKeyAsync "\\.test\\.js$", ], "testRunner": "jest-circus/runner", - "timers": "real", "transform": Array [ Array [ "\\.js$", @@ -328,7 +334,7 @@ exports[`ScriptTransformer passes expected transform options to getCacheKeyAsync "unmockedModulePathPatterns": undefined, "watchPathIgnorePatterns": Array [], }, - "configString": "{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_async_preprocessor",{"configKey":"configValue"}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}", + "configString": "{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_async_preprocessor",{"configKey":"configValue"}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}", "coverageProvider": "babel", "instrument": true, "supportsDynamicImport": false, @@ -676,7 +682,7 @@ exports[`ScriptTransformer uses mixture of sync/async preprocessors 1`] = ` "const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_async_preprocessor",{}],["\\\\.css$","css-preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_async_preprocessor\\",{}],[\\"\\\\\\\\.css$\\",\\"css-preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_async_preprocessor",{}],["\\\\.css$","css-preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"fakeTimers\\":{\\"enableGlobally\\":false},\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_async_preprocessor\\",{}],[\\"\\\\\\\\.css$\\",\\"css-preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', };" `; @@ -693,7 +699,7 @@ exports[`ScriptTransformer uses multiple preprocessors 1`] = ` "const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}],["\\\\.css$","css-preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}],[\\"\\\\\\\\.css$\\",\\"css-preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_preprocessor",{}],["\\\\.css$","css-preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"fakeTimers\\":{\\"enableGlobally\\":false},\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}],[\\"\\\\\\\\.css$\\",\\"css-preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', };" `; @@ -710,7 +716,7 @@ exports[`ScriptTransformer uses the supplied preprocessor 1`] = ` "const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"cacheFS":{},"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extensionsToTreatAsEsm":[],"fakeTimers":{"enableGlobally":false},"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","runtime":"/test_module_loader_path","sandboxInjectedGlobals":[],"setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotFormat":{},"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-circus/runner","transform":[["\\\\.js$","test_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extensionsToTreatAsEsm\\":[],\\"fakeTimers\\":{\\"enableGlobally\\":false},\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"runtime\\":\\"/test_module_loader_path\\",\\"sandboxInjectedGlobals\\":[],\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotFormat\\":{},\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-circus/runner\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}","transformerConfig":{}}', };" `; diff --git a/packages/jest-types/__typetests__/config.test.ts b/packages/jest-types/__typetests__/config.test.ts index dd69249ea7b6..04027cae0dcb 100644 --- a/packages/jest-types/__typetests__/config.test.ts +++ b/packages/jest-types/__typetests__/config.test.ts @@ -5,9 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import {expectAssignable} from 'tsd-lite'; +import {expectAssignable, expectError, expectNotAssignable} from 'tsd-lite'; import type {Config} from '@jest/types'; +expectAssignable({}); + expectAssignable({ coverageThreshold: { './src/api/very-important-module.js': { @@ -39,3 +41,79 @@ expectAssignable({ }, ], }); + +const doNotFake: Array = [ + 'Date', + 'hrtime', + 'nextTick', + 'performance', + 'queueMicrotask', + 'requestAnimationFrame', + 'cancelAnimationFrame', + 'requestIdleCallback', + 'cancelIdleCallback', + 'setImmediate', + 'clearImmediate', + 'setInterval', + 'clearInterval', + 'setTimeout', + 'clearTimeout', +]; + +expectAssignable({ + fakeTimers: { + advanceTimers: true, + doNotFake, + enableGlobally: true, + now: 1483228800000, + timerLimit: 1000, + }, +}); + +expectAssignable({ + fakeTimers: { + advanceTimers: 40, + now: Date.now(), + }, +}); + +expectError({ + fakeTimers: { + now: new Date(), + }, +}); + +expectAssignable({ + fakeTimers: { + enableGlobally: true, + legacyFakeTimers: true, + }, +}); + +expectError({ + fakeTimers: { + advanceTimers: true, + legacyFakeTimers: true, + }, +}); + +expectError({ + fakeTimers: { + doNotFake, + legacyFakeTimers: true, + }, +}); + +expectError({ + fakeTimers: { + legacyFakeTimers: true, + now: 1483228800000, + }, +}); + +expectError({ + fakeTimers: { + legacyFakeTimers: true, + timerLimit: 1000, + }, +}); diff --git a/packages/jest-types/__typetests__/jest.test.ts b/packages/jest-types/__typetests__/jest.test.ts index 6c2a9f17b75a..ae46c5e4e372 100644 --- a/packages/jest-types/__typetests__/jest.test.ts +++ b/packages/jest-types/__typetests__/jest.test.ts @@ -43,8 +43,7 @@ expectType( .setTimeout(6000) .unmock('moduleName') .useFakeTimers() - .useFakeTimers('modern') - .useFakeTimers('legacy') + .useFakeTimers({legacyFakeTimers: true}) .useRealTimers(), ); @@ -248,9 +247,53 @@ expectType(jest.setSystemTime(new Date(1995, 11, 17))); expectError(jest.setSystemTime('1995-12-17T03:24:00')); expectType(jest.useFakeTimers()); -expectType(jest.useFakeTimers('modern')); -expectType(jest.useFakeTimers('legacy')); -expectError(jest.useFakeTimers('latest')); + +expectType(jest.useFakeTimers({advanceTimers: true})); +expectType(jest.useFakeTimers({advanceTimers: 10})); +expectError(jest.useFakeTimers({advanceTimers: 'fast'})); + +expectType(jest.useFakeTimers({doNotFake: ['Date']})); +expectType( + jest.useFakeTimers({ + doNotFake: [ + 'Date', + 'hrtime', + 'nextTick', + 'performance', + 'queueMicrotask', + 'requestAnimationFrame', + 'cancelAnimationFrame', + 'requestIdleCallback', + 'cancelIdleCallback', + 'setImmediate', + 'clearImmediate', + 'setInterval', + 'clearInterval', + 'setTimeout', + 'clearTimeout', + ], + }), +); +expectError(jest.useFakeTimers({doNotFake: ['globalThis']})); + +expectType(jest.useFakeTimers({legacyFakeTimers: true})); +expectError(jest.useFakeTimers({legacyFakeTimers: 1000})); +expectError(jest.useFakeTimers({doNotFake: ['Date'], legacyFakeTimers: true})); +expectError(jest.useFakeTimers({enableGlobally: true, legacyFakeTimers: true})); +expectError(jest.useFakeTimers({legacyFakeTimers: true, now: 1483228800000})); +expectError(jest.useFakeTimers({legacyFakeTimers: true, timerLimit: 1000})); + +expectType(jest.useFakeTimers({now: 1483228800000})); +expectType(jest.useFakeTimers({now: Date.now()})); +expectType(jest.useFakeTimers({now: new Date(1995, 11, 17)})); +expectError(jest.useFakeTimers({now: '1995-12-17T03:24:00'})); + +expectType(jest.useFakeTimers({timerLimit: 1000})); +expectError(jest.useFakeTimers({timerLimit: true})); + +expectError(jest.useFakeTimers({enableGlobally: true})); +expectError(jest.useFakeTimers('legacy')); +expectError(jest.useFakeTimers('modern')); expectType(jest.useRealTimers()); expectError(jest.useRealTimers(true)); diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index d93d77c87b69..3b9d14cf76ab 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -12,7 +12,94 @@ import type {SnapshotFormat} from '@jest/schemas'; type CoverageProvider = 'babel' | 'v8'; -type Timers = 'real' | 'fake' | 'modern' | 'legacy'; +export type FakeableAPI = + | 'Date' + | 'hrtime' + | 'nextTick' + | 'performance' + | 'queueMicrotask' + | 'requestAnimationFrame' + | 'cancelAnimationFrame' + | 'requestIdleCallback' + | 'cancelIdleCallback' + | 'setImmediate' + | 'clearImmediate' + | 'setInterval' + | 'clearInterval' + | 'setTimeout' + | 'clearTimeout'; + +export type GlobalFakeTimersConfig = { + /** + * Whether fake timers should be enabled globally for all test files. + * + * @defaultValue + * The default is `false`. + * */ + enableGlobally?: boolean; +}; + +export 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. + * + * @defaultValue + * The default is `false`. + */ + advanceTimers?: boolean | number; + /** + * List of names of APIs (e.g. `Date`, `nextTick()`, `setImmediate()`, + * `setTimeout()`) that should not be faked. + * + * @defaultValue + * The default is `[]`, meaning all APIs are faked. + * */ + doNotFake?: Array; + /** + * Sets current system time to be used by fake timers. + * + * @defaultValue + * The default is `Date.now()`. + */ + now?: number | Date; + /** + * The maximum number of recursive timers that will be run when calling + * `jest.runAllTimers()`. + * + * @defaultValue + * The default is `100_000` timers. + */ + timerLimit?: number; + /** + * Use the old fake timers implementation instead of one backed by + * [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers). + * + * @defaultValue + * The default is `false`. + */ + legacyFakeTimers?: false; +}; + +export type LegacyFakeTimersConfig = { + /** + * Use the old fake timers implementation instead of one backed by + * [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers). + * + * @defaultValue + * The default is `false`. + */ + legacyFakeTimers?: true; +}; + +type FakeTimers = GlobalFakeTimersConfig & + ( + | (FakeTimersConfig & { + now?: Exclude; + }) + | LegacyFakeTimersConfig + ); export type HasteConfig = { /** Whether to hash files using SHA-1. */ @@ -76,6 +163,7 @@ export type DefaultOptions = { errorOnDeprecated: boolean; expand: boolean; extensionsToTreatAsEsm: Array; + fakeTimers: FakeTimers; forceCoverageMatch: Array; globals: ConfigGlobals; haste: HasteConfig; @@ -112,7 +200,6 @@ export type DefaultOptions = { testRegex: Array; testRunner: string; testSequencer: string; - timers: Timers; transformIgnorePatterns: Array; useStderr: boolean; watch: boolean; @@ -158,6 +245,7 @@ export type InitialOptions = Partial<{ displayName: string | DisplayName; expand: boolean; extensionsToTreatAsEsm: Array; + fakeTimers: FakeTimers; filter: string; findRelatedTests: boolean; forceCoverageMatch: Array; @@ -241,7 +329,6 @@ export type InitialOptions = Partial<{ testRunner: string; testSequencer: string; testTimeout: number; - timers: Timers; transform: { [regex: string]: string | TransformerConfig; }; @@ -363,6 +450,7 @@ export type ProjectConfig = { displayName?: DisplayName; errorOnDeprecated: boolean; extensionsToTreatAsEsm: Array; + fakeTimers: FakeTimers; filter?: string; forceCoverageMatch: Array; globalSetup?: string; @@ -401,7 +489,6 @@ export type ProjectConfig = { testPathIgnorePatterns: Array; testRegex: Array; testRunner: string; - timers: Timers; transform: Array<[string, string, Record]>; transformIgnorePatterns: Array; watchPathIgnorePatterns: Array; @@ -487,7 +574,6 @@ export type Argv = Arguments< testRunner: string; testSequencer: string; testTimeout: number | null | undefined; - timers: string; transform: string; transformIgnorePatterns: Array; unmockedModulePathPatterns: Array | null | undefined; diff --git a/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts b/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts index 6f2b022d2ee8..bcc54ead1baf 100644 --- a/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts +++ b/packages/jest-validate/src/__tests__/fixtures/jestConfig.ts @@ -28,6 +28,7 @@ const defaultConfig = { coveragePathIgnorePatterns: [NODE_MODULES_REGEXP], coverageReporters: ['json', 'text', 'lcov', 'clover'], expand: false, + fakeTimers: {enableGlobally: false}, globals: {}, haste: {}, moduleDirectories: ['node_modules'], @@ -48,7 +49,6 @@ const defaultConfig = { testPathIgnorePatterns: [NODE_MODULES_REGEXP], testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$', testResultsProcessor: null, - timers: 'real', transformIgnorePatterns: [NODE_MODULES_REGEXP], useStderr: false, verbose: null, @@ -77,6 +77,7 @@ const validConfig = { }, }, expand: false, + fakeTimers: {enableGlobally: false}, forceExit: false, globals: {}, haste: {}, @@ -111,7 +112,6 @@ const validConfig = { testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$', testResultsProcessor: 'processor-node-module', testRunner: 'circus', - timers: 'real', transform: { '\\.js$': '/preprocessor.js', }, diff --git a/packages/jest-worker/src/workers/__tests__/processChild.test.js b/packages/jest-worker/src/workers/__tests__/processChild.test.js index ba579e052efe..55b29107bdf7 100644 --- a/packages/jest-worker/src/workers/__tests__/processChild.test.js +++ b/packages/jest-worker/src/workers/__tests__/processChild.test.js @@ -241,8 +241,6 @@ it('returns results immediately when function is synchronous', () => { }); it('returns results when it gets resolved if function is asynchronous', async () => { - jest.useRealTimers(); - process.emit('message', [ CHILD_MESSAGE_INITIALIZE, true, // Not really used here, but for flow type purity. diff --git a/packages/jest-worker/src/workers/__tests__/threadChild.test.js b/packages/jest-worker/src/workers/__tests__/threadChild.test.js index 657ce23a33bb..fe0107a926f2 100644 --- a/packages/jest-worker/src/workers/__tests__/threadChild.test.js +++ b/packages/jest-worker/src/workers/__tests__/threadChild.test.js @@ -268,8 +268,6 @@ it('returns results immediately when function is synchronous', () => { }); it('returns results when it gets resolved if function is asynchronous', async () => { - jest.useRealTimers(); - thread.emit('message', [ CHILD_MESSAGE_INITIALIZE, true, // Not really used here, but for flow type purity. diff --git a/packages/test-utils/src/config.ts b/packages/test-utils/src/config.ts index f86bbd3f0c65..448547d46749 100644 --- a/packages/test-utils/src/config.ts +++ b/packages/test-utils/src/config.ts @@ -78,6 +78,7 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = { displayName: undefined, errorOnDeprecated: false, extensionsToTreatAsEsm: [], + fakeTimers: {enableGlobally: false}, filter: undefined, forceCoverageMatch: [], globalSetup: undefined, @@ -116,7 +117,6 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = { testPathIgnorePatterns: [], testRegex: ['\\.test\\.js$'], testRunner: 'jest-circus/runner', - timers: 'real', transform: [], transformIgnorePatterns: [], unmockedModulePathPatterns: undefined, diff --git a/yarn.lock b/yarn.lock index 1c1b0414cf1f..ad5fc5a79327 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2651,10 +2651,11 @@ __metadata: version: 0.0.0-use.local resolution: "@jest/fake-timers@workspace:packages/jest-fake-timers" dependencies: + "@jest/test-utils": ^28.0.0-alpha.7 "@jest/types": ^28.0.0-alpha.7 "@sinonjs/fake-timers": ^9.1.1 "@types/node": "*" - "@types/sinonjs__fake-timers": ^8.1.1 + "@types/sinonjs__fake-timers": ^8.1.2 jest-message-util: ^28.0.0-alpha.7 jest-mock: ^28.0.0-alpha.7 jest-util: ^28.0.0-alpha.7 @@ -5424,10 +5425,10 @@ __metadata: languageName: node linkType: hard -"@types/sinonjs__fake-timers@npm:^8.1.1": - version: 8.1.1 - resolution: "@types/sinonjs__fake-timers@npm:8.1.1" - checksum: ca09d54d47091d87020824a73f026300fa06b17cd9f2f9b9387f28b549364b141ef194ee28db762f6588de71d8febcd17f753163cb7ea116b8387c18e80ebd5c +"@types/sinonjs__fake-timers@npm:^8.1.2": + version: 8.1.2 + resolution: "@types/sinonjs__fake-timers@npm:8.1.2" + checksum: bbc73a5ab6c0ec974929392f3d6e1e8db4ebad97ec506d785301e1c3d8a4f98a35b1aa95b97035daef02886fd8efd7788a2fa3ced2ec7105988bfd8dce61eedd languageName: node linkType: hard