'node + ts-jest + ESM, jest.mock doing nothing

I am using ts-jest with ESM imports on nodejs.
The problem is that my jest.mock is not working, it is not mocking.

import { jest } from "@jest/globals";

jest.mock("./helpers"); // I tried before or after import
import { fn } from "./helpers";


describe("SimpleTest", () => {
  it("should work", () => {
    console.log(fn); // => defined
    console.log(fn.mockReturnValue); // => /!\ UNDEFINED, fn is not a jest mock.
  });
});

My jest config:

export default {
  preset: "ts-jest/presets/default-esm",
  extensionsToTreatAsEsm: [".ts"],
  globals: {
    "ts-jest": {
      useESM: true,
    },
  },
}

The command I use:
node --experimental-vm-modules --experimental-specifier-resolution=node $(yarn bin jest)

I am using node v16.13.2 and ts-jest 27.1.3



Solution 1:[1]

jest.mock works for CJS, but not for ESM.

There is a jest.unstable_mockModule and an opened PR to turn it into a stable API, but it's in limbo (Jest author lost motivation).

For more details:

Some valuable comments in the issue might help you find a partial solution.

It didn't work for me. I gave up on it and went a different route altogether.

Solution 2:[2]

This is a known issue (as mentioned in https://github.com/facebook/jest/issues/10025).

Basically, the issue is that Jest can't hoist the mock before all other imports as it does using babel (https://github.com/facebook/jest/issues/10025#issuecomment-920401080). Using a top-level await along with jest.unstable_mockModule worked for me.

Just to note the example using jest.unstable_mockModule:

import { jest } from "@jest/globals";

const mockFn = jest.fn();
jest.unstable_mockModule("./helpers", () => ({
  fn: mockFn
}));
const { fn } = await import("./helpers"); // Needs to be after the mock is declared.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Zdenek F
Solution 2 Chris Hsu