diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dd0a9c2f752..41045c037810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - `[jest-circus, jest-cli, jest-config]` Add `waitNextEventLoopTurnForUnhandledRejectionEvents` flag to minimise performance impact of correct detection of unhandled promise rejections introduced in [#14315](https://github.com/jestjs/jest/pull/14315) ([#14681](https://github.com/jestjs/jest/pull/14681)) - `[jest-circus]` Add a `waitBeforeRetry` option to `jest.retryTimes` ([#14738](https://github.com/jestjs/jest/pull/14738)) +- `[jest-circus, jest-jasmine2]` Allow `setupFilesAfterEnv` to export an async function ([#10962](https://github.com/jestjs/jest/issues/10962)) - `[jest-config]` [**BREAKING**] Add `mts` and `cts` to default `moduleFileExtensions` config ([#14369](https://github.com/facebook/jest/pull/14369)) - `[jest-config]` [**BREAKING**] Update `testMatch` and `testRegex` default option for supporting `mjs`, `cjs`, `mts`, and `cts` ([#14584](https://github.com/jestjs/jest/pull/14584)) - `[jest-config]` Loads config file from provided path in `package.json` ([#14044](https://github.com/facebook/jest/pull/14044)) diff --git a/docs/Configuration.md b/docs/Configuration.md index 26b0ced5a8bd..907af0b9ec7a 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1665,6 +1665,12 @@ const config: Config = { export default config; ``` +:::tip + +If your setup script is a CJS module, it may export an async function. Jest will call the function and await its result. This might be useful to fetch some data asynchronously. If the file is an ESM module, simply use top-level await to achieve the same result. + +::: + ### `showSeed` \[boolean] Default: `false` diff --git a/e2e/__tests__/setupFilesAfterEnvConfig.test.ts b/e2e/__tests__/setupFilesAfterEnvConfig.test.ts index 031b98b2ce54..953f86a874c4 100644 --- a/e2e/__tests__/setupFilesAfterEnvConfig.test.ts +++ b/e2e/__tests__/setupFilesAfterEnvConfig.test.ts @@ -64,4 +64,48 @@ describe('setupFilesAfterEnv', () => { expect(result.json.testResults).toHaveLength(1); expect(result.exitCode).toBe(0); }); + + it('awaits async function returned from the setup file (jest-circus)', () => { + const pkgJson = { + jest: { + setupFilesAfterEnv: ['./setupAsyncFunction.js'], + testRunner: 'jest-circus', + }, + }; + + writeFiles(DIR, { + 'package.json': JSON.stringify(pkgJson, null, 2), + }); + + const result = runWithJson('setup-files-after-env-config', [ + 'setupAsyncFunction.test.js', + ]); + + expect(result.json.numTotalTests).toBe(1); + expect(result.json.numPassedTests).toBe(1); + expect(result.json.testResults).toHaveLength(1); + expect(result.exitCode).toBe(0); + }); + + it('awaits async function returned from the setup file (jest-jasmine2)', () => { + const pkgJson = { + jest: { + setupFilesAfterEnv: ['./setupAsyncFunction.js'], + testRunner: 'jest-jasmine2', + }, + }; + + writeFiles(DIR, { + 'package.json': JSON.stringify(pkgJson, null, 2), + }); + + const result = runWithJson('setup-files-after-env-config', [ + 'setupAsyncFunction.test.js', + ]); + + expect(result.json.numTotalTests).toBe(1); + expect(result.json.numPassedTests).toBe(1); + expect(result.json.testResults).toHaveLength(1); + expect(result.exitCode).toBe(0); + }); }); diff --git a/e2e/setup-files-after-env-config/__tests__/setupAsyncFunction.test.js b/e2e/setup-files-after-env-config/__tests__/setupAsyncFunction.test.js new file mode 100644 index 000000000000..0fa60b5f5424 --- /dev/null +++ b/e2e/setup-files-after-env-config/__tests__/setupAsyncFunction.test.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +describe('setupFilesAfterEnv', () => { + it('has waited for async function', () => { + expect(globalThis.afterEnvAsyncFunctionFinished).toBe(true); + }); +}); diff --git a/e2e/setup-files-after-env-config/setupAsyncFunction.js b/e2e/setup-files-after-env-config/setupAsyncFunction.js new file mode 100644 index 000000000000..ec17aaa05065 --- /dev/null +++ b/e2e/setup-files-after-env-config/setupAsyncFunction.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +globalThis.afterEnvAsyncFunctionFinished = false; + +module.exports = async () => { + await new Promise(resolve => + setTimeout(() => { + globalThis.afterEnvAsyncFunctionFinished = true; + resolve(); + }, 2000), + ); +}; 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 eeea251f4774..e80bbfba4809 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -81,7 +81,10 @@ const jestAdapter = async ( if (esm) { await runtime.unstable_importModule(path); } else { - runtime.requireModule(path); + const setupFile = runtime.requireModule(path); + if (typeof setupFile === 'function') { + await setupFile(); + } } } const setupAfterEnvEnd = Date.now(); diff --git a/packages/jest-jasmine2/src/index.ts b/packages/jest-jasmine2/src/index.ts index 16546e862a64..e641c0be5de5 100644 --- a/packages/jest-jasmine2/src/index.ts +++ b/packages/jest-jasmine2/src/index.ts @@ -180,7 +180,10 @@ export default async function jasmine2( if (esm) { await runtime.unstable_importModule(path); } else { - runtime.requireModule(path); + const setupFile = runtime.requireModule(path); + if (typeof setupFile === 'function') { + await setupFile(); + } } }