diff --git a/CHANGELOG.md b/CHANGELOG.md index 786ec76af00a..1a9662f3aec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Fixes -- `[jest-mock]` Fix typings for `mockResolvedValue`, `mockResolvedValueOnce`, `mockRejectedValue` and `mockRejectedValueOnce` +- `[jest-circus]` Setup globals before emitting `setup`, and include Jest globals in the `setup` payload ([#10598](https://github.com/facebook/jest/pull/10598)) +- `[jest-mock]` Fix typings for `mockResolvedValue`, `mockResolvedValueOnce`, `mockRejectedValue` and `mockRejectedValueOnce` ([#10600](https://github.com/facebook/jest/pull/10600)) ### Chore & Maintenance 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 7ea8be508da0..bddb5d5606a0 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import * as path from 'path'; import type {Config} from '@jest/types'; import type {JestEnvironment} from '@jest/environment'; import type {TestResult} from '@jest/test-result'; @@ -14,8 +13,7 @@ import type {RuntimeType as Runtime} from 'jest-runtime'; import type {SnapshotStateType} from 'jest-snapshot'; import {deepCyclicCopy} from 'jest-util'; -const FRAMEWORK_INITIALIZER = path.resolve(__dirname, './jestAdapterInit.js'); -const EXPECT_INITIALIZER = path.resolve(__dirname, './jestExpect.js'); +const FRAMEWORK_INITIALIZER = require.resolve('./jestAdapterInit'); const jestAdapter = async ( globalConfig: Config.GlobalConfig, @@ -32,10 +30,6 @@ const jestAdapter = async ( FRAMEWORK_INITIALIZER, ); - const expect = runtime - .requireInternalModule(EXPECT_INITIALIZER) - .default(globalConfig); - const getPrettier = () => config.prettierPath ? require(config.prettierPath) : null; const getBabelTraverse = () => require('@babel/traverse').default; @@ -49,18 +43,10 @@ const jestAdapter = async ( localRequire: runtime.requireModule.bind(runtime), parentProcess: process, sendMessageToJest, + setGlobalsForRuntime: runtime.setGlobalsForRuntime?.bind(runtime), testPath, }); - const runtimeGlobals = {expect, ...globals}; - // TODO: `jest-circus` might be newer than `jest-runtime` - remove `?.` for Jest 27 - runtime.setGlobalsForRuntime?.(runtimeGlobals); - - // TODO: `jest-circus` might be newer than `jest-config` - remove `??` for Jest 27 - if (config.injectGlobals ?? true) { - Object.assign(environment.global, runtimeGlobals); - } - if (config.timers === 'fake' || config.timers === 'legacy') { // during setup, this cannot be null (and it's fine to explode if it is) environment.fakeTimers!.useFakeTimers(); diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 2e0f38f08d13..b8820e32fe80 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -35,9 +35,14 @@ import {getTestID} from '../utils'; import run from '../run'; import testCaseReportHandler from '../testCaseReportHandler'; import globals from '..'; +import createExpect, {Expect} from './jestExpect'; type Process = NodeJS.Process; +interface JestGlobals extends Global.TestFrameworkGlobals { + expect: Expect; +} + export const initialize = async ({ config, environment, @@ -46,8 +51,9 @@ export const initialize = async ({ globalConfig, localRequire, parentProcess, - testPath, sendMessageToJest, + setGlobalsForRuntime, + testPath, }: { config: Config.ProjectConfig; environment: JestEnvironment; @@ -58,6 +64,7 @@ export const initialize = async ({ testPath: Config.Path; parentProcess: Process; sendMessageToJest?: TestFileEvent; + setGlobalsForRuntime?: (globals: JestGlobals) => void; }): Promise<{ globals: Global.TestFrameworkGlobals; snapshotState: SnapshotStateType; @@ -120,9 +127,22 @@ export const initialize = async ({ addEventHandler(environment.handleTestEvent.bind(environment)); } + const runtimeGlobals: JestGlobals = { + ...globalsObject, + expect: createExpect(globalConfig), + }; + // TODO: `jest-circus` might be newer than `jest-runtime` - remove `?.` for Jest 27 + setGlobalsForRuntime?.(runtimeGlobals); + + // TODO: `jest-circus` might be newer than `jest-config` - remove `??` for Jest 27 + if (config.injectGlobals ?? true) { + Object.assign(environment.global, runtimeGlobals); + } + await dispatch({ name: 'setup', parentProcess, + runtimeGlobals, testNamePattern: globalConfig.testNamePattern, }); diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index 3b67860c255e..81a62f3cfe75 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -16,7 +16,9 @@ import { toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; -export default (config: Pick): typeof expect => { +export type Expect = typeof expect; + +export default (config: Pick): Expect => { expect.setState({expand: config.expand}); expect.extend({ toMatchInlineSnapshot, diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 5dec97bda397..b4c94d57c3b6 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -38,6 +38,11 @@ export interface EventHandler { export type Event = SyncEvent | AsyncEvent; +interface JestGlobals extends Global.TestFrameworkGlobals { + // we cannot type `expect` properly as it'd create circular dependencies + expect: unknown; +} + export type SyncEvent = | { asyncError: Error; @@ -77,6 +82,7 @@ export type AsyncEvent = // first action to dispatch. Good time to initialize all settings name: 'setup'; testNamePattern?: string; + runtimeGlobals: JestGlobals; parentProcess: Process; } | { diff --git a/packages/jest-util/src/globsToMatcher.ts b/packages/jest-util/src/globsToMatcher.ts index e100d42cfcbf..ad4285825efe 100644 --- a/packages/jest-util/src/globsToMatcher.ts +++ b/packages/jest-util/src/globsToMatcher.ts @@ -9,12 +9,11 @@ import micromatch = require('micromatch'); import type {Config} from '@jest/types'; import replacePathSepForGlob from './replacePathSepForGlob'; +type Matcher = (str: Config.Path) => boolean; + const globsToMatchersMap = new Map< string, - { - isMatch: (str: string) => boolean; - negated: boolean; - } + {isMatch: Matcher; negated: boolean} >(); const micromatchOptions = {dot: true}; @@ -36,13 +35,11 @@ const micromatchOptions = {dot: true}; * isMatch('pizza.js'); // true * isMatch('pizza.test.js'); // false */ -export default function globsToMatcher( - globs: Array, -): (path: Config.Path) => boolean { +export default function globsToMatcher(globs: Array): Matcher { if (globs.length === 0) { // Since there were no globs given, we can simply have a fast path here and // return with a very simple function. - return (_: Config.Path): boolean => false; + return () => false; } const matchers = globs.map(glob => { @@ -62,7 +59,7 @@ export default function globsToMatcher( return globsToMatchersMap.get(glob)!; }); - return (path: Config.Path): boolean => { + return path => { const replacedPath = replacePathSepForGlob(path); let kept = undefined; let negatives = 0;