Description
I am reporting what I consider to be a bug.
Originally reported in facebook/create-react-app#1271.
Some people use NODE_PATH
to enable "absolute imports" in their codebase. For example, running NODE_PATH=. npm test
makes every file and folder in the top-level directory available as require('name')
rather than require('./name')
.
Current behavior
This approach works fine with Jest, but the mocking behavior is a bit confusing. jest.mock()
only works with it correctly when jest.mock()
matches the require
. In other words, jest.mock('./a')
will only work for files that happen to require('./a')
but not for the ones that require('a')
. Conversely, jest.mock('a')
will only work for files that do require('a')
but not require('./a')
. Since both are possible when one sets NODE_PATH
, it can be tricky to figure out what went wrong, and why jest.mock
doesn't always work.
Expected behavior
When NODE_PATH
is used, and a
is a file or folder in that directory, both jest.mock('a')
and jest.mock('./a')
work the same way, and mock both require('a')
and require('./a')
calls.
Repro
git clone https://github.com/gaearon/jest-mock-issue-repro.git
cd jest-mock-issue-repro
npm i
npm test
See that the test fails. Open index.test.js
and index.js
.
Observe that jest.mock('./a', () => 'goodbye, ');
only works if there's a require('./a')
in index.js
, and jest.mock('a', () => 'goodbye, ');
only works if there's a require('a')
in index.js
.
I would expect that both work in both cases, and are considered equivalent, because they ultimately resolved to the same module.
What Does Node Do?
One could argue that it's intentional behavior because ./a
and a
are different paths, and Node is known to treat different paths as different modules, so Jest should do the same.
However I don't think this is the case with NODE_PATH
.
With code like this:
require('./a');
require('./A');
Node will indeed execute the module twice.
However, with NODE_PATH=.
and calls like this:
require('a');
require('./a');
Node will still execute the module just once. This means that the module ID should be based on path after resolving, and I argue that jest.mock()
should also treat them as the same module.