Open harvzor opened 1 month ago
This works:
import { jest } from '@jest/globals';
jest.unstable_mockModule('../foo-bar-baz', () => {
return {
bar: () => 'mocked bar',
};
});
const { bar } = await import('../foo-bar-baz');
test('should do a partial mock', () => {
expect(bar()).toBe('mocked bar');
});
Docs for unstable_mockModule
are available here: https://jestjs.io/docs/ecmascript-modules#module-mocking-in-esm
Trying to make the implementation exactly the same as in the original example, I think this is the correct code:
import { jest } from '@jest/globals';
jest.unstable_mockModule('../foo-bar-baz', async () => {
const originalModule = await import('../foo-bar-baz');
return {
...originalModule,
default: jest.fn(() => 'mocked baz'),
foo: 'mocked foo',
};
});
const { default: defaultExport, bar, foo } = await import('../foo-bar-baz');
test('should do a partial mock', () => {
const defaultExportResult = defaultExport();
expect(defaultExportResult).toBe('mocked baz');
expect(defaultExport).toHaveBeenCalled();
expect(foo).toBe('mocked foo');
expect(bar()).toBe('bar');
});
However, the test never finishes. Seems this issue was reported a while ago: https://github.com/jestjs/jest/issues/13851
As you see CJS has jest.requireActual()
, but it can’t work in ESM. Similar async method for imports is needed as mentioned in the meta issue: #9430
It seems that https://github.com/jestjs/jest/issues/10025 is tracking a potential fix for this issue (since 2020)
Since requireActual()
does not work with partial ES6 module mocks, probably the documentation should say this.
Should I make a PR?
Similar code works in Vitest using a special method called importOriginal()
: https://stackblitz.com/edit/vitejs-vite-fcr3z9
Vitest supports partial mocks but has a caveat that's well explained in the docs:
It is not possible to mock the foo method from the outside because it is referenced directly. So this code will have no effect on the foo call inside foobar (but it will affect the foo call in other modules):
And then goes on to write:
This is the intended behaviour. It is usually a sign of bad code when mocking is involved in such a manner.
https://vitest.dev/guide/mocking.html#mocking-pitfalls
Probably partial mocks should be generally avoided.
require()
does not work in ESM as well as requireActual()
. It might make sense to mention that partial mocking is not yet supported, but that is mentioned in #9430 and the ECMAScript Modules page already links to this issue. In a way several features are not yet working. Not sure if it worth mentioning them in documentation.
As a side note. Jest and Vitest have very different approach to ESM. In Jest a plain JavaScript ESM is simply executed, in Vitest you will see transform time being reported. I don’t know what is that transformation about, but that is: 1. waste of time; 2. not ESM as implemented by Node.js (for instance require
global gets injected).
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.
Version
29.7.0
Steps to reproduce
Stackblitz playground: https://stackblitz.com/edit/stackblitz-starters-nybxbq
Result:
Follow the documentation available here: https://jestjs.io/docs/mock-functions#mocking-partials
./foo-bar-baz.js
:./tests/test.js
:package.json
is configured correctly (so Jest works with ES6 modules):npm test
Expected behavior
defaultExportResult()
should returnmocked baz
instead ofbaz
Actual behavior
Test fails, and it appears the mocks simply aren't run:
Additional context
Pulling down the StackBlitz and running it locally produces the same result.
Also, in my own repository, I have this same issue.
Environment
This is what my local environment reports:
This is what StackBlitz reports: