diff --git a/CHANGELOG.md b/CHANGELOG.md index ba07e937f8fc..c7a2686fef08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,15 +18,18 @@ - `[jest-core]` Add support for `testSequencer` written in ESM ([#11207](https://github.com/facebook/jest/pull/11207)) - `[jest-core]` Add support for `globalSetup` and `globalTeardown` written in ESM ([#11267](https://github.com/facebook/jest/pull/11267)) - `[jest-core]` Add support for `watchPlugins` written in ESM ([#11315](https://github.com/facebook/jest/pull/11315)) +- `[jest-core]` Add support for `runner` written in ESM ([#11232](https://github.com/facebook/jest/pull/11232)) - `[jest-environment-node]` Add AbortController to globals ([#11182](https://github.com/facebook/jest/pull/11182)) - `[@jest/fake-timers]` Update to `@sinonjs/fake-timers` to v7 ([#11198](https://github.com/facebook/jest/pull/11198)) - `[jest-haste-map]` Handle injected scm clocks ([#10966](https://github.com/facebook/jest/pull/10966)) - `[jest-haste-map]` Add `enableSymlinks` configuration option to follow symlinks for test files ([#9351](https://github.com/facebook/jest/pull/9351)) - `[jest-repl, jest-runner]` [**BREAKING**] Run transforms over environment ([#8751](https://github.com/facebook/jest/pull/8751)) +- `[jest-repl]` Add support for `testEnvironment` written in ESM ([#11232](https://github.com/facebook/jest/pull/11232)) - `[jest-runner]` [**BREAKING**] set exit code to 1 if test logs after teardown ([#10728](https://github.com/facebook/jest/pull/10728)) - `[jest-runner]` [**BREAKING**] Run transforms over `runnner` ([#8823](https://github.com/facebook/jest/pull/8823)) - `[jest-runner]` [**BREAKING**] Run transforms over `testRunnner` ([#8823](https://github.com/facebook/jest/pull/8823)) - `[jest-runner]` Possibility to use ESM for test environment ([11033](https://github.com/facebook/jest/pull/11033)) +- `[jest-runner]` Add support for `testRunner` written in ESM ([#11232](https://github.com/facebook/jest/pull/11232)) - `[jest-runtime]` Detect reexports from CJS as named exports in ESM ([#10988](https://github.com/facebook/jest/pull/10988)) - `[jest-runtime]` Support for async code transformations ([#11191](https://github.com/facebook/jest/pull/11191) & [#11220](https://github.com/facebook/jest/pull/11220)) - `[jest-reporters]` Add static filepath property to all reporters ([#11015](https://github.com/facebook/jest/pull/11015)) @@ -37,6 +40,10 @@ - `[jest-transform]` [**BREAKING**] Do not export `ScriptTransformer` class, instead export the async function `createScriptTransformer` ([#11163](https://github.com/facebook/jest/pull/11163)) - `[jest-transform]` Async code transformations ([#9889](https://github.com/facebook/jest/pull/9889)) - `[jest-transform]` Support transpiled transformers ([#11193](https://github.com/facebook/jest/pull/11193)) +- `[jest-transform]` [**BREAKING**] `requireAndTranspileModule` always return a `Promise`, and the third parameter type is changed to `RequireAndTranspileModuleOptions` which accept `applyInteropRequireDefault` option ([#11232](https://github.com/facebook/jest/pull/11232)) +- `[jest-transform]` [**BREAKING**] `createTranspilingRequire` return function which return a `Promise` now ([#11232](https://github.com/facebook/jest/pull/11232)) +- `[jest-util]` add requireOrImportModule for importing CJS or ESM ([#11199](https://github.com/facebook/jest/pull/11199)) +- `[jest-util]` add `applyInteropRequireDefault` option on `requireOrImportModule` ([#11232](https://github.com/facebook/jest/pull/11232)) - `[jest-watcher]` Added support for clearing the line when `` is pressed in a watch mode pattern prompt ([#11358](https://github.com/facebook/jest/pull/11358)) - `[jest-worker]` Add support for custom task queues and adds a `PriorityQueue` implementation. ([#10921](https://github.com/facebook/jest/pull/10921)) - `[jest-worker]` Add in-order scheduling policy to jest worker ([10902](https://github.com/facebook/jest/pull/10902)) diff --git a/e2e/__tests__/globalSetup.test.ts b/e2e/__tests__/globalSetup.test.ts index bb104b6a4e4d..900c28345d19 100644 --- a/e2e/__tests__/globalSetup.test.ts +++ b/e2e/__tests__/globalSetup.test.ts @@ -27,6 +27,7 @@ const customTransformDIR = path.join( const nodeModulesDIR = path.join(tmpdir(), 'jest-global-setup-node-modules'); const rejectionDir = path.join(tmpdir(), 'jest-global-setup-rejection'); const e2eDir = path.resolve(__dirname, '../global-setup'); +const esmTmpDir = path.join(tmpdir(), 'jest-global-setup-esm'); beforeAll(() => { runYarnInstall(e2eDir); @@ -39,6 +40,7 @@ beforeEach(() => { cleanup(customTransformDIR); cleanup(nodeModulesDIR); cleanup(rejectionDir); + cleanup(esmTmpDir); }); afterAll(() => { @@ -48,6 +50,7 @@ afterAll(() => { cleanup(customTransformDIR); cleanup(nodeModulesDIR); cleanup(rejectionDir); + cleanup(esmTmpDir); }); test('globalSetup is triggered once before all test suites', () => { diff --git a/e2e/__tests__/globalTeardown.test.ts b/e2e/__tests__/globalTeardown.test.ts index 5f9a9ef78813..3ac81a0e49e3 100644 --- a/e2e/__tests__/globalTeardown.test.ts +++ b/e2e/__tests__/globalTeardown.test.ts @@ -17,6 +17,7 @@ const DIR = path.join(tmpdir(), 'jest-global-teardown'); const project1DIR = path.join(tmpdir(), 'jest-global-teardown-project-1'); const project2DIR = path.join(tmpdir(), 'jest-global-teardown-project-2'); const e2eDir = path.resolve(__dirname, '../global-teardown'); +const esmTmpDir = path.join(tmpdir(), 'jest-global-teardown-esm'); beforeAll(() => { runYarnInstall(e2eDir); @@ -26,11 +27,13 @@ beforeEach(() => { cleanup(DIR); cleanup(project1DIR); cleanup(project2DIR); + cleanup(esmTmpDir); }); afterAll(() => { cleanup(DIR); cleanup(project1DIR); cleanup(project2DIR); + cleanup(esmTmpDir); }); test('globalTeardown is triggered once after all test suites', () => { diff --git a/e2e/__tests__/transform.test.ts b/e2e/__tests__/transform.test.ts index 7783be39bb2c..f596b94f4398 100644 --- a/e2e/__tests__/transform.test.ts +++ b/e2e/__tests__/transform.test.ts @@ -315,4 +315,33 @@ onNodeVersions('^12.17.0 || >=13.2.0', () => { expect(json.numPassedTests).toBe(1); }); }); + + describe('transform-esm-runner', () => { + const dir = path.resolve(__dirname, '../transform/transform-esm-runner'); + test('runs test with native ESM', () => { + const {json, stderr} = runWithJson(dir, ['--no-cache'], { + nodeOptions: '--experimental-vm-modules', + }); + + expect(stderr).toMatch(/PASS/); + expect(json.success).toBe(true); + expect(json.numPassedTests).toBe(1); + }); + }); + + describe('transform-esm-testrunner', () => { + const dir = path.resolve( + __dirname, + '../transform/transform-esm-testrunner', + ); + test('runs test with native ESM', () => { + const {json, stderr} = runWithJson(dir, ['--no-cache'], { + nodeOptions: '--experimental-vm-modules', + }); + + expect(stderr).toMatch(/PASS/); + expect(json.success).toBe(true); + expect(json.numPassedTests).toBe(1); + }); + }); }); diff --git a/e2e/test-environment-async/__tests__/custom.test.js b/e2e/test-environment-async/__tests__/custom.test.js index 0bc863baf566..91eadf76a535 100644 --- a/e2e/test-environment-async/__tests__/custom.test.js +++ b/e2e/test-environment-async/__tests__/custom.test.js @@ -6,7 +6,6 @@ * */ 'use strict'; -/* eslint-env browser*/ test('setup', () => { expect(global.setup).toBe('setup'); diff --git a/e2e/transform/transform-esm-runner/__tests__/add.test.js b/e2e/transform/transform-esm-runner/__tests__/add.test.js new file mode 100644 index 000000000000..10dca79b8672 --- /dev/null +++ b/e2e/transform/transform-esm-runner/__tests__/add.test.js @@ -0,0 +1,10 @@ +/** + * 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. + */ + +it('should add two numbers', () => { + expect(1 + 1).toBe(2); +}); diff --git a/e2e/transform/transform-esm-runner/package.json b/e2e/transform/transform-esm-runner/package.json new file mode 100644 index 000000000000..5d34c7c4091d --- /dev/null +++ b/e2e/transform/transform-esm-runner/package.json @@ -0,0 +1,7 @@ +{ + "type": "module", + "jest": { + "rootDir": "./", + "runner": "/runner.mjs" + } +} diff --git a/e2e/transform/transform-esm-runner/runner.mjs b/e2e/transform/transform-esm-runner/runner.mjs new file mode 100644 index 000000000000..fa9becc105bc --- /dev/null +++ b/e2e/transform/transform-esm-runner/runner.mjs @@ -0,0 +1,48 @@ +/** + * 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 testResult from '@jest/test-result'; + +const {createEmptyTestResult} = testResult; + +export default class BaseTestRunner { + constructor(globalConfig, context) { + this._globalConfig = globalConfig; + this._context = context || {}; + } + + async runTests(tests, watcher, onStart, onResult, onFailure) { + return tests.reduce( + (promise, test) => + promise + .then(async () => { + await onStart(test); + return { + ...createEmptyTestResult(), + numPassingTests: 1, + testFilePath: test.path, + testResults: [ + { + ancestorTitles: [], + duration: 2, + failureDetails: [], + failureMessages: [], + fullName: 'sample test', + location: null, + numPassingAsserts: 1, + status: 'passed', + title: 'sample test', + }, + ], + }; + }) + .then(result => onResult(test, result)) + .catch(err => onFailure(test, err)), + Promise.resolve(), + ); + } +} diff --git a/e2e/transform/transform-esm-testrunner/__tests__/add.test.js b/e2e/transform/transform-esm-testrunner/__tests__/add.test.js new file mode 100644 index 000000000000..10dca79b8672 --- /dev/null +++ b/e2e/transform/transform-esm-testrunner/__tests__/add.test.js @@ -0,0 +1,10 @@ +/** + * 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. + */ + +it('should add two numbers', () => { + expect(1 + 1).toBe(2); +}); diff --git a/e2e/transform/transform-esm-testrunner/package.json b/e2e/transform/transform-esm-testrunner/package.json new file mode 100644 index 000000000000..813b6f4b1533 --- /dev/null +++ b/e2e/transform/transform-esm-testrunner/package.json @@ -0,0 +1,7 @@ +{ + "type": "module", + "jest": { + "rootDir": "./", + "testRunner": "/test-runner.mjs" + } +} diff --git a/e2e/transform/transform-esm-testrunner/test-runner.mjs b/e2e/transform/transform-esm-testrunner/test-runner.mjs new file mode 100644 index 000000000000..fc04d3efc7e6 --- /dev/null +++ b/e2e/transform/transform-esm-testrunner/test-runner.mjs @@ -0,0 +1,35 @@ +/** + * 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 testResult from '@jest/test-result'; + +const {createEmptyTestResult} = testResult; + +export default async function testRunner( + globalConfig, + config, + environment, + runtime, + testPath, +) { + return { + ...createEmptyTestResult(), + numPassingTests: 1, + testFilePath: testPath, + testResults: [ + { + ancestorTitles: [], + duration: 2, + failureMessages: [], + fullName: 'sample test', + location: null, + numPassingAsserts: 1, + status: 'passed', + title: 'sample test', + }, + ], + }; +} diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index a813fcb026a8..7da4517b285e 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -203,9 +203,9 @@ export default class TestScheduler { const {config} = context; if (!testRunners[config.runner]) { const transformer = await createScriptTransformer(config); - const Runner: typeof TestRunner = interopRequireDefault( - transformer.requireAndTranspileModule(config.runner), - ).default; + const Runner: typeof TestRunner = await transformer.requireAndTranspileModule( + config.runner, + ); const runner = new Runner(this._globalConfig, { changedFiles: this._context?.changedFiles, sourcesRelatedToTestsInChangedFiles: this._context diff --git a/packages/jest-core/src/runGlobalHook.ts b/packages/jest-core/src/runGlobalHook.ts index 02aac73f0c10..1a0e0a463d3b 100644 --- a/packages/jest-core/src/runGlobalHook.ts +++ b/packages/jest-core/src/runGlobalHook.ts @@ -5,14 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {pathToFileURL} from 'url'; import * as util from 'util'; import pEachSeries = require('p-each-series'); import {createScriptTransformer} from '@jest/transform'; import type {Config} from '@jest/types'; import type {Test} from 'jest-runner'; -import {interopRequireDefault} from 'jest-util'; -import {format as prettyFormat} from 'pretty-format'; +import prettyFormat from 'pretty-format'; export default async ({ allTests, @@ -49,53 +47,31 @@ export default async ({ const transformer = await createScriptTransformer(projectConfig); try { - await transformer.requireAndTranspileModule(modulePath, async m => { - const globalModule = interopRequireDefault(m).default; - - if (typeof globalModule !== 'function') { - throw new TypeError( - `${moduleName} file must export a function at ${modulePath}`, - ); - } - - await globalModule(globalConfig); - }); + await transformer.requireAndTranspileModule( + modulePath, + async globalModule => { + if (typeof globalModule !== 'function') { + throw new TypeError( + `${moduleName} file must export a function at ${modulePath}`, + ); + } + + await globalModule(globalConfig); + }, + ); } catch (error) { - if (error && error.code === 'ERR_REQUIRE_ESM') { - const configUrl = pathToFileURL(modulePath); - - // node `import()` supports URL, but TypeScript doesn't know that - const importedConfig = await import(configUrl.href); - - if (!importedConfig.default) { - throw new Error( - `Jest: Failed to load ESM transformer at ${modulePath} - did you use a default export?`, - ); - } - - const globalModule = importedConfig.default; + if (util.types.isNativeError(error)) { + error.message = `Jest: Got error running ${moduleName} - ${modulePath}, reason: ${error.message}`; - if (typeof globalModule !== 'function') { - throw new TypeError( - `${moduleName} file must export a function at ${modulePath}`, - ); - } - - await globalModule(globalConfig); - } else { - if (util.types.isNativeError(error)) { - error.message = `Jest: Got error running ${moduleName} - ${modulePath}, reason: ${error.message}`; - - throw error; - } - - throw new Error( - `Jest: Got error running ${moduleName} - ${modulePath}, reason: ${prettyFormat( - error, - {maxDepth: 3}, - )}`, - ); + throw error; } + + throw new Error( + `Jest: Got error running ${moduleName} - ${modulePath}, reason: ${prettyFormat( + error, + {maxDepth: 3}, + )}`, + ); } }); } diff --git a/packages/jest-repl/src/cli/runtime-cli.ts b/packages/jest-repl/src/cli/runtime-cli.ts index 3d8a8c871676..c9941eb065f6 100644 --- a/packages/jest-repl/src/cli/runtime-cli.ts +++ b/packages/jest-repl/src/cli/runtime-cli.ts @@ -15,7 +15,7 @@ import {createScriptTransformer} from '@jest/transform'; import type {Config} from '@jest/types'; import {deprecationEntries, readConfig} from 'jest-config'; import Runtime from 'jest-runtime'; -import {interopRequireDefault, setGlobal, tryRealpath} from 'jest-util'; +import {setGlobal, tryRealpath} from 'jest-util'; import {validateCLIOptions} from 'jest-validate'; import * as args from './args'; import {VERSION} from './version'; @@ -75,9 +75,10 @@ export async function run( }); const transformer = await createScriptTransformer(config); - const Environment: typeof JestEnvironment = interopRequireDefault( - transformer.requireAndTranspileModule(config.testEnvironment), - ).default; + const Environment: typeof JestEnvironment = await transformer.requireAndTranspileModule( + config.testEnvironment, + ); + const environment = new Environment(config); setGlobal( environment.global, diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 396bd6c415f7..2f1b89d7cf3a 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -6,7 +6,6 @@ * */ -import {pathToFileURL} from 'url'; import chalk = require('chalk'); import * as fs from 'graceful-fs'; import sourcemapSupport = require('source-map-support'); @@ -106,44 +105,13 @@ async function runTestInternal( const cacheFS = new Map([[path, testSource]]); const transformer = await createScriptTransformer(config, cacheFS); - let TestEnvironment: typeof JestEnvironment; - try { - TestEnvironment = interopRequireDefault( - transformer.requireAndTranspileModule(testEnvironment), - ).default; - } catch (err) { - if (err.code === 'ERR_REQUIRE_ESM') { - try { - const configUrl = pathToFileURL(testEnvironment); - - // node `import()` supports URL, but TypeScript doesn't know that - const importedConfig = await import(configUrl.href); - - if (!importedConfig.default) { - throw new Error( - `Jest: Failed to load mjs config file ${testEnvironment} - did you use a default export?`, - ); - } - - TestEnvironment = importedConfig.default; - } catch (innerError) { - if (innerError.message === 'Not supported') { - throw new Error( - `Jest: Your version of Node does not support dynamic import - please enable it or use a .cjs file extension for file ${testEnvironment}`, - ); - } - - throw innerError; - } - } else { - throw err; - } - } - const testFramework: TestFramework = interopRequireDefault( - transformer.requireAndTranspileModule( - process.env.JEST_JASMINE === '1' ? 'jest-jasmine2' : config.testRunner, - ), - ).default; + + const TestEnvironment: typeof JestEnvironment = await transformer.requireAndTranspileModule( + testEnvironment, + ); + const testFramework: TestFramework = await transformer.requireAndTranspileModule( + process.env.JEST_JASMINE === '1' ? 'jest-jasmine2' : config.testRunner, + ); const Runtime: typeof RuntimeClass = interopRequireDefault( config.moduleLoader ? require(config.moduleLoader) diff --git a/packages/jest-snapshot/src/SnapshotResolver.ts b/packages/jest-snapshot/src/SnapshotResolver.ts index 4bf11bb5c9dc..5e8358e5046d 100644 --- a/packages/jest-snapshot/src/SnapshotResolver.ts +++ b/packages/jest-snapshot/src/SnapshotResolver.ts @@ -37,19 +37,19 @@ export const buildSnapshotResolver = async ( const resolver = cache.get(key) ?? - createSnapshotResolver(await localRequire, config.snapshotResolver); + (await createSnapshotResolver(await localRequire, config.snapshotResolver)); cache.set(key, resolver); return resolver; }; -function createSnapshotResolver( +async function createSnapshotResolver( localRequire: LocalRequire, snapshotResolverPath?: Config.Path | null, -): SnapshotResolver { +): Promise { return typeof snapshotResolverPath === 'string' - ? createCustomSnapshotResolver(snapshotResolverPath, localRequire) + ? await createCustomSnapshotResolver(snapshotResolverPath, localRequire) : createDefaultSnapshotResolver(); } @@ -76,12 +76,12 @@ function createDefaultSnapshotResolver(): SnapshotResolver { }; } -function createCustomSnapshotResolver( +async function createCustomSnapshotResolver( snapshotResolverPath: Config.Path, localRequire: LocalRequire, -): SnapshotResolver { +): Promise { const custom: SnapshotResolver = interopRequireDefault( - localRequire(snapshotResolverPath), + await localRequire(snapshotResolverPath), ).default; const keys: Array<[keyof SnapshotResolver, string]> = [ diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts index 3eac1012423b..0cf2de288a88 100644 --- a/packages/jest-transform/src/ScriptTransformer.ts +++ b/packages/jest-transform/src/ScriptTransformer.ts @@ -20,7 +20,6 @@ import type {Config} from '@jest/types'; import HasteMap from 'jest-haste-map'; import { createDirectory, - interopRequireDefault, isPromise, requireOrImportModule, tryRealpath, @@ -30,6 +29,7 @@ import shouldInstrument from './shouldInstrument'; import type { Options, ReducedTransformOptions, + RequireAndTranspileModuleOptions, StringMap, SyncTransformer, TransformOptions, @@ -735,28 +735,20 @@ class ScriptTransformer { return fileSource; } - requireAndTranspileModule( - moduleName: string, - callback?: (module: ModuleType) => void, - transformOptions?: ReducedTransformOptions, - ): ModuleType; - requireAndTranspileModule( - moduleName: string, - callback?: (module: ModuleType) => Promise, - transformOptions?: ReducedTransformOptions, - ): Promise; - requireAndTranspileModule( + async requireAndTranspileModule( moduleName: string, callback?: (module: ModuleType) => void | Promise, - transformOptions: ReducedTransformOptions = { + options: RequireAndTranspileModuleOptions = { + applyInteropRequireDefault: true, instrument: false, supportsDynamicImport: false, supportsExportNamespaceFrom: false, supportsStaticESM: false, supportsTopLevelAwait: false, }, - ): ModuleType | Promise { + ): Promise { let transforming = false; + const {applyInteropRequireDefault, ...transformOptions} = options; const revertHook = addHook( (code, filename) => { try { @@ -780,7 +772,10 @@ class ScriptTransformer { }, }, ); - const module: ModuleType = require(moduleName); + const module: ModuleType = await requireOrImportModule( + moduleName, + applyInteropRequireDefault, + ); if (!callback) { revertHook(); @@ -818,21 +813,28 @@ export async function createTranspilingRequire( ( resolverPath: string, applyInteropRequireDefault?: boolean, - ) => TModuleType + ) => Promise > { const transformer = await createScriptTransformer(config); - return function requireAndTranspileModule( + return async function requireAndTranspileModule( resolverPath: string, applyInteropRequireDefault: boolean = false, - ): TModuleType { - const transpiledModule = transformer.requireAndTranspileModule( + ) { + const transpiledModule = await transformer.requireAndTranspileModule( resolverPath, + () => {}, + { + applyInteropRequireDefault, + instrument: false, + supportsDynamicImport: false, // this might be true, depending on node version. + supportsExportNamespaceFrom: false, + supportsStaticESM: false, + supportsTopLevelAwait: false, + }, ); - return applyInteropRequireDefault - ? interopRequireDefault(transpiledModule).default - : transpiledModule; + return transpiledModule; }; } diff --git a/packages/jest-transform/src/types.ts b/packages/jest-transform/src/types.ts index f2e5d44b27cf..fa18c2ec4196 100644 --- a/packages/jest-transform/src/types.ts +++ b/packages/jest-transform/src/types.ts @@ -50,6 +50,11 @@ export interface ReducedTransformOptions extends CallerTransformOptions { instrument: boolean; } +export interface RequireAndTranspileModuleOptions + extends ReducedTransformOptions { + applyInteropRequireDefault: boolean; +} + export type StringMap = Map; export interface TransformOptions diff --git a/packages/jest-util/src/requireOrImportModule.ts b/packages/jest-util/src/requireOrImportModule.ts index 684a114f12b1..9966ee727ba9 100644 --- a/packages/jest-util/src/requireOrImportModule.ts +++ b/packages/jest-util/src/requireOrImportModule.ts @@ -12,28 +12,36 @@ import interopRequireDefault from './interopRequireDefault'; export default async function requireOrImportModule( filePath: Config.Path, + applyInteropRequireDefault = true, ): Promise { - let module: T; if (!isAbsolute(filePath) && filePath[0] === '.') { throw new Error(`Jest: requireOrImportModule path must be absolute`); } try { - module = interopRequireDefault(require(filePath)).default; + const requiredModule = require(filePath); + if (!applyInteropRequireDefault) { + return requiredModule; + } + return interopRequireDefault(requiredModule).default; } catch (error) { if (error.code === 'ERR_REQUIRE_ESM') { try { - const configUrl = pathToFileURL(filePath); + const moduleUrl = pathToFileURL(filePath); // node `import()` supports URL, but TypeScript doesn't know that - const importedConfig = await import(configUrl.href); + const importedModule = await import(moduleUrl.href); + + if (!applyInteropRequireDefault) { + return importedModule; + } - if (!importedConfig.default) { + if (!importedModule.default) { throw new Error( `Jest: Failed to load ESM at ${filePath} - did you use a default export?`, ); } - module = importedConfig.default; + return importedModule.default; } catch (innerError) { if (innerError.message === 'Not supported') { throw new Error( @@ -46,5 +54,4 @@ export default async function requireOrImportModule( throw error; } } - return module; }