Repository navigation
Feature Request: Module level mocking #51164
Description
Activity
- addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.
on Dec 15, 2023 When I was searching for a workaround, how to mock imports with the native test runner I found this looking very similar:
https://github.com/nodejs/node/blob/main/test/es-module/test-esm-loader-mock.mjs
I can't tell if this is already integrated, just missing the new types in @types/node?
It's already possible to mock things as the test linked below using the experimental Customization Hook API (https://nodejs.org/api/module.html#customization-hooks). Note that it should work only on Node.js 18.19+/20.6+.
Here are the files to set it up, and as you can see, it's only using public APIs:
https://github.com/nodejs/node/blob/6a5394ea7dc62b044ed826a7c8d18506ab532b96/test/fixtures/es-module-loaders/mock.mjs
https://github.com/nodejs/node/blob/6a5394ea7dc62b044ed826a7c8d18506ab532b96/test/fixtures/es-module-loaders/mock-loader.mjsReacted by Jrson, Albert Mañosa and dolphin278It's already possible to mock things as the test linked below using the experimental Customization Hook API (https://nodejs.org/api/module.html#customization-hooks)
This information should be added to the test runner docs. I was searching for a working solution to mock modules for days.
Reacted by Albert Mañosa, Ivo Janssen, Ronan Jouchet and Thomas RosenauIt's already possible to mock things as the test linked below using the experimental Customization Hook API. Note that it should work only on Node.js 18.19+/20.6+.
Here are the files to set it up, and as you can see, it's only using public APIs: test/fixtures/es-module-loaders/mock.mjs , test/fixtures/es-module-loaders/mock-loader.mjs
@aduh95 thanks, but these files leave me confused. The path of these things
.../test/fixtures/es-module-loaders/...suggests this is ESM setup for Nodejs' own tests, right?If so, then are we supposed to replicate such a weighty setup in every project where we want to mock module methods? Or do you know if a nicer/lighter way will end up shipping to test_runner? Is there a reason it's not exposed yet, or is the reason merely "because nobody shipped it yet"?
The path of these things
.../test/fixtures/es-module-loaders/...suggests this is ESM setup for Nodejs' own tests, right?Not at all, it's a test that validates mocking of module works (and keeps working). Node.js own tests do not need mocking.
If so, then are we supposed to replicate such a weighty setup in every project where we want to mock module methods? Or do you know if a nicer/lighter way will end up shipping to test_runner? Is there a reason it's not exposed yet, or is the reason merely "because nobody shipped it yet"?
Well nobody shipped it yet indeed, I haven't tried myself so I can't tell you what would be the road blockers. I think it should be feasible to create an npm package that exposes a mock API.
Reacted by Ronan JouchetThx @aduh95, understood.
Note to future self and passerbys: there’s similar discussion and links on stubbing ESM modules at sinonjs/sinon#1832, some of it is probably useful outside of Sinon and in the context of mocking with Node-builtin
t.mock.Reacted by ctorres-lynxlabsFrom https://cjihrig.com/test_runner_wishlist_2024 (2024-01-09):
I have put together a short wishlist of improvements that I would love to see in Node's test runner even though I have moved on from Node.js myself.
Module mocking is something that I actually already implemented in a git branch. However, mocking ESM, requires using Node's experimental module customization hooks. These experimental APIs were changing pretty drastically while I was working on module mocking, and in my opinion, they are still not adequate for building a stable module mocking API in Node's test runner.
I hope someone is willing to fight the uphill battle of adding these features to core.
Hooks are RC in 21. Not sure how current Colin's opinion is since wip branch is from August 2023.
Thank you Colin and everyone else who led me here. Open source can be hard.
- addedtest_runnerIssues and PRs related to the test runner subsystem.Issues and PRs related to the test runner subsystem.
on Apr 3, 2024 Just a heads up - I plan to resume working on this. It will need to be an experimental feature though until the underlying modules APIs stabilize.
Reacted by Ronan Jouchet, Roberto Bianchi, Moshe Atlow, Michał Drobniak, Jrson, Ken Smith, Alex Yang, Richard Phipps, Ricardo Garim, Mehul Kar and 4 moreI made a simple script to replace a module to fixtures files
- dist - index.js - fixtures - index.ts - tests - index.test.ts// mock-module.js import { stat } from "node:fs/promises"; import { join, relative } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; const packageDistDir = fileURLToPath(new URL("./dist", import.meta.url)); const fixturesDir = fileURLToPath(new URL("./fixtures", import.meta.url)); export async function resolve(specifier, context, nextResolve) { const result = await nextResolve(specifier, context); if (result.format === "builtin" || result.url.startsWith("node:")) { return result; } const targetUrl = fileURLToPath(result.url).replace(/\.js$/, ".ts"); const relativePath = relative(packageDistDir, targetUrl); if (relativePath.startsWith(".") || relativePath.startsWith("/")) { return result; } const url = pathToFileURL(join(fixturesDir, relativePath)).toString(); const exist = await stat(fileURLToPath(url)) .then((stat) => stat.isFile()) .catch((err) => { if (err.code === "ENOENT") { return false; } throw err; }); if (!exist) { return result; } return { url, format: "module", }; }
// mock-register.js import { register } from "node:module"; register("./mock-module.js", import.meta.url);
node --import tsx --import ./mock-register.js --test ./tests/index.test.ts
- Reacted by Steven
- added a commit that references this issue
on May 19, 2024 - added a commit that references this issue
on Jun 1, 2024 - added a commit that references this issue
on Jun 20, 2024 - added a commit that references this issue
on Sep 21, 2024
What is the problem this feature will solve?
Currently you can't mock external or built-in modules which makes it difficult if you code imports a module that may run some side-effects and you have no control over it.
There may be some built in modules which you need to stub out but don't have access to during a test run.
What is the feature you are proposing to solve the problem?
Allowing us to use the built-in test runner to mock modules entirely.
There has already been some work in this by @cjihrig
I think the biggest things missing before I can open a PR are related to ESM loaders and are tracked in #49472 and #49473.
Both of those issues look to be resolved now, I don't know what the current blockers are for this
What alternatives have you considered?
No response