Skip to content

Commit 04ba44b

Browse files
Support loading ESM test files
Co-authored-by: Mark Wubben <[email protected]>
1 parent ea05758 commit 04ba44b

File tree

11 files changed

+75
-20
lines changed

11 files changed

+75
-20
lines changed

docs/recipes/es-modules.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,35 @@
22

33
Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/docs/recipes/es-modules.md)
44

5-
As of Node.js 13, [ECMAScript modules](https://nodejs.org/docs/latest/api/esm.html#esm_introduction) are natively supported in Node.js itself. AVA does not quite support them *yet*, but we're close.
5+
As of Node.js 13, [ECMAScript Modules](https://nodejs.org/docs/latest/api/esm.html#esm_introduction) are natively supported in Node.js itself. AVA 3.3 supports ESM test files, however support is incomplete. The [ESM support project](https://github.com/orgs/avajs/projects/2) tracks our progress.
66

7-
For the time being, AVA *does* select test files with the `.mjs` extension, however it refuses to load them. Similarly the `package.json` `"type": "module"` field is recognized, but if set AVA will refuse to load test files with the `.js` extension.
7+
ESM support in Node.js is experimental, though enabled by default in Node.js 13. *You will see messages like `ExperimentalWarning: The ESM module loader is experimental` in AVA's output. These are emitted by Node.js, not AVA.*
88

9-
For now, your best bet is to use the [`esm`](https://github.com/standard-things/esm) package. Make sure to use the `.js` extension and *do not* set `"type": "module"` in `package.json`.
9+
## Enabling experimental ESM support in Node.js 12
10+
11+
In Node.js 12 you need to enable ESM support. You can do so via AVA by configuring `nodeArguments` in your `package.json` or `ava.config.*` file:
12+
13+
**`package.json`:**
14+
15+
```json
16+
{
17+
"ava": {
18+
"nodeArguments": [
19+
"--experimental-modules"
20+
]
21+
}
22+
}
23+
```
24+
25+
Or on the command line:
26+
27+
```console
28+
npx ava --node-arguments '--experimental-modules' test.mjs
29+
```
30+
31+
## Using the `esm` package
32+
33+
If you want to use the ESM syntax, without relying on Node.js' implementation, your best bet is to use the [`esm`](https://github.com/standard-things/esm) package. Make sure to use the `.js` extension and *do not* set `"type": "module"` in `package.json`.
1034

1135
Here's how you get it working with AVA.
1236

lib/esm-probe.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Keep this file in place.
2+
// It is there to check that ESM dynamic import actually works in the current Node.js version.

lib/worker/subprocess.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict';
2+
const {pathToFileURL} = require('url');
23
const currentlyUnhandled = require('currently-unhandled')();
34

45
require('./ensure-forked'); // eslint-disable-line import/no-unassigned-import
@@ -133,11 +134,27 @@ ipc.options.then(async options => {
133134
return null;
134135
}).filter(provider => provider !== null);
135136

137+
// Lazily determine support since this prints an experimental warning.
138+
let supportsESM = async () => {
139+
try {
140+
await import('../esm-probe.mjs');
141+
supportsESM = async () => true;
142+
} catch {
143+
supportsESM = async () => false;
144+
}
145+
146+
return supportsESM();
147+
};
148+
136149
let requireFn = require;
137150
const load = async ref => {
138151
for (const extension of extensionsToLoadAsModules) {
139152
if (ref.endsWith(`.${extension}`)) {
140-
ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, new Error('AVA cannot yet load ESM files.'))});
153+
if (await supportsESM()) { // eslint-disable-line no-await-in-loop
154+
return import(pathToFileURL(ref));
155+
}
156+
157+
ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, new Error('ECMAScript Modules are not supported in this Node.js version.'))});
141158
exit(1);
142159
return;
143160
}

test/api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ test('`esm` package support', t => {
671671
require: [require.resolve('esm')]
672672
});
673673

674-
return api.run({files: [path.join(__dirname, 'fixture/esm-pkg/test.js')]})
674+
return api.run({files: [path.join(__dirname, 'fixture/userland-esm-package/test.js')]})
675675
.then(runStatus => {
676676
t.is(runStatus.stats.passedTests, 1);
677677
});

test/fixture/esm/test.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

test/fixture/mjs.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import test from '../..';
1+
import test from '../../index.js'; // eslint-disable-line import/no-useless-path-segments, unicorn/import-index, import/extensions
22

33
test('pass', t => {
44
t.pass();
File renamed without changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import test from '../../../index.js'; // eslint-disable-line import/no-useless-path-segments, unicorn/import-index, import/extensions
2+
3+
test('pass', t => {
4+
t.pass();
5+
});
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)