🐛 Bug: esm-utils (mocha.addFile) should support URL
envgap__mochajs__mocha-4993
01 / FAILURE SIGNATURE
As reported upstream
Error: Cannot find module '/path/to/project/file:/path/to/project/suite.js'
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
fbd831e9c93e2a704bfa5dca587eb3e664569414- Manifest
package.json- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / ORIGINAL ISSUE TEXT
mochajs/mocha #4993 · read the original issue
### Prerequisites
<!--
Place an `x` between the square brackets on the lines below for every satisfied prerequisite.
-->
- [x] Checked that your issue hasn't already been filed by cross-referencing [issues with the `faq` label](https://github.com/mochajs/mocha/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq%20)
- [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_modules/.bin/mocha --version`(Local) and `mocha --version`(Global). We recommend that you _not_ install Mocha globally.
### Description
According to the official Node.js documentation, ES modules are resolved and cached as URLs. However, `esm-utils` does not support loading files from a URL.
Reference: https://nodejs.org/docs/latest-v18.x/api/esm.html#urls
### Steps to Reproduce
1. Initialize a new project: `npm init -y` (make sure to use a recent version of Node >= 18)
2. Install Mocha 10.2.0: `npm i mocha@10.2.0 --save`
3. Add `type": "module"` in `package.json`
5. Create two files:
*index.js*
```js
import Mocha from 'mocha'
import ospath from 'node:path'
const mocha = new Mocha()
mocha.addFile(`file://${ospath.resolve('./suite.js')}`)
await mocha.loadFilesAsync()
mocha.run((failures) => {
console.log({failures, stats: runner.stats})
})
```
*suite.js*
```js
describe('Suite', () => {
it('should run', () => {
// OK
})
})
```
6. `node index.js`
```
node /path/to/project/index.js
node:internal/modules/cjs/loader:1026
const err = new Error(message);
^
Error: Cannot find module '/path/to/project/file:/path/to/project/suite.js'
Require stack:
- /path/to/project/node_modules/mocha/lib/nodejs/esm-utils.js
- /path/to/project/node_modules/mocha/lib/mocha.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1026:15)
at Function.Module._load (node:internal/modules/cjs/loader:871:27)
at Module.require (node:internal/modules/cjs/loader:1098:19)
at require (node:internal/modules/cjs/helpers:108:18)
at Object.exports.requireOrImport (/path/to/project/node_modules/mocha/lib/nodejs/esm-utils.js:53:16)
at async Object.exports.loadFilesAsync (/path/to/project/node_modules/mocha/lib/nodejs/esm-utils.js:100:20)
at async file:///path/to/project/index.js:6:1 {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/path/to/project/node_modules/mocha/lib/nodejs/esm-utils.js',
'/path/to/project/node_modules/mocha/lib/mocha.js'
]
}
```
Using `.mjs` extension does fail as well:
```
node /path/to/project/index.js
node:internal/errors:478
ErrorCaptureStackTrace(err);
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/path/to/project/file:/path/to/project/suite.mjs' imported from /path/to/project/node_modules/mocha/lib/nodejs/esm-utils.js
at new NodeError (node:internal/errors:387:5)
at finalizeResolution (node:internal/modules/esm/resolve:330:11)
at moduleResolve (node:internal/modules/esm/resolve:907:10)
at defaultResolve (node:internal/modules/esm/resolve:1115:11)
at nextResolve (node:internal/modules/esm/loader:163:28)
at ESMLoader.resolve (node:internal/modules/esm/loader:841:30)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
at ESMLoader.import (node:internal/modules/esm/loader:525:22)
at importModuleDynamically (node:internal/modules/cjs/loader:1134:29)
at importModuleDynamicallyWrapper (node:internal/vm/module:438:21) {
code: 'ERR_MODULE_NOT_FOUND'
}
```
**Expected behavior:**
Mocha should be able to load ES modules from URL (`file://`).
**Actual behavior:**
Module is not found :(
**Reproduces how often:**
100%
### Versions
- The output of `mocha --version` and `node_modules/.bin/mocha --version`: 10.2.0
- The output of `node --version`: v18.16.1
- Your operating system
- name and version: Ubuntu 22.04
- architecture (32 or 64-bit): 64-bit
- Your shell (e.g., bash, zsh, PowerShell, cmd): bash
### Additional Information
It should also support query parameters and fragments. That's particularly useful when you want to load a test suite more than once:
```js
const mocha = new Mocha()
mocha.addFile(`file://${ospath.resolve('./suite.js')}?time=${Date.now()}`)
await mocha.loadFilesAsync()
```
Otherwise, the file will be loaded only on the first `mocha` instance:
```js
const mocha = new Mocha()
mocha.addFile(`file://${ospath.resolve('./suite.js')}`)
await mocha.loadFilesAsync()
// mocha has a test suite
const mocha1 = new Mocha()
mocha1.addFile(`file://${ospath.resolve('./suite.js')}`)
await mocha1.loadFilesAsync()
// mocha1 has no test suite because suite.js was not loaded again!
```
Please note that `mocha.dispose`, `mocha.unloadFiles` has no effect (as mentioned in the JSDoc):
> Note: does not clear ESM module files from the cache
Thanks!
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]