Skip to content

Commit 68736ef

Browse files
committed
code review
1 parent 6a61d73 commit 68736ef

File tree

8 files changed

+86
-99
lines changed

8 files changed

+86
-99
lines changed

.eslintrc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ overrides:
3737
ecmaVersion: 2018
3838
sourceType: module
3939
parser: babel-eslint
40+
env:
41+
browser: false
4042
- files:
4143
- test/**/*.{js,mjs}
4244
env:

docs/index.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Mocha is a feature-rich JavaScript test framework running on [Node.js][] and in
7171
- [Command-Line Usage](#command-line-usage)
7272
- [Interfaces](#interfaces)
7373
- [Reporters](#reporters)
74+
- [Node.JS native ESM support](#nodejs-native-esm-support)
7475
- [Running Mocha in the Browser](#running-mocha-in-the-browser)
7576
- [Desktop Notification Support](#desktop-notification-support)
7677
- [Configuring Mocha (Node.js)](#configuring-mocha-nodejs)
@@ -869,7 +870,8 @@ Configuration
869870
--package Path to package.json for config [string]
870871
871872
File Handling
872-
--extension File extension(s) to load [array] [default: js]
873+
--extension File extension(s) to load
874+
[array] [default: ["js","cjs","mjs"]]
873875
--file Specify file(s) to be loaded prior to root suite
874876
execution [array] [default: (none)]
875877
--ignore, --exclude Ignore file(s) or glob pattern(s)
@@ -1541,7 +1543,9 @@ Alias: `HTML`, `html`
15411543

15421544
## Node.JS native ESM support
15431545

1544-
Mocha supports writing your tests as ES modules (without needing to use the `esm` polyfill module), and not just using CommonJS. For example:
1546+
> _New in v7.1.0_
1547+
1548+
Mocha supports writing your tests as ES modules, and not just using CommonJS. For example:
15451549

15461550
```js
15471551
// test.mjs
@@ -1558,18 +1562,20 @@ this means either ending the file with a `.mjs` extension, or, if you want to us
15581562
adding `"type": "module"` to your `package.json`.
15591563
More information can be found in the [Node.js documentation](https://nodejs.org/api/esm.html).
15601564

1561-
> Mocha supports ES modules only from Node.js v12.11.0 and above. Also note that
1562-
> to enable this in vesions smaller than 13.2.0, you need to add `--experimental-modules` when running
1565+
> Mocha supports ES modules only from Node.js v12.11.0 and above. To enable this in versions smaller than 13.2.0, you need to add `--experimental-modules` when running
15631566
> Mocha. From version 13.2.0 of Node.js, you can use ES modules without any flags.
15641567
1565-
### Limitations
1568+
### Current Limitations
1569+
1570+
Node.JS native ESM support still has status: **Stability: 1 - Experimental**
15661571

1567-
- "Watch mode" (i.e. using `--watch` options) does not currently support ES Module test files,
1568-
although we intend to support it in the future
1572+
- [Watch mode](#-watch-w) does not support ES Module test files
15691573
- [Custom reporters](#third-party-reporters) and [custom interfaces](#interfaces)
1570-
can currently only be CommonJS files, although we intend to support it in the future
1571-
- `mocharc.js` can only be a CommonJS file (can also be called `mocharc.cjs`),
1572-
although we intend to support ESM in the future
1574+
can only be CommonJS files
1575+
- [Required modules](#-require-module-r-module) can only be CommonJS files
1576+
- [Configuration file](#configuring-mocha-nodejs) can only be a CommonJS file (`mocharc.js` or `mocharc.cjs`)
1577+
- When using module-level mocks via libs like `proxyquire`, `rewiremock` or `rewire`, hold off on using ES modules for your test files
1578+
- Node.JS native ESM support does not work with [esm][npm-esm] module
15731579

15741580
## Running Mocha in the Browser
15751581

lib/cli/run-helpers.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ const collectFiles = require('./collect-files');
1515

1616
const cwd = (exports.cwd = process.cwd());
1717

18-
exports.watchRun = watchRun;
19-
2018
/**
2119
* Exits Mocha when tests + code under test has finished execution (default)
2220
* @param {number} code - Exit code; typically # of failures
@@ -101,7 +99,7 @@ exports.handleRequires = (requires = []) => {
10199
* @returns {Promise<Runner>}
102100
* @private
103101
*/
104-
exports.singleRun = async (mocha, {exit}, fileCollectParams) => {
102+
const singleRun = async (mocha, {exit}, fileCollectParams) => {
105103
const files = collectFiles(fileCollectParams);
106104
debug('running tests with files', files);
107105
mocha.files = files;
@@ -117,7 +115,7 @@ exports.singleRun = async (mocha, {exit}, fileCollectParams) => {
117115
* @private
118116
* @returns {Promise}
119117
*/
120-
exports.runMocha = (mocha, options) => {
118+
exports.runMocha = async (mocha, options) => {
121119
const {
122120
watch = false,
123121
extension = [],
@@ -143,7 +141,7 @@ exports.runMocha = (mocha, options) => {
143141
if (watch) {
144142
watchRun(mocha, {watchFiles, watchIgnore}, fileCollectParams);
145143
} else {
146-
return exports.singleRun(mocha, {exit}, fileCollectParams);
144+
await singleRun(mocha, {exit}, fileCollectParams);
147145
}
148146
};
149147

lib/cli/run.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ exports.builder = yargs =>
8787
},
8888
extension: {
8989
default: defaults.extension,
90-
defaultDescription: 'js',
9190
description: 'File extension(s) to load',
9291
group: GROUPS.FILES,
9392
requiresArg: true,
@@ -306,7 +305,7 @@ exports.handler = async function(argv) {
306305
try {
307306
await runMocha(mocha, argv);
308307
} catch (err) {
309-
console.error(err.stack || `Error: ${err.message || err}`);
308+
console.error('\n' + (err.stack || `Error: ${err.message || err}`));
310309
process.exit(1);
311310
}
312311
};

lib/esm-utils.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
// This file is allowed to use async/await because it is not exposed to browsers (see the `eslintrc`),
2-
// and Node supports async/await in all its non-dead version.
3-
41
const url = require('url');
52
const path = require('path');
63

7-
exports.requireOrImport = async file => {
4+
const requireOrImport = async file => {
85
file = path.resolve(file);
96

107
if (path.extname(file) === '.mjs') {
118
return import(url.pathToFileURL(file));
129
}
13-
// This way of figuring out whether a test file is CJS or ESM is currently the only known
14-
// way of figuring out whether a file is CJS or ESM.
10+
// This is currently the only known way of figuring out whether a file is CJS or ESM.
1511
// If Node.js or the community establish a better procedure for that, we can fix this code.
1612
// Another option here would be to always use `import()`, as this also supports CJS, but I would be
1713
// wary of using it for _all_ existing test files, till ESM is fully stable.
@@ -29,7 +25,7 @@ exports.requireOrImport = async file => {
2925
exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => {
3026
for (const file of files) {
3127
preLoadFunc(file);
32-
const result = await exports.requireOrImport(file);
28+
const result = await requireOrImport(file);
3329
postLoadFunc(file, result);
3430
}
3531
};

lib/mocha.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,13 @@ Mocha.prototype.loadFiles = function(fn) {
329329
* @see {@link Mocha#addFile}
330330
* @see {@link Mocha#run}
331331
* @see {@link Mocha#unloadFiles}
332-
*
333332
* @returns {Promise}
333+
* @example
334+
*
335+
* // loads ESM (and CJS) test files asynchronously, then runs root suite
336+
* mocha.loadFilesAsync()
337+
* .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0))
338+
* .catch(() => process.exitCode = 1);
334339
*/
335340
Mocha.prototype.loadFilesAsync = function() {
336341
var self = this;
@@ -371,8 +376,9 @@ Mocha.unloadFile = function(file) {
371376
* Unloads `files` from Node's `require` cache.
372377
*
373378
* @description
374-
* This allows files to be "freshly" reloaded, providing the ability
379+
* This allows required files to be "freshly" reloaded, providing the ability
375380
* to reuse a Mocha instance programmatically.
381+
* Note: does not clear ESM module files from the cache
376382
*
377383
* <strong>Intended for consumers &mdash; not used internally</strong>
378384
*
@@ -883,7 +889,11 @@ Object.defineProperty(Mocha.prototype, 'version', {
883889
* @see {@link Mocha#unloadFiles}
884890
* @see {@link Runner#run}
885891
* @param {DoneCB} [fn] - Callback invoked when test execution completed.
886-
* @return {Runner} runner instance
892+
* @returns {Runner} runner instance
893+
* @example
894+
*
895+
* // exit with non-zero status if there were test failures
896+
* mocha.run(failures => process.exitCode = failures ? 1 : 0);
887897
*/
888898
Mocha.prototype.run = function(fn) {
889899
if (this.files.length && !this.loadAsync) {

lib/utils.js

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -838,39 +838,18 @@ exports.defineConstants = function(obj) {
838838
* @description
839839
* Versions prior to 10 did not support ES Modules, and version 10 has an old incompatibile version of ESM.
840840
* This function returns whether Node.JS has ES Module supports that is compatible with Mocha's needs,
841-
* which is version 12 and older
841+
* which is version >=12.11.
842842
*
843-
* @param {Boolean} unflagged whether the support is unflagged (`true`) or only using the `--experimental-modules` flag (`false`)
844-
* @returns {Boolean} whether the current version of Node.JS supports ES Modules in a way that is compatbile with Mocha
843+
* @returns {Boolean} whether the current version of Node.JS supports ES Modules in a way that is compatible with Mocha
845844
*/
846-
exports.supportsEsModules = function(unflagged) {
847-
if (typeof document !== 'undefined') {
848-
return false;
849-
}
850-
if (
851-
typeof process !== 'object' ||
852-
!process.versions ||
853-
!process.versions.node
854-
) {
855-
return false;
856-
}
857-
var versionFields = process.versions.node.split('.');
858-
var major = +versionFields[0];
859-
var minor = +versionFields[1];
860-
861-
if (major >= 13) {
862-
if (unflagged) {
863-
return minor >= 2;
845+
exports.supportsEsModules = function() {
846+
if (!process.browser && process.versions && process.versions.node) {
847+
var versionFields = process.versions.node.split('.');
848+
var major = +versionFields[0];
849+
var minor = +versionFields[1];
850+
851+
if (major >= 13 || (major === 12 && minor >= 11)) {
852+
return true;
864853
}
865-
return true;
866854
}
867-
if (unflagged) {
868-
return false;
869-
}
870-
if (major < 12) {
871-
return false;
872-
}
873-
// major === 12
874-
875-
return minor >= 11;
876855
};

test/integration/esm.spec.js

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,53 @@
11
'use strict';
22
var run = require('./helpers').runMochaJSON;
33
var utils = require('../../lib/utils');
4-
5-
if (!utils.supportsEsModules()) return;
4+
var args =
5+
+process.versions.node.split('.')[0] >= 13 ? [] : ['--experimental-modules'];
66

77
describe('esm', function() {
8+
before(function() {
9+
if (!utils.supportsEsModules()) this.skip();
10+
});
11+
812
it('should pass a passing esm test that uses esm', function(done) {
9-
run(
10-
'esm/esm-success.fixture.mjs',
11-
utils.supportsEsModules(true)
12-
? ['--no-warnings']
13-
: ['--experimental-modules', '--no-warnings'],
14-
function(err, result) {
15-
if (err) {
16-
done(err);
17-
return;
18-
}
19-
expect(result, 'to have passed test count', 1);
20-
done();
21-
},
22-
'pipe'
23-
);
13+
var fixture = 'esm/esm-success.fixture.mjs';
14+
run(fixture, args, function(err, result) {
15+
if (err) {
16+
done(err);
17+
return;
18+
}
19+
20+
expect(result, 'to have passed test count', 1);
21+
done();
22+
});
2423
});
2524

2625
it('should fail a failing esm test that uses esm', function(done) {
27-
run(
28-
'esm/esm-failure.fixture.mjs',
29-
['--experimental-modules', '--no-warnings'],
30-
function(err, result) {
31-
if (err) {
32-
done(err);
33-
return;
34-
}
35-
expect(result, 'to have failed test count', 1);
36-
done();
26+
var fixture = 'esm/esm-failure.fixture.mjs';
27+
run(fixture, args, function(err, result) {
28+
if (err) {
29+
done(err);
30+
return;
3731
}
38-
);
32+
33+
expect(result, 'to have failed test count', 1).and(
34+
'to have failed test',
35+
'should use a function from an esm, and fail'
36+
);
37+
done();
38+
});
3939
});
4040

4141
it('should recognize esm files ending with .js due to package.json type flag', function(done) {
42-
run(
43-
'esm/js-folder/esm-in-js.fixture.js',
44-
['--experimental-modules', '--no-warnings'],
45-
function(err, result) {
46-
if (err) {
47-
done(err);
48-
return;
49-
}
50-
expect(result, 'to have passed test count', 1);
51-
done();
52-
},
53-
'pipe'
54-
);
42+
var fixture = 'esm/js-folder/esm-in-js.fixture.js';
43+
run(fixture, args, function(err, result) {
44+
if (err) {
45+
done(err);
46+
return;
47+
}
48+
49+
expect(result, 'to have passed test count', 1);
50+
done();
51+
});
5552
});
5653
});

0 commit comments

Comments
 (0)