镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Feature Request: Module level mocking #51164

Description

@jasonwilliams

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

Activity

  1. jrson83 commented on Dec 16, 2023

    @jrson83

    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?

  2. aduh95 commented on Dec 24, 2023

    @aduh95
    Contributor

    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.mjs

  3. jrson83 commented on Dec 24, 2023

    @jrson83

    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)

    This information should be added to the test runner docs. I was searching for a working solution to mock modules for days.

  4. ronjouch commented on Jan 15, 2024

    @ronjouch

    It'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"?

  5. aduh95 commented on Jan 15, 2024

    @aduh95
    Contributor

    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.

  6. ronjouch commented on Jan 16, 2024

    @ronjouch

    Thx @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.

  7. hparra commented on Apr 3, 2024

    @hparra

    From 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.

  8. added
    test_runnerIssues and PRs related to the test runner subsystem.
    on Apr 3, 2024
  9. cjihrig commented on Apr 3, 2024

    @cjihrig
    Contributor

    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.

  10. himself65 commented on Apr 7, 2024

    @himself65
    Member

    I 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
  11. cjihrig commented on May 5, 2024

    @cjihrig
    Contributor
  12. added a commit that references this issue on Jun 1, 2024
  13. moved this from Awaiting Triage to Done in Node.js feature requestson Jul 1, 2024
  14. added a commit that references this issue on Sep 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues requesting new Node.js features.test_runnerIssues and PRs related to the test runner subsystem.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions