diff --git a/lib/esm-utils.js b/lib/esm-utils.js index 604f883d9a..eebeb9322b 100644 --- a/lib/esm-utils.js +++ b/lib/esm-utils.js @@ -3,7 +3,29 @@ const url = require('url'); const formattedImport = async file => { if (path.isAbsolute(file)) { - return import(url.pathToFileURL(file)); + try { + return await import(url.pathToFileURL(file)); + } catch (err) { + // This is a hack created because ESM in Node.js (at least in Node v15.5.1) does not emit + // the location of the syntax error in the error thrown. + // This is problematic because the user can't see what file has the problem, + // so we add the file location to the error. + // This `if` should be removed once Node.js fixes the problem. + if ( + err instanceof SyntaxError && + err.message && + err.stack && + !err.stack.includes(file) + ) { + const newErrorWithFilename = new SyntaxError(err.message); + newErrorWithFilename.stack = err.stack.replace( + /^SyntaxError/, + `SyntaxError[ @${file} ]` + ); + throw newErrorWithFilename; + } + throw err; + } } return import(file); }; diff --git a/test/integration/esm.spec.js b/test/integration/esm.spec.js index 20b3a27248..f1de91dfb5 100644 --- a/test/integration/esm.spec.js +++ b/test/integration/esm.spec.js @@ -1,5 +1,7 @@ 'use strict'; -var run = require('./helpers').runMochaJSON; +var helpers = require('./helpers'); +var run = helpers.runMochaJSON; +var runMochaAsync = helpers.runMochaAsync; var utils = require('../../lib/utils'); var args = +process.versions.node.split('.')[0] >= 13 ? [] : ['--experimental-modules']; @@ -38,6 +40,17 @@ describe('esm', function() { }); }); + it('should show file location when there is a syntax error in the test', async function() { + var fixture = 'esm/syntax-error/esm-syntax-error.fixture.mjs'; + const err = await runMochaAsync(fixture, args, {stdio: 'pipe'}).catch( + err => err + ); + expect(err.output, 'to contain', 'SyntaxError').and( + 'to contain', + 'esm-syntax-error.fixture.mjs' + ); + }); + it('should recognize esm files ending with .js due to package.json type flag', function(done) { if (!utils.supportsEsModules(false)) return this.skip(); diff --git a/test/integration/fixtures/esm/syntax-error/esm-syntax-error.fixture.mjs b/test/integration/fixtures/esm/syntax-error/esm-syntax-error.fixture.mjs new file mode 100644 index 0000000000..c9c23b9634 --- /dev/null +++ b/test/integration/fixtures/esm/syntax-error/esm-syntax-error.fixture.mjs @@ -0,0 +1,3 @@ +// This is intentionally a syntax error +it('should never run because of a syntax error here', => { +});