Skip to content

Commit

Permalink
feature: allow ESM for test environment (#11033)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilles Yvetot committed Apr 30, 2021
1 parent 4c3643c commit 1a977d9
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -26,6 +26,7 @@
- `[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-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))
Expand Down
20 changes: 20 additions & 0 deletions e2e/__tests__/testEnvironmentEsm.ts
@@ -0,0 +1,20 @@
/**
* 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 {resolve} from 'path';
import {onNodeVersions} from '@jest/test-utils';
import runJest from '../runJest';

// The versions where vm.Module exists and commonjs with "exports" is not broken
onNodeVersions('^12.16.0 || >=13.7.0', () => {
it('support test environment written in ESM', () => {
const DIR = resolve(__dirname, '../test-environment-esm');
const {exitCode} = runJest(DIR);

expect(exitCode).toBe(0);
});
});
15 changes: 15 additions & 0 deletions e2e/test-environment-esm/EnvESM.js
@@ -0,0 +1,15 @@
/**
* 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 NodeEnvironment from 'jest-environment-node';

export default class Env extends NodeEnvironment {
constructor(...args) {
super(...args);
this.global.someVar = 42;
}
}
11 changes: 11 additions & 0 deletions e2e/test-environment-esm/__tests__/testUsingESMTestEnv.test.js
@@ -0,0 +1,11 @@
/**
* 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('dummy', () => {
expect(global.someVar).toBe(42);
});
7 changes: 7 additions & 0 deletions e2e/test-environment-esm/package.json
@@ -0,0 +1,7 @@
{
"type": "module",
"jest": {
"testEnvironment": "<rootDir>/EnvESM.js",
"transform": {}
}
}
38 changes: 34 additions & 4 deletions packages/jest-runner/src/runTest.ts
Expand Up @@ -6,6 +6,7 @@
*
*/

import {pathToFileURL} from 'url';
import chalk = require('chalk');
import * as fs from 'graceful-fs';
import sourcemapSupport = require('source-map-support');
Expand Down Expand Up @@ -105,10 +106,39 @@ async function runTestInternal(

const cacheFS = new Map([[path, testSource]]);
const transformer = await createScriptTransformer(config, cacheFS);

const TestEnvironment: typeof JestEnvironment = interopRequireDefault(
transformer.requireAndTranspileModule(testEnvironment),
).default;
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,
Expand Down

0 comments on commit 1a977d9

Please sign in to comment.