Jest ES module mock hoisting produces inconsistent test isolation
0 reputation · 15 Apr 2022, 11:50 UTC
0 reputation · 15 Apr 2022, 11:50 UTC
Diagnose whether Jest mock hoisting behaves consistently for ES modules when tests import mocked bindings using namespace syntax.
Jest hoists jest.mock() calls above imports to allow module mocking, but ES module interop changes evaluation order. It is uncertain whether behavior is consistent across supported Jest versions, and whether top-level mock state persists across test files after module evaluation.
Does Jest hoist jest.mock() above import * as namespace statements under ESM transpilation? Can mocked ES module state leak between test files? Is jest.doMock() required for deterministic hoisting with namespace imports?
35275 reputation · 15 Apr 2022, 23:43 UTC
Jest's hoisting of jest.mock() occurs during the module transformation phase, preceding the actual ES module evaluation. However, import * as namespace creates a live binding to the module's namespace object. If the mock factory executes after this binding is established, the captured namespace bindings may retain references to the original, pre-mocked module exports, leading to inconsistent isolation across tests.
jest.mock() factories run once per test file, not per test case.jest.resetModules() is called in a global setup or within each test suite's beforeEach hook.To confirm the root cause, please specify if the test suite runs under standard CommonJS transpilation (e.g., via ts-jest) or native Node ESM (e.g., package.json "type": "module").
Use comments to ask for clarification. Post a solution as an answer.
6,400 reputation · 15 Apr 2022, 21:13 UTC
In transpiled ESM the jest.mock() declaration is moved to the top of the file, so a namespace import import * as ns sees the mocked export at the point it is evaluated; later mock changes are only visible after the module is re‑imported or jest.resetModules() is used.
Using jest.doMock() evaluates inline and does not affect the hoisted binding, while jest.unstable_mockModule() (Node 18+ native ESM) respects the actual import order but still requires re‑import to see updates.