From c6d44df40c513495947af86784f9ea8d1966b2e0 Mon Sep 17 00:00:00 2001 From: Gil Tayar Date: Fri, 21 May 2021 13:43:51 +0300 Subject: [PATCH 1/6] Change port used in test, because port 55555 is used in MacOS Big Sure --- test/integration/fixtures/exit.fixture.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/fixtures/exit.fixture.js b/test/integration/fixtures/exit.fixture.js index d369fb311b..0a5e5eb900 100644 --- a/test/integration/fixtures/exit.fixture.js +++ b/test/integration/fixtures/exit.fixture.js @@ -4,5 +4,5 @@ var net = require('net'); it('should hang when --no-exit used', function (done) { var server = net.createServer(); - server.listen(55555, done); + server.listen(55554, done); }); From 084b4e505e3e95387f2031a9488304a33d298a77 Mon Sep 17 00:00:00 2001 From: Gil Tayar Date: Fri, 21 May 2021 13:45:13 +0300 Subject: [PATCH 2/6] change test file loading to be ESM-first FIrst try ESM, and only if that fails, load test file using require. This enables an ESM loader to have first dibs at transforming the file. --- lib/esm-utils.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/esm-utils.js b/lib/esm-utils.js index eebeb9322b..a79aeca74c 100644 --- a/lib/esm-utils.js +++ b/lib/esm-utils.js @@ -34,21 +34,28 @@ exports.requireOrImport = async file => { if (path.extname(file) === '.mjs') { return formattedImport(file); } - // This is currently the only known way of figuring out whether a file is CJS or ESM. - // If Node.js or the community establish a better procedure for that, we can fix this code. - // Another option here would be to always use `import()`, as this also supports CJS, but I would be - // wary of using it for _all_ existing test files, till ESM is fully stable. try { - return require(file); + return dealWithExports(await formattedImport(file)); } catch (err) { - if (err.code === 'ERR_REQUIRE_ESM') { - return formattedImport(file); + if ( + err.code === 'ERR_MODULE_NOT_FOUND' || + err.code === 'ERR_UNKNOWN_FILE_EXTENSION' + ) { + return require(file); } else { throw err; } } }; +function dealWithExports(module) { + if (module.default) { + return module.default; + } else { + return {...module, default: undefined}; + } +} + exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => { for (const file of files) { preLoadFunc(file); From 81bdaeedfee45286feb4b17a1ad9ef86d729eb5c Mon Sep 17 00:00:00 2001 From: Gil Tayar Date: Sat, 22 May 2021 17:03:22 +0300 Subject: [PATCH 3/6] docs: removed reference to esm being experimental Also removed outdated information and references to the "esm" module that emulated ESM in Node.js --- docs/index.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/docs/index.md b/docs/index.md index 953f7bfef9..1cc8047687 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1065,7 +1065,6 @@ Require a module before loading the user interface or test files. This is useful - Test harnesses - Assertion libraries that augment built-ins or global scope (such as [should.js][npm-should.js]) -- Instant ECMAScript modules via [esm][npm-esm] - Compilers such as Babel via [@babel/register][npm-babel-register] or TypeScript via [ts-node][npm-ts-node] (using `--require ts-node/register`). See [Babel][example-babel] or [TypeScript][example-typescript] working examples. Modules required in this manner are expected to do work synchronously; Mocha won't wait for async tasks in a required module to finish. @@ -2034,20 +2033,15 @@ this means either ending the file with a `.mjs` extension, or, if you want to us adding `"type": "module"` to your `package.json`. More information can be found in the [Node.js documentation](https://nodejs.org/api/esm.html). -> 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 -> Mocha. From version 13.2.0 of Node.js, you can use ES modules without any flags. -> (Mocha _will_ load ESM even in Node v10, but this is not officially supported. Use at your own risk.) - ### Current Limitations -Node.JS native ESM support still has status: **Stability: 1 - Experimental** - - [Watch mode](#-watch-w) does not support ES Module test files - [Custom reporters](#third-party-reporters) and [custom interfaces](#interfaces) can only be CommonJS files - [Configuration file](#configuring-mocha-nodejs) can only be a CommonJS file (`.mocharc.js` or `.mocharc.cjs`) -- When using module-level mocks via libs like `proxyquire`, `rewiremock` or `rewire`, hold off on using ES modules for your test files -- Node.JS native ESM support does not work with [esm][npm-esm] module +- When using module-level mocks via libs like `proxyquire`, `rewiremock` or `rewire`, + hold off on using ES modules for your test files. You can switch to using `testdouble`, + which does support ESM. ## Running Mocha in the Browser @@ -2426,7 +2420,6 @@ or the [source](https://github.com/mochajs/mocha/blob/master/lib/mocha.js). [npm]: https://npmjs.org/ [npm-babel-register]: https://npm.im/@babel/register [npm-chai-as-promised]: https://www.npmjs.com/package/chai-as-promised -[npm-esm]: https://npm.im/esm [npm-glob]: https://www.npmjs.com/package/glob [npm-growl]: https://npm.im/growl [npm-mocha-lcov-reporter]: https://npm.im/mocha-lcov-reporter From 3637b7658cb02f6daf5b43267a474c465216063e Mon Sep 17 00:00:00 2001 From: Gil Tayar Date: Sat, 22 May 2021 17:31:01 +0300 Subject: [PATCH 4/6] bring back support for Node <= 12.22.0 --- lib/esm-utils.js | 58 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/esm-utils.js b/lib/esm-utils.js index a79aeca74c..2aa9fe674a 100644 --- a/lib/esm-utils.js +++ b/lib/esm-utils.js @@ -30,23 +30,32 @@ const formattedImport = async file => { return import(file); }; -exports.requireOrImport = async file => { - if (path.extname(file) === '.mjs') { - return formattedImport(file); - } - try { - return dealWithExports(await formattedImport(file)); - } catch (err) { - if ( - err.code === 'ERR_MODULE_NOT_FOUND' || - err.code === 'ERR_UNKNOWN_FILE_EXTENSION' - ) { - return require(file); - } else { - throw err; +const hasStableEsmImplementation = (() => { + const [major, minor] = process.version.split('.'); + // ESM is stable from v12.22.0 onward + // https://nodejs.org/api/esm.html#esm_modules_ecmascript_modules + return parseInt(major.slice(1), 10) > 12 || parseInt(minor, 10) >= 22; +})(); + +exports.requireOrImport = hasStableEsmImplementation + ? async file => { + if (path.extname(file) === '.mjs') { + return formattedImport(file); + } + try { + return dealWithExports(await formattedImport(file)); + } catch (err) { + if ( + err.code === 'ERR_MODULE_NOT_FOUND' || + err.code === 'ERR_UNKNOWN_FILE_EXTENSION' + ) { + return require(file); + } else { + throw err; + } + } } - } -}; + : implemenetationOfRequireOrImportForUnstableEsm; function dealWithExports(module) { if (module.default) { @@ -63,3 +72,20 @@ exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => { postLoadFunc(file, result); } }; + +async function implemenetationOfRequireOrImportForUnstableEsm(file) { + if (path.extname(file) === '.mjs') { + return formattedImport(file); + } + // This is currently the only known way of figuring out whether a file is CJS or ESM in + // Node.js that doesn't necessitate calling `import` first. + try { + return require(file); + } catch (err) { + if (err.code === 'ERR_REQUIRE_ESM') { + return formattedImport(file); + } else { + throw err; + } + } +} From d68d8eaa36b07f03206c95be9b304df4a00b9c9b Mon Sep 17 00:00:00 2001 From: Gil Tayar Date: Fri, 28 May 2021 08:51:39 +0300 Subject: [PATCH 5/6] fix typo of "implementationOfRequireOrImportForUnstableEsm" --- lib/esm-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/esm-utils.js b/lib/esm-utils.js index 2aa9fe674a..ecd9a1cefa 100644 --- a/lib/esm-utils.js +++ b/lib/esm-utils.js @@ -55,7 +55,7 @@ exports.requireOrImport = hasStableEsmImplementation } } } - : implemenetationOfRequireOrImportForUnstableEsm; + : implementationOfRequireOrImportForUnstableEsm; function dealWithExports(module) { if (module.default) { @@ -73,7 +73,7 @@ exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => { } }; -async function implemenetationOfRequireOrImportForUnstableEsm(file) { +async function implementationOfRequireOrImportForUnstableEsm(file) { if (path.extname(file) === '.mjs') { return formattedImport(file); } From 35a5c9f147d8f80cfcb213b4e19e46a46f54176c Mon Sep 17 00:00:00 2001 From: Gil Tayar Date: Fri, 28 May 2021 08:52:32 +0300 Subject: [PATCH 6/6] ignore "implementationOfRequireOrImportForUnstableEsm" when profiling --- lib/esm-utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/esm-utils.js b/lib/esm-utils.js index ecd9a1cefa..14a9c28fa8 100644 --- a/lib/esm-utils.js +++ b/lib/esm-utils.js @@ -73,6 +73,7 @@ exports.loadFilesAsync = async (files, preLoadFunc, postLoadFunc) => { } }; +/* istanbul ignore next */ async function implementationOfRequireOrImportForUnstableEsm(file) { if (path.extname(file) === '.mjs') { return formattedImport(file);