From bcaa1463abf3f5488f30d0ce602c5911cca7b999 Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Tue, 26 Feb 2019 00:39:20 +0100 Subject: [PATCH 1/3] Fix asymmetric equal for Number (#7948) * Fix asymmetric equal for Number * Update CHANGELOG * Handle the case of a being a new Number * Use Object.is for Number equality * Add unit tests related to issues/7941 * Add extra units for equality * Remove unnecessary comment in eq --- CHANGELOG.md | 1 + .../__snapshots__/matchers.test.js.snap | 49 +++++++++++++++++++ .../expect/src/__tests__/matchers.test.js | 11 +++++ packages/expect/src/jasmineUtils.ts | 4 +- 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ff03985fa81..af04a394f8f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - `[jest-cli]` Refactor `-o` and `--coverage` combined ([#7611](https://github.com/facebook/jest/pull/7611)) - `[expect]` Fix custom async matcher stack trace ([#7652](https://github.com/facebook/jest/pull/7652)) - `[expect]` Fix `toStrictEqual` not considering arrays with objects having undefined values correctly ([#7938](https://github.com/facebook/jest/pull/7938)) +- `[expect]` Fix non-symmetric equal for Number ([#7948](https://github.com/facebook/jest/pull/7948)) - `[jest-changed-files]` Improve default file selection for Mercurial repos ([#7880](https://github.com/facebook/jest/pull/7880)) - `[jest-validate]` Fix validating async functions ([#7894](https://github.com/facebook/jest/issues/7894)) - `[jest-circus]` Fix bug with test.only ([#7888](https://github.com/facebook/jest/pull/7888)) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 8e07feaf3198..d576cdbad479 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -1818,6 +1818,13 @@ Expected: \\"abc\\" Received: \\"abc\\"" `; +exports[`.toEqual() {pass: false} expect("abc").not.toEqual({"0": "a", "1": "b", "2": "c"}) 1`] = ` +"expect(received).not.toEqual(expected) + +Expected: {\\"0\\": \\"a\\", \\"1\\": \\"b\\", \\"2\\": \\"c\\"} +Received: \\"abc\\"" +`; + exports[`.toEqual() {pass: false} expect("abcd").not.toEqual(StringContaining "bc") 1`] = ` "expect(received).not.toEqual(expected) @@ -1931,6 +1938,13 @@ Expected: Any Received: [Function anonymous]" `; +exports[`.toEqual() {pass: false} expect({"0": "a", "1": "b", "2": "c"}).not.toEqual("abc") 1`] = ` +"expect(received).not.toEqual(expected) + +Expected: \\"abc\\" +Received: {\\"0\\": \\"a\\", \\"1\\": \\"b\\", \\"2\\": \\"c\\"}" +`; + exports[`.toEqual() {pass: false} expect({"a": 1, "b": [Function b], "c": true}).not.toEqual({"a": 1, "b": Any, "c": Anything}) 1`] = ` "expect(received).not.toEqual(expected) @@ -2006,6 +2020,20 @@ Expected: {} Received: {}" `; +exports[`.toEqual() {pass: false} expect({}).not.toEqual(0) 1`] = ` +"expect(received).not.toEqual(expected) + +Expected: 0 +Received: {}" +`; + +exports[`.toEqual() {pass: false} expect(0).not.toEqual({}) 1`] = ` +"expect(received).not.toEqual(expected) + +Expected: {} +Received: 0" +`; + exports[`.toEqual() {pass: false} expect(0).toEqual(-0) 1`] = ` "expect(received).toEqual(expected) @@ -2013,6 +2041,13 @@ Expected: -0 Received: 0" `; +exports[`.toEqual() {pass: false} expect(0).toEqual(5e-324) 1`] = ` +"expect(received).toEqual(expected) + +Expected: 5e-324 +Received: 0" +`; + exports[`.toEqual() {pass: false} expect(1).not.toEqual(1) 1`] = ` "expect(received).not.toEqual(expected) @@ -2034,6 +2069,13 @@ Expected: ArrayContaining [1, 2] Received: 1" `; +exports[`.toEqual() {pass: false} expect(5e-324).toEqual(0) 1`] = ` +"expect(received).toEqual(expected) + +Expected: 0 +Received: 5e-324" +`; + exports[`.toEqual() {pass: false} expect(Immutable.List [1, 2]).not.toEqual(Immutable.List [1, 2]) 1`] = ` "expect(received).not.toEqual(expected) @@ -2394,6 +2436,13 @@ Expected: Map {2 => [\\"two\\"], 1 => [\\"one\\"]} Received: Map {1 => [\\"one\\"], 2 => [\\"two\\"]}" `; +exports[`.toEqual() {pass: false} expect(NaN).not.toEqual(NaN) 1`] = ` +"expect(received).not.toEqual(expected) + +Expected: NaN +Received: NaN" +`; + exports[`.toEqual() {pass: false} expect(Set {[1], [2], [3], [3]}).not.toEqual(Set {[3], [3], [2], [1]}) 1`] = ` "expect(received).not.toEqual(expected) diff --git a/packages/expect/src/__tests__/matchers.test.js b/packages/expect/src/__tests__/matchers.test.js index 89435ff47c1d..4e2cf535b6b3 100644 --- a/packages/expect/src/__tests__/matchers.test.js +++ b/packages/expect/src/__tests__/matchers.test.js @@ -344,6 +344,8 @@ describe('.toEqual()', () => { [true, false], [1, 2], [0, -0], + [0, Number.MIN_VALUE], // issues/7941 + [Number.MIN_VALUE, 0], [{a: 5}, {b: 6}], ['banana', 'apple'], [null, undefined], @@ -426,7 +428,16 @@ describe('.toEqual()', () => { [ [true, true], [1, 1], + [NaN, NaN], + // eslint-disable-next-line no-new-wrappers + [0, new Number(0)], + // eslint-disable-next-line no-new-wrappers + [new Number(0), 0], ['abc', 'abc'], + // eslint-disable-next-line no-new-wrappers + [new String('abc'), 'abc'], + // eslint-disable-next-line no-new-wrappers + ['abc', new String('abc')], [[1], [1]], [[1, 2], [1, 2]], [Immutable.List([1]), Immutable.List([1])], diff --git a/packages/expect/src/jasmineUtils.ts b/packages/expect/src/jasmineUtils.ts index f9945dbf64df..11e368d11001 100644 --- a/packages/expect/src/jasmineUtils.ts +++ b/packages/expect/src/jasmineUtils.ts @@ -106,9 +106,7 @@ function eq( // $FlowFixMe – Flow sees `a` as a number return a == String(b); case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : a === 0 ? 1 / a == 1 / b : a == +b; + return Object.is(Number(a), Number(b)); case '[object Date]': case '[object Boolean]': // Coerce dates and booleans to numeric primitive values. Dates are compared by their From 419661f57ea8e3af26a788bb3db92127c854d13b Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 26 Feb 2019 09:38:54 +0100 Subject: [PATCH 2/3] chore: extract FakeTimers into a separate package (#7987) --- CHANGELOG.md | 1 + packages/jest-environment-jsdom/package.json | 1 + packages/jest-environment-jsdom/src/index.js | 3 +- packages/jest-environment-node/package.json | 1 + packages/jest-environment-node/src/index.js | 3 +- packages/jest-environment/package.json | 1 + packages/jest-environment/src/index.ts | 29 +++++++------------ packages/jest-environment/tsconfig.json | 1 + packages/jest-fake-timers/.npmignore | 3 ++ packages/jest-fake-timers/package.json | 22 ++++++++++++++ .../jestFakeTimers.test.ts.snap} | 0 .../src/__tests__/jestFakeTimers.test.ts} | 6 ++-- packages/jest-fake-timers/src/index.ts | 8 +++++ .../src/jestFakeTimers.ts} | 22 +++++++------- packages/jest-fake-timers/tsconfig.json | 11 +++++++ packages/jest-util/package.json | 3 +- packages/jest-util/src/index.ts | 3 +- packages/jest-util/tsconfig.json | 5 ++-- 18 files changed, 83 insertions(+), 40 deletions(-) create mode 100644 packages/jest-fake-timers/.npmignore create mode 100644 packages/jest-fake-timers/package.json rename packages/{jest-util/src/__tests__/__snapshots__/fakeTimers.test.ts.snap => jest-fake-timers/src/__tests__/__snapshots__/jestFakeTimers.test.ts.snap} (100%) rename packages/{jest-util/src/__tests__/fakeTimers.test.ts => jest-fake-timers/src/__tests__/jestFakeTimers.test.ts} (99%) create mode 100644 packages/jest-fake-timers/src/index.ts rename packages/{jest-util/src/FakeTimers.ts => jest-fake-timers/src/jestFakeTimers.ts} (97%) create mode 100644 packages/jest-fake-timers/tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index af04a394f8f3..c28550f79bee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ - `[jest-phabricator]`: Migrate to TypeScript ([#7965](https://github.com/facebook/jest/pull/7965)) - `[jest-runner]`: Migrate to TypeScript ([#7968](https://github.com/facebook/jest/pull/7968)) - `[jest-runtime]`: Migrate to TypeScript ([#7964](https://github.com/facebook/jest/pull/7964)) +- `[@jest/fake-timers]`: Extract FakeTimers class from `jest-util` into a new separate package ([#7987](https://github.com/facebook/jest/pull/7987)) ### Performance diff --git a/packages/jest-environment-jsdom/package.json b/packages/jest-environment-jsdom/package.json index 0fb34d1b04f9..65799a5f7909 100644 --- a/packages/jest-environment-jsdom/package.json +++ b/packages/jest-environment-jsdom/package.json @@ -9,6 +9,7 @@ "license": "MIT", "main": "build/index.js", "dependencies": { + "@jest/fake-timers": "^24.1.0", "jest-mock": "^24.0.0", "jest-util": "^24.0.0", "jsdom": "^11.5.1" diff --git a/packages/jest-environment-jsdom/src/index.js b/packages/jest-environment-jsdom/src/index.js index 52eed2ff069c..56f417ba8188 100644 --- a/packages/jest-environment-jsdom/src/index.js +++ b/packages/jest-environment-jsdom/src/index.js @@ -12,7 +12,8 @@ import type {EnvironmentContext} from 'types/Environment'; import type {Global} from 'types/Global'; import type {ModuleMocker} from 'jest-mock'; -import {FakeTimers, installCommonGlobals} from 'jest-util'; +import {JestFakeTimers as FakeTimers} from '@jest/fake-timers'; +import {installCommonGlobals} from 'jest-util'; import mock from 'jest-mock'; import {JSDOM, VirtualConsole} from 'jsdom'; diff --git a/packages/jest-environment-node/package.json b/packages/jest-environment-node/package.json index 0914ca74f5e8..374695a24a69 100644 --- a/packages/jest-environment-node/package.json +++ b/packages/jest-environment-node/package.json @@ -9,6 +9,7 @@ "license": "MIT", "main": "build/index.js", "dependencies": { + "@jest/fake-timers": "^24.1.0", "jest-mock": "^24.0.0", "jest-util": "^24.0.0" }, diff --git a/packages/jest-environment-node/src/index.js b/packages/jest-environment-node/src/index.js index f09b3f7c30a1..1ba6d72de0af 100644 --- a/packages/jest-environment-node/src/index.js +++ b/packages/jest-environment-node/src/index.js @@ -13,7 +13,8 @@ import type {Global} from 'types/Global'; import type {ModuleMocker} from 'jest-mock'; import vm from 'vm'; -import {FakeTimers, installCommonGlobals} from 'jest-util'; +import {JestFakeTimers as FakeTimers} from '@jest/fake-timers'; +import {installCommonGlobals} from 'jest-util'; import mock from 'jest-mock'; type Timer = {| diff --git a/packages/jest-environment/package.json b/packages/jest-environment/package.json index d1888425032d..d9595ec1d00b 100644 --- a/packages/jest-environment/package.json +++ b/packages/jest-environment/package.json @@ -10,6 +10,7 @@ "main": "build/index.js", "types": "build/index.d.ts", "dependencies": { + "@jest/fake-timers": "^24.1.0", "@jest/transform": "^24.1.0", "@jest/types": "^24.1.0", "@types/node": "*", diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index 8f9d1e08502e..d8a6aed05f4e 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -7,8 +7,12 @@ import {Script} from 'vm'; import {Config, Global} from '@jest/types'; -import moduleMocker from 'jest-mock'; +import jestMock, {ModuleMocker} from 'jest-mock'; import {ScriptTransformer} from '@jest/transform'; +import {JestFakeTimers as FakeTimers} from '@jest/fake-timers'; + +type JestMockFn = typeof jestMock.fn; +type JestMockSpyOn = typeof jestMock.spyOn; export type EnvironmentContext = { console?: Console; @@ -27,21 +31,10 @@ export interface JestEnvironment { script: Script, ): {[ScriptTransformer.EVAL_RESULT_VARIABLE]: ModuleWrapper} | null; global: Global.Global; - // TODO: When `jest-util` is ESM, this can just be `fakeTimers: import('jest-util').FakeTimers` - fakeTimers: { - clearAllTimers(): void; - runAllImmediates(): void; - runAllTicks(): void; - runAllTimers(): void; - advanceTimersByTime(msToRun: number): void; - runOnlyPendingTimers(): void; - runWithRealTimers(callback: () => void): void; - getTimerCount(): number; - useFakeTimers(): void; - useRealTimers(): void; - }; + // TODO: This is nullable, and TS doesn't understand we deal with it in `jest-runtime`. Should be fixed + fakeTimers: FakeTimers; testFilePath: Config.Path; - moduleMocker: typeof moduleMocker; + moduleMocker: ModuleMocker; setup(): Promise; teardown(): Promise; } @@ -112,7 +105,7 @@ export interface Jest { /** * Creates a mock function. Optionally takes a mock implementation. */ - fn: typeof moduleMocker.fn; + fn: JestMockFn; /** * Given the name of a module, use the automatic mocking system to generate a * mocked version of the module for you. @@ -124,7 +117,7 @@ export interface Jest { /** * Determines if the given function is a mocked function. */ - isMockFunction(fn: Function): fn is ReturnType; + isMockFunction(fn: Function): fn is ReturnType; /** * Mocks a module with an auto-mocked version when it is being required. */ @@ -235,7 +228,7 @@ export interface Jest { * Note: By default, jest.spyOn also calls the spied method. This is * different behavior from most other test libraries. */ - spyOn: typeof moduleMocker.spyOn; + spyOn: JestMockSpyOn; /** * Indicates that the module system should never return a mocked version of * the specified module from require() (e.g. that it should always return the diff --git a/packages/jest-environment/tsconfig.json b/packages/jest-environment/tsconfig.json index 8824863bd93b..cfce4b39485b 100644 --- a/packages/jest-environment/tsconfig.json +++ b/packages/jest-environment/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "build" }, "references": [ + {"path": "../jest-fake-timers"}, {"path": "../jest-transform"}, {"path": "../jest-types"}, {"path": "../jest-util"} diff --git a/packages/jest-fake-timers/.npmignore b/packages/jest-fake-timers/.npmignore new file mode 100644 index 000000000000..85e48fe7b0a4 --- /dev/null +++ b/packages/jest-fake-timers/.npmignore @@ -0,0 +1,3 @@ +**/__mocks__/** +**/__tests__/** +src diff --git a/packages/jest-fake-timers/package.json b/packages/jest-fake-timers/package.json new file mode 100644 index 000000000000..988be66bb72f --- /dev/null +++ b/packages/jest-fake-timers/package.json @@ -0,0 +1,22 @@ +{ + "name": "@jest/fake-timers", + "version": "24.1.0", + "repository": { + "type": "git", + "url": "https://github.com/facebook/jest.git", + "directory": "packages/jest-fake-timers" + }, + "license": "MIT", + "main": "build/index.js", + "types": "build/index.d.ts", + "dependencies": { + "@jest/types": "^24.1.0", + "@types/node": "*", + "jest-message-util": "^24.0.0", + "jest-mock": "^24.0.0" + }, + "engines": { + "node": ">= 6" + }, + "gitHead": "b16789230fd45056a7f2fa199bae06c7a1780deb" +} diff --git a/packages/jest-util/src/__tests__/__snapshots__/fakeTimers.test.ts.snap b/packages/jest-fake-timers/src/__tests__/__snapshots__/jestFakeTimers.test.ts.snap similarity index 100% rename from packages/jest-util/src/__tests__/__snapshots__/fakeTimers.test.ts.snap rename to packages/jest-fake-timers/src/__tests__/__snapshots__/jestFakeTimers.test.ts.snap diff --git a/packages/jest-util/src/__tests__/fakeTimers.test.ts b/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts similarity index 99% rename from packages/jest-util/src/__tests__/fakeTimers.test.ts rename to packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts index 7d53b0c91e51..ac0d7ad149d1 100644 --- a/packages/jest-util/src/__tests__/fakeTimers.test.ts +++ b/packages/jest-fake-timers/src/__tests__/jestFakeTimers.test.ts @@ -7,9 +7,7 @@ import vm from 'vm'; import mock from 'jest-mock'; -import FakeTimers from '../FakeTimers'; -// TODO: import this type directly from jest-mock once TS migration is done -type ModuleMocker = typeof mock; +import FakeTimers from '../jestFakeTimers'; const timerConfig = { idToRef: (id: number) => id, @@ -22,7 +20,7 @@ const config = { }; describe('FakeTimers', () => { - let moduleMocker: ModuleMocker; + let moduleMocker: mock.ModuleMocker; beforeEach(() => { const global = vm.runInNewContext('this'); diff --git a/packages/jest-fake-timers/src/index.ts b/packages/jest-fake-timers/src/index.ts new file mode 100644 index 000000000000..fe0d39d5b62a --- /dev/null +++ b/packages/jest-fake-timers/src/index.ts @@ -0,0 +1,8 @@ +/** + * 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. + */ + +export {default as JestFakeTimers} from './jestFakeTimers'; diff --git a/packages/jest-util/src/FakeTimers.ts b/packages/jest-fake-timers/src/jestFakeTimers.ts similarity index 97% rename from packages/jest-util/src/FakeTimers.ts rename to packages/jest-fake-timers/src/jestFakeTimers.ts index aea4916981b5..9dca4a0ac1d2 100644 --- a/packages/jest-util/src/FakeTimers.ts +++ b/packages/jest-fake-timers/src/jestFakeTimers.ts @@ -5,18 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import mock from 'jest-mock'; +import {ModuleMocker} from 'jest-mock'; import {formatStackTrace, StackTraceConfig} from 'jest-message-util'; -import setGlobal from './setGlobal'; -type ModuleMocker = typeof mock; - -/** - * We don't know the type of arguments for a callback ahead of time which is why - * we are disabling the flowtype/no-weak-types rule here. - */ - -type Callback = (...args: any) => void; +type Callback = (...args: Array) => void; type TimerID = string; @@ -50,6 +42,16 @@ type TimerConfig = { const MS_IN_A_YEAR = 31536000000; +// TODO: Copied from `jest-util` to avoid cyclic dependency. Import from `jest-util` in the next major +const setGlobal = ( + globalToMutate: NodeJS.Global | Window, + key: string, + value: unknown, +) => { + // @ts-ignore: no index + globalToMutate[key] = value; +}; + export default class FakeTimers { private _cancelledImmediates!: {[key: string]: boolean}; private _cancelledTicks!: {[key: string]: boolean}; diff --git a/packages/jest-fake-timers/tsconfig.json b/packages/jest-fake-timers/tsconfig.json new file mode 100644 index 000000000000..335b1e9c373a --- /dev/null +++ b/packages/jest-fake-timers/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + "references": [ + {"path": "../jest-message-util"}, + {"path": "../jest-mock"} + ] +} diff --git a/packages/jest-util/package.json b/packages/jest-util/package.json index 13e9e9f6c706..4fceefa7a5da 100644 --- a/packages/jest-util/package.json +++ b/packages/jest-util/package.json @@ -10,14 +10,13 @@ "main": "build/index.js", "types": "build/index.d.ts", "dependencies": { + "@jest/fake-timers": "^24.1.0", "@jest/types": "^24.1.0", "@types/node": "*", "callsites": "^3.0.0", "chalk": "^2.0.1", "graceful-fs": "^4.1.15", "is-ci": "^2.0.0", - "jest-message-util": "^24.0.0", - "jest-mock": "^24.0.0", "mkdirp": "^0.5.1", "readable-stream": "^3.1.1", "slash": "^2.0.0", diff --git a/packages/jest-util/src/index.ts b/packages/jest-util/src/index.ts index 66c38c2b63e0..a7291e0ae7e1 100644 --- a/packages/jest-util/src/index.ts +++ b/packages/jest-util/src/index.ts @@ -5,12 +5,13 @@ * LICENSE file in the root directory of this source tree. */ +// TODO: Remove this export in the next major +import {JestFakeTimers as FakeTimers} from '@jest/fake-timers'; import BufferedConsole from './BufferedConsole'; import clearLine from './clearLine'; import CustomConsole from './CustomConsole'; import createDirectory from './createDirectory'; import ErrorWithStack from './ErrorWithStack'; -import FakeTimers from './FakeTimers'; import formatTestResults from './formatTestResults'; import getFailedSnapshotTests from './getFailedSnapshotTests'; import getConsoleOutput from './getConsoleOutput'; diff --git a/packages/jest-util/tsconfig.json b/packages/jest-util/tsconfig.json index c8a0f5ac5aa8..876baa6cf5c8 100644 --- a/packages/jest-util/tsconfig.json +++ b/packages/jest-util/tsconfig.json @@ -5,8 +5,7 @@ "outDir": "build" }, "references": [ - {"path": "../jest-types"}, - {"path": "../jest-message-util"}, - {"path": "../jest-mock"} + {"path": "../jest-fake-timers"}, + {"path": "../jest-types"} ] } From 16fe18d62c34713a6758c2fb216c31834115807a Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 26 Feb 2019 11:05:17 +0100 Subject: [PATCH 3/3] chore: cleanup JestEnvironment types (#7988) --- CHANGELOG.md | 2 +- .../src/legacy-code-todo-rewrite/jestAdapter.ts | 6 ++++-- packages/jest-environment/src/index.ts | 16 ++++++---------- packages/jest-runner/src/runTest.ts | 2 +- packages/jest-runtime/src/cli/index.ts | 2 +- packages/jest-runtime/src/index.ts | 16 +++++++++------- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c28550f79bee..e6e9e2d3890b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,7 @@ - `[jest-circus]`: Migrate to TypeScript ([#7916](https://github.com/facebook/jest/pull/7916)) - `[jest-phabricator]`: Migrate to TypeScript ([#7965](https://github.com/facebook/jest/pull/7965)) - `[jest-runner]`: Migrate to TypeScript ([#7968](https://github.com/facebook/jest/pull/7968)) -- `[jest-runtime]`: Migrate to TypeScript ([#7964](https://github.com/facebook/jest/pull/7964)) +- `[jest-runtime]`: Migrate to TypeScript ([#7964](https://github.com/facebook/jest/pull/7964), [#7988](https://github.com/facebook/jest/pull/7988)) - `[@jest/fake-timers]`: Extract FakeTimers class from `jest-util` into a new separate package ([#7987](https://github.com/facebook/jest/pull/7987)) ### Performance 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 7064ad335553..7ad289942726 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -47,7 +47,8 @@ const jestAdapter = async ( }); if (config.timers === 'fake') { - environment.fakeTimers.useFakeTimers(); + // during setup, this cannot be null (and it's fine to explode if it is) + environment.fakeTimers!.useFakeTimers(); } globals.beforeEach(() => { @@ -63,7 +64,8 @@ const jestAdapter = async ( runtime.resetAllMocks(); if (config.timers === 'fake') { - environment.fakeTimers.useFakeTimers(); + // during setup, this cannot be null (and it's fine to explode if it is) + environment.fakeTimers!.useFakeTimers(); } } diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index d8a6aed05f4e..a29270083abb 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -22,19 +22,15 @@ export type EnvironmentContext = { // TODO: type this better: https://nodejs.org/api/modules.html#modules_the_module_wrapper type ModuleWrapper = (...args: Array) => unknown; -export interface JestEnvironment { - new ( - config: Config.ProjectConfig, - context?: EnvironmentContext, - ): JestEnvironment; +export declare class JestEnvironment { + constructor(config: Config.ProjectConfig); + constructor(config: Config.ProjectConfig, context: EnvironmentContext); + global: Global.Global; + fakeTimers: FakeTimers | null; + moduleMocker: ModuleMocker | null; runScript( script: Script, ): {[ScriptTransformer.EVAL_RESULT_VARIABLE]: ModuleWrapper} | null; - global: Global.Global; - // TODO: This is nullable, and TS doesn't understand we deal with it in `jest-runtime`. Should be fixed - fakeTimers: FakeTimers; - testFilePath: Config.Path; - moduleMocker: ModuleMocker; setup(): Promise; teardown(): Promise; } diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 94c759a5188f..22e7cd57465b 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -96,7 +96,7 @@ async function runTestInternal( }); } - const TestEnvironment: JestEnvironment = require(testEnvironment); + const TestEnvironment: typeof JestEnvironment = require(testEnvironment); const testFramework: TestFramework = process.env.JEST_CIRCUS === '1' ? require('jest-circus/runner') // eslint-disable-line import/no-extraneous-dependencies diff --git a/packages/jest-runtime/src/cli/index.ts b/packages/jest-runtime/src/cli/index.ts index cb4527e312ec..5a6284388da5 100644 --- a/packages/jest-runtime/src/cli/index.ts +++ b/packages/jest-runtime/src/cli/index.ts @@ -80,7 +80,7 @@ export function run(cliArgv?: Config.Argv, cliInfo?: Array) { watchman: globalConfig.watchman, }) as Promise) .then(hasteMap => { - const Environment: JestEnvironment = require(config.testEnvironment); + const Environment: typeof JestEnvironment = require(config.testEnvironment); const environment = new Environment(config); setGlobal( environment.global, diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 6c8849a792ee..694738227f3a 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -125,7 +125,8 @@ class Runtime { this._isCurrentlyExecutingManualMock = null; this._mockFactories = Object.create(null); this._mockRegistry = Object.create(null); - this._moduleMocker = this._environment.moduleMocker; + // during setup, this cannot be null (and it's fine to explode if it is) + this._moduleMocker = this._environment.moduleMocker!; this._isolatedModuleRegistry = null; this._isolatedMockRegistry = null; this._moduleRegistry = Object.create(null); @@ -170,7 +171,7 @@ class Runtime { } } - // TODO: Can this be `static shouldInstrument = shouldInstrument;`? + // TODO: Make this `static shouldInstrument = shouldInstrument;` after https://github.com/facebook/jest/issues/7846 static shouldInstrument( filename: Config.Path, options: ShouldInstrumentOptions, @@ -934,11 +935,11 @@ class Runtime { return jestObject; }; const useFakeTimers = () => { - this._environment.fakeTimers.useFakeTimers(); + _getFakeTimers().useFakeTimers(); return jestObject; }; const useRealTimers = () => { - this._environment.fakeTimers.useRealTimers(); + _getFakeTimers().useRealTimers(); return jestObject; }; const resetModules = () => { @@ -968,7 +969,7 @@ class Runtime { return jestObject; }; - const _getFakeTimers = () => { + const _getFakeTimers = (): NonNullable => { if (!this._environment.fakeTimers) { this._logFormattedReferenceError( 'You are trying to access a property or method of the Jest environment after it has been torn down.', @@ -976,7 +977,8 @@ class Runtime { process.exitCode = 1; } - return this._environment.fakeTimers; + // We've logged a user message above, so it doesn't matter if we return `null` here + return this._environment.fakeTimers!; }; const jestObject: Jest = { @@ -1024,7 +1026,7 @@ class Runtime { return jestObject; } - _logFormattedReferenceError(errorMessage: string) { + private _logFormattedReferenceError(errorMessage: string) { const originalStack = new ReferenceError(errorMessage) .stack!.split('\n') // Remove this file from the stack (jest-message-utils will keep one line)