Skip to content

🐛 Bug: Node.js v23 testing with .ts files #5314

@legendecas

Description

@legendecas

Bug Report Checklist

  • I have read and agree to Mocha's Code of Conduct and Contributing Guidelines
  • I have searched for related issues and issues with the faq label, but none matched my issue.
  • I have '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, my usage of Mocha, or Mocha itself.
  • I want to provide a PR to resolve this

Expected

Minimal reproduction repo: https://github.com/legendecas/mocha-register-node-v23

  • Test with @babel/register, with typescript preset
  • Test with ts-node

Run npm test should pass in either Node.js v23, or Node.js v22.

Actual

Node.js v22 passes the test.

Node.js v23 fails with error:

(node:51969) Warning: Failed to load the ES module: /Developer/notebook/mocha-register/test/mytest.test.ts. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)

 Exception during run: /Developer/notebook/mocha-register/test/mytest.test.ts:1
import { foo } from './mymod';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at loadCJSModule (node:internal/modules/esm/translators:122:25)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:207:7)
    at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
    at async formattedImport (/Developer/notebook/mocha-register/node_modules/mocha/lib/nodejs/esm-utils.js:9:14)
    at async Object.exports.requireOrImport (/Developer/notebook/mocha-register/node_modules/mocha/lib/nodejs/esm-utils.js:42:28)
    at async Object.exports.loadFilesAsync (/Developer/notebook/mocha-register/node_modules/mocha/lib/nodejs/esm-utils.js:100:20)
    at async singleRun (/Developer/notebook/mocha-register/node_modules/mocha/lib/cli/run-helpers.js:162:3)
    at async Object.exports.handler (/Developer/notebook/mocha-register/node_modules/mocha/lib/cli/run.js:375:5)

Minimal, Reproducible Example

Minimal reproduction repo: https://github.com/legendecas/mocha-register-node-v23

Existing ts projects can be written in module syntax for static analysis and transpiled to CJS. These workflows assume that these TS files are loaded as CJS modules. However, in this case, mocha will try to import a .ts file first, and try require if import fails, and a default enabled ts loader takes precedence over user configuered CJS loader.

exports.requireOrImport = async (file, esmDecorator) => {
if (path.extname(file) === '.mjs') {
return formattedImport(file, esmDecorator);
}
try {
return dealWithExports(await formattedImport(file, esmDecorator));
} catch (err) {
if (
err.code === 'ERR_MODULE_NOT_FOUND' ||
err.code === 'ERR_UNKNOWN_FILE_EXTENSION' ||
err.code === 'ERR_UNSUPPORTED_DIR_IMPORT'
) {
try {
// Importing a file usually works, but the resolution of `import` is the ESM
// resolution algorithm, and not the CJS resolution algorithm. We may have
// failed because we tried the ESM resolution, so we try to `require` it.
return require(file);

Alternatives:

  • Use --no-experimental-strip-types in user code.
  • Use package.json#type to determine import/require which should be used to load a test file first in mocha.
  • Node.js ESM loader should also respect require.extensions?

Just throwing ideas. /cc @marco-ippolito

Versions

  • mocha --version: 11.1.0
  • node_modules/.bin/mocha --version: 11.1.0
  • node --version: v23.10.0

Additional Info

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: accepting prsMocha can use your help with this one!type: buga defect, confirmed by a maintainer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions