diff --git a/lib/nodejs/esm-utils.js b/lib/nodejs/esm-utils.js index 620fb7e764..fd26665595 100644 --- a/lib/nodejs/esm-utils.js +++ b/lib/nodejs/esm-utils.js @@ -1,5 +1,6 @@ const path = require('node:path'); const url = require('node:url'); +const debug = require('debug')('mocha:esm-utils'); const forward = x => x; @@ -95,14 +96,22 @@ const requireModule = async (file, esmDecorator) => { } try { return require(file); - } catch (err) { - // Import if require fails. - return dealWithExports(await formattedImport(file, esmDecorator)); + } catch (requireErr) { + debug('requireModule caught err: %O', requireErr.message); + try { + return dealWithExports(await formattedImport(file, esmDecorator)); + } catch (importErr) { + if (importErr.code === 'ERR_INTERNAL_ASSERTION') { + throw requireErr; + } + throw importErr; + } } }; // We only assign this `requireOrImport` function once based on Node version // We check for file extensions in `requireModule` and `tryImportAndRequire` +debug('assigning requireOrImport, require_module === %O', process.features.require_module); if (process.features.require_module) { exports.requireOrImport = requireModule; } else { diff --git a/test/node-unit/esm-utils.spec.js b/test/node-unit/esm-utils.spec.js index 184756eb5d..e751ce3caf 100644 --- a/test/node-unit/esm-utils.spec.js +++ b/test/node-unit/esm-utils.spec.js @@ -5,15 +5,32 @@ const sinon = require('sinon'); const url = require('node:url'); describe('esm-utils', function () { - beforeEach(function () { - sinon.stub(esmUtils, 'doImport').resolves({}); - }); - - afterEach(function () { - sinon.restore(); + describe('requireOrImport', function () { + it('should show an informative error message for a broken default import', async function () { + return expect( + () => + esmUtils.requireOrImport( + '../../test/node-unit/fixtures/broken-default-import.mjs' + ), + 'to be rejected with error satisfying', + { + name: 'SyntaxError', + message: + "The requested module './module-without-default-export.mjs' does not provide an export named 'default'" + } + ); + }); }); describe('loadFilesAsync()', function () { + beforeEach(function () { + sinon.stub(esmUtils, 'doImport').resolves({}); + }); + + afterEach(function () { + sinon.restore(); + }); + it('should not decorate imported module if no decorator passed', async function () { await esmUtils.loadFilesAsync( ['/foo/bar.mjs'], diff --git a/test/node-unit/fixtures/broken-default-import.mjs b/test/node-unit/fixtures/broken-default-import.mjs new file mode 100644 index 0000000000..523103014e --- /dev/null +++ b/test/node-unit/fixtures/broken-default-import.mjs @@ -0,0 +1,3 @@ +import moduleWithoutDefaultExport from './module-without-default-export.mjs'; + +moduleWithoutDefaultExport; diff --git a/test/node-unit/fixtures/module-without-default-export.mjs b/test/node-unit/fixtures/module-without-default-export.mjs new file mode 100644 index 0000000000..46d3ca8c61 --- /dev/null +++ b/test/node-unit/fixtures/module-without-default-export.mjs @@ -0,0 +1 @@ +export const value = 42;