Skip to content

Commit 64de4d7

Browse files
authored
feat: support files other than js to be ESM (#10823)
1 parent fe144ea commit 64de4d7

27 files changed

Lines changed: 268 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- `[jest-config]` [**BREAKING**] Default to Node testing environment instead of browser (JSDOM) ([#9874](https://github.com/facebook/jest/pull/9874))
66
- `[jest-config]` [**BREAKING**] Use `jest-circus` as default test runner ([#10686](https://github.com/facebook/jest/pull/10686))
7+
- `[jest-config, jest-runtime]` Support ESM for files other than `.js` and `.mjs` ([#10823](https://github.com/facebook/jest/pull/10823))
78
- `[jest-repl, jest-runner]` [**BREAKING**] Run transforms over environment ([#8751](https://github.com/facebook/jest/pull/8751))
89
- `[jest-runner]` [**BREAKING**] set exit code to 1 if test logs after teardown ([#10728](https://github.com/facebook/jest/pull/10728))
910
- `[jest-snapshot]` [**BREAKING**] Make prettier optional for inline snapshots - fall back to string replacement ([#7792](https://github.com/facebook/jest/pull/7792))

docs/Configuration.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,23 @@ Default: `false`
353353

354354
Make calling deprecated APIs throw helpful error messages. Useful for easing the upgrade process.
355355

356+
### `extensionsToTreatAsEsm` [array\<string>]
357+
358+
Default: `[]`
359+
360+
Jest will run `.mjs` and `.js` files with nearest `package.json`'s `type` field set to `module` as ECMAScript Modules. If you have any other files that should run with native ESM, you need to specify their file extension here.
361+
362+
> Note: Jest's ESM support is still experimental, see [its docs for more details](ECMAScriptModules.md).
363+
364+
```json
365+
{
366+
...
367+
"jest": {
368+
"extensionsToTreatAsEsm": [".ts"]
369+
}
370+
}
371+
```
372+
356373
### `extraGlobals` [array\<string>]
357374

358375
Default: `undefined`

docs/ECMAScriptModules.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ Jest ships with _experimental_ support for ECMAScript Modules (ESM).
1212
With the warnings out of the way, this is how you activate ESM support in your tests.
1313

1414
1. Ensure you either disable [code transforms](./configuration#transform-objectstring-pathtotransformer--pathtotransformer-object) by passing `transform: {}` or otherwise configure your transformer to emit ESM rather than the default CommonJS (CJS).
15-
1. Execute `node` with `--experimental-vm-modules`, e.g. `node --experimental-vm-modules node_modules/.bin/jest` or `NODE_OPTIONS=--experimental-vm-modules npx jest` etc.. On Windows, you can use [`cross-env`](https://github.com/kentcdodds/cross-env) to be able to set environment variables
16-
1. Beyond that, we attempt to follow `node`'s logic for activating "ESM mode" (such as looking at `type` in `package.json` or `mjs` files), see [their docs](https://nodejs.org/api/esm.html#esm_enabling) for details
15+
1. Execute `node` with `--experimental-vm-modules`, e.g. `node --experimental-vm-modules node_modules/.bin/jest` or `NODE_OPTIONS=--experimental-vm-modules npx jest` etc.. On Windows, you can use [`cross-env`](https://github.com/kentcdodds/cross-env) to be able to set environment variables.
16+
1. Beyond that, we attempt to follow `node`'s logic for activating "ESM mode" (such as looking at `type` in `package.json` or `mjs` files), see [their docs](https://nodejs.org/api/esm.html#esm_enabling) for details.
17+
1. If you want to treat other file extensions (such as `ts`) as ESM, please use the [`extensionsToTreatAsEsm` option](Configuration.md#extensionstotreatasesm-arraystring).
1718

1819
## Differences between ESM and CommonJS
1920

e2e/__tests__/__snapshots__/showConfig.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
1515
"detectLeaks": false,
1616
"detectOpenHandles": false,
1717
"errorOnDeprecated": false,
18+
"extensionsToTreatAsEsm": [],
1819
"extraGlobals": [],
1920
"forceCoverageMatch": [],
2021
"globals": {},
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import {resolve} from 'path';
9+
import {onNodeVersions} from '@jest/test-utils';
10+
import {json as runJest} from '../runJest';
11+
12+
const DIR = resolve(__dirname, '../native-esm-typescript');
13+
14+
// The versions where vm.Module exists and commonjs with "exports" is not broken
15+
onNodeVersions('^12.16.0 || >=13.7.0', () => {
16+
test('runs TS test with native ESM', () => {
17+
const {exitCode, json} = runJest(DIR, [], {
18+
nodeOptions: '--experimental-vm-modules',
19+
});
20+
21+
expect(exitCode).toBe(0);
22+
23+
expect(json.numTotalTests).toBe(2);
24+
expect(json.numPassedTests).toBe(2);
25+
});
26+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import {double} from '../double';
9+
10+
test('test double', () => {
11+
expect(double(2)).toBe(4);
12+
});
13+
14+
test('test import.meta', () => {
15+
expect(typeof import.meta.url).toBe('string');
16+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
module.exports = {
9+
// importantly this does _not_ include `preset-env`
10+
presets: ['@babel/preset-typescript'],
11+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
export function double(num: number): number {
9+
return num * 2;
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "native-esm-typescript",
3+
"version": "1.0.0",
4+
"jest": {
5+
"extensionsToTreatAsEsm": [".ts"],
6+
"testEnvironment": "node"
7+
}
8+
}

packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,15 @@ const jestAdapter = async (
7272
});
7373

7474
for (const path of config.setupFilesAfterEnv) {
75-
// TODO: remove ? in Jest 26
76-
const esm = runtime.unstable_shouldLoadAsEsm?.(path);
75+
const esm = runtime.unstable_shouldLoadAsEsm(path);
7776

7877
if (esm) {
7978
await runtime.unstable_importModule(path);
8079
} else {
8180
runtime.requireModule(path);
8281
}
8382
}
84-
85-
// TODO: remove ? in Jest 26
86-
const esm = runtime.unstable_shouldLoadAsEsm?.(testPath);
83+
const esm = runtime.unstable_shouldLoadAsEsm(testPath);
8784

8885
if (esm) {
8986
await runtime.unstable_importModule(testPath);

0 commit comments

Comments
 (0)