Skip to content
Permalink
Browse files

Support loading ESM test files

Co-authored-by: Mark Wubben <mark@novemberborn.net>
  • Loading branch information
arlac77 and novemberborn committed Feb 9, 2020
1 parent ea05758 commit 04ba44b4d738088a5133895caad7e85d25240b42
@@ -2,11 +2,35 @@

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

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.
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.

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.
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.*

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`.
## Enabling experimental ESM support in Node.js 12

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:

**`package.json`:**

```json
{
"ava": {
"nodeArguments": [
"--experimental-modules"
]
}
}
```

Or on the command line:

```console
npx ava --node-arguments '--experimental-modules' test.mjs
```

## Using the `esm` package

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`.

Here's how you get it working with AVA.

@@ -0,0 +1,2 @@
// Keep this file in place.
// It is there to check that ESM dynamic import actually works in the current Node.js version.
@@ -1,4 +1,5 @@
'use strict';
const {pathToFileURL} = require('url');
const currentlyUnhandled = require('currently-unhandled')();

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

// Lazily determine support since this prints an experimental warning.
let supportsESM = async () => {
try {
await import('../esm-probe.mjs');
supportsESM = async () => true;
} catch {
supportsESM = async () => false;
}

return supportsESM();
};

let requireFn = require;
const load = async ref => {
for (const extension of extensionsToLoadAsModules) {
if (ref.endsWith(`.${extension}`)) {
ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, new Error('AVA cannot yet load ESM files.'))});
if (await supportsESM()) { // eslint-disable-line no-await-in-loop
return import(pathToFileURL(ref));
}

ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, new Error('ECMAScript Modules are not supported in this Node.js version.'))});
exit(1);
return;
}
@@ -671,7 +671,7 @@ test('`esm` package support', t => {
require: [require.resolve('esm')]
});

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

This file was deleted.

@@ -1,4 +1,4 @@
import test from '../..';
import test from '../../index.js'; // eslint-disable-line import/no-useless-path-segments, unicorn/import-index, import/extensions

test('pass', t => {
t.pass();
File renamed without changes.
@@ -0,0 +1,5 @@
import test from '../../../index.js'; // eslint-disable-line import/no-useless-path-segments, unicorn/import-index, import/extensions

test('pass', t => {
t.pass();
});
File renamed without changes.
File renamed without changes.
@@ -164,18 +164,30 @@ test('selects .cjs test files', t => {
});
});

test('refuses to load .mjs test files', t => {
test('load .mjs test files (when node supports it)', t => {
execCli('mjs.mjs', (err, stdout) => {
t.ok(err);
t.match(stdout, /AVA cannot yet load ESM files/);
t.end();
if (Number.parseFloat(process.version.slice(1)) >= 13) {
t.ifError(err);
t.match(stdout, /1 test passed/);
t.end();
} else {
t.ok(err);
t.match(stdout, /ECMAScript Modules are not supported in this Node.js version./);
t.end();
}
});
});

test('refuses to load .js test files as ESM modules', t => {
execCli('test.js', {dirname: 'fixture/esm'}, (err, stdout) => {
t.ok(err);
t.match(stdout, /AVA cannot yet load ESM files/);
t.end();
test('load .js test files as ESM modules (when node supports it)', t => {
execCli('test.js', {dirname: 'fixture/pkg-type-module'}, (err, stdout) => {
if (Number.parseFloat(process.version.slice(1)) >= 13) {
t.ifError(err);
t.match(stdout, /1 test passed/);
t.end();
} else {
t.ok(err);
t.match(stdout, /ECMAScript Modules are not supported in this Node.js version./);
t.end();
}
});
});

0 comments on commit 04ba44b

Please sign in to comment.
You can’t perform that action at this time.