Mocha: support ESM in watch mode

Created on 14 Jul 2020  路  3Comments  路  Source: mochajs/mocha

Prerequisites

  • [x] Checked that your issue hasn't already been filed by cross-referencing issues with the faq label
  • [x] Checked next-gen ES issues and syntax problems by using the same environment and/or transpiler configuration without Mocha to ensure it isn't just a feature that actually isn't supported in the environment in question or a bug in your code.
  • [x] 'Smoke tested' the code to be tested by running it outside the real test suite to get a better sense of whether the problem is in the code under test, your usage of Mocha, or Mocha itself
  • [x] Ensured that there is no discrepancy between the locally and globally installed versions of Mocha. You can find them with: node node_modules/.bin/mocha --version(Local) and mocha --version(Global). We recommend that you _not_ install Mocha globally.

Description

When running --watch within a package that has "type": "module" set in its package.json, Mocha fails to properly import, instead attempting to require() the file.

$ npm run test-mocha:watch

> @ test-mocha:watch /home/jdalrymple/src/bugs/mochajs
> mocha --require @babel/register $(find ./src -type f -name '*.test.js') --watch

internal/modules/cjs/loader.js:1217
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
      ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /.../src/index.test.js
require() of ES modules is not supported.
require() of /.../src/index.test.js from /.../node_modules/mocha/lib/mocha.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.test.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /.../package.json.

    at Module._extensions..js (internal/modules/cjs/loader.js:1217:13)
    at Object.newLoader [as .js] (/home/jdalrymple/src/bugs/mochajs/node_modules/pirates/lib/index.js:104:7)
    at Module.load (internal/modules/cjs/loader.js:1050:32)
    at Function.Module._load (internal/modules/cjs/loader.js:938:14)
    at Module.require (internal/modules/cjs/loader.js:1090:19)
    at require (internal/modules/cjs/helpers.js:75:18)
    at /home/jdalrymple/src/bugs/mochajs/node_modules/mocha/lib/mocha.js:384:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/home/jdalrymple/src/bugs/mochajs/node_modules/mocha/lib/mocha.js:381:14)
    at Mocha.run (/home/jdalrymple/src/bugs/mochajs/node_modules/mocha/lib/mocha.js:954:10)
    at Object.run (/home/jdalrymple/src/bugs/mochajs/node_modules/mocha/lib/cli/watch-run.js:223:20)
    at FSWatcher.<anonymous> (/home/jdalrymple/src/bugs/mochajs/node_modules/mocha/lib/cli/watch-run.js:169:14)
    at FSWatcher.emit (events.js:314:20)
    at /home/jdalrymple/src/bugs/mochajs/node_modules/mocha/node_modules/chokidar/index.js:364:35
    at processTicksAndRejections (internal/process/task_queues.js:75:11) {
  code: 'ERR_REQUIRE_ESM'
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ test-mocha:watch: `mocha --require @babel/register $(find ./src -type f -name '*.test.js') --watch`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ test-mocha:watch script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/jdalrymple/.npm/_logs/2020-07-14T00_20_36_063Z-debug.log

Steps to Reproduce

For convenience, the following respository was created that adequately reproduces the issue:

  1. Ensure your node version matches the one listed below
  2. Clone the repo: https://github.com/Swivelgames/issues-mochajs-4374
  3. Install its dependencies: npm i
  4. Test the repo: npm run test-mocha
  5. Start a watch: npm run test-mocha:watch

Expected Behavior:

  • Mocha would begin watching the files

Actual Behavior:

  • Error is thrown when attempting to watch files

Versions

Package Versions
  • node: v14.5.0
  • mocha: 8.0.1
  • babel: v7.10.4
Environment
  • OS: Linux, Arch, x86_64
  • Shell: tmux + zsh

Additional Information

It is my understanding that the following scenarios are applicable:

import should be used under the following conditions:

  • If the target file's associated package.json file contains "type": "module" and its file extension is .js
  • If the target file's extension is .mjs, regardless of what is inside its associated package.json file

require() should be used under the following conditions:

  • If the target file's associated package.json file does NOT contain "type": "module" and its file extension is .js
  • If the target file's extension is .cjs, regardless of what is inside its associated package.json file

Conclusion

Presently, it appears as though --watch is assuming the target file is a CommonJS module when its extension is .js, and failing to yield to its package.json file's "type": "module".

Considerations

It's worth considering the fact that the package.json file associated with the file being imported may be different than the package.json in the directory that mocha is being called, even in the event that the target file's path does not include node_modules.

feature needs-upstream-fix

Most helpful comment

@Swivelgames Have you tried --parallel combined with --watch? It might work, since we dump the workers after each run, but I don't think we are testing it anywhere yet.

All 3 comments

Please see our docs: current limitations.

We do not (yet?) support ESModules in watch mode. Node's ESM implementation is using its separate cache (not require.cache), which currently can't be cleared before re-running the tests in watch mode.

@Swivelgames Have you tried --parallel combined with --watch? It might work, since we dump the workers after each run, but I don't think we are testing it anywhere yet.

@boneskull I'm not @Swivelgames but your suggestion of adding --parallel works for me. Thanks!

Was this page helpful?
0 / 5 - 0 ratings