I use jest with webpack. Webpack is configured to use alias for some imports:
alias: {
shared: path.resolve(process.cwd(), "some-lib/src"),
},
modules: ["app", "node_modules", "some-lib"],
some-lib
is git submodule added to the project.
part of Jest config from package.json
:
"moduleDirectories": [
"node_modules",
"app",
"shared-lib"
],
"modulePaths": ["<rootDir>/shared-lib"],
"moduleNameMapper": {
"^api(.*)$": "<rootDir>/shared-lib/src$1"
},
When I'm trying to mock imported module in jest it doesn't work
jest.mock("shared/utils")
import { utilFunc } from "shared/utils"
as a result utilFunc
is unmocked.
I'm using the latest version of jest.
I think "it works" but it's broken maybe?
// src/moduleWithSomethingToMock.js
import moduleToMock from '../../rootAlias/helpers/moduleToMock';
import moduleWithSomethingToMock from './moduleWithSomethingToMock';
// Here I'm using the alias
jest.mock('rootAlias/helpers/moduleToMock');
// src/moduleWithSomethingToMock.js
// Here I'm using the alias
import moduleToMock from 'rootAlias/helpers/moduleToMock';
import moduleWithSomethingToMock from './moduleWithSomethingToMock';
// Using or not the alias, it doesn't mock the module
jest.mock('rootAlias/helpers/moduleToMock');
Does it happen on jest@test
?
It does 馃樋
If someone can find it interesting: in my case the problem was that the order of entries in moduleNameMapper
was wrong... Children should always be before parents in that list.
I had experienced similar issues with jest v20.0.4 upgrading to v22.2.2 solved that issue.
We're hitting this issue as well - upgrading to 22.2.2 or downgrading to 20.0.4 didn't work.
Some details:
jest.mock()
jest-runtime.requireMock()
. Specifically:manualMock
gets set to null, which eventually calls this._generateMock(from, moduleName);
manualMock
gets set to the absolute FS path (even though this isn't a manual mock). This causes _generateMock
to not be called.manualMock
is a string/path, and in other cases (inside if (fs.existsSync(potentialManualMock))
) it's a boolean with the path in modulePath
.Unfortunately, that's as far as I got. I attempted a fix but since I've only started working with this framework every change I made broke a bunch of tests...
Hopefully this helps someone find the true fix. I'm also happy to help put in a PR with some direction on what the fix should be.
First and foremost, thanks to @timtrinidad for the workaround (passing a factory to jest.mock()
).
Second, expanding on what @timtrinidad found, I'm on 22.4.0 of jest-runtime
and took a look. The code does roughly the following:
manualMock
is resolved to a path by this._resolver.getMockModule(from, moduleName);
this._mockRegistry
.this._mockFactories
and calls (and returns) it if there is._gracefulFs
is used to check if there's a manual mock defined in a __mocks__
directory and if there is, manualMock is set to true
(a boolean rather than a string) and modulePath
is changed to the path to the manually mocked module.modulePath
(it's never falsy unless there's no moduleName
which... unlikely) and if it's truthy, executes the module at module at module path with this._execModule()
. The newly minted module (the real thing, not a mock), is then registered with the mock registry.So, there's a couple problems here. First, at step 4, it's determined whether or not we're dealing with a manual mock. In the use case that we're discussing here, we're not. But manualMock
is never set to something falsy. Easy fix; just add an else to the conditional. That calls this._generateMock()
which is the method we want called.
However, we have a new problem. The first line of _generateMock(from, moduleName)
is const modulePath = this._resolveModule(from, moduleName);
. That method call eventually kicks things to the jest-resolver
method resolveModule()
which in turn calls this.getModule()
. That method tries to find the module, but doesn't take into account the moduleNameMapper
configuration. So, this.getModule()
returns null
and then resolveModule()
blows up and the module can't be loaded. Tests explode. People run screaming. Chaos reigns.
I took a walk and tried something when I got back. I changed this._generateMock(from, moduleName)
to this._generateMock(from, modulePath);
and it works.
Rolled the two lines I changed back and working on a test. Hopefully I'll have a PR shortly.
Having trouble running the tests. Reached out on discord. Once I can sort that out, I can submit the PR.
I can't get the tests to run on my machine and haven't had any luck getting help with them. I was able to run them with my changes on Travis and my change breaks other things. Without being able to run them locally, it'll take way more time than is worth it to get a fix that doesn't break the existing tests. So, I'm shelving this for the time being.
Does anyone have any new information about this, or know whether it's going to be fixed before the next release? The same problem occurs when using a custom resolver. We use aliases/nonrelative paths almost exclusively so this is a big issue for us adopting jest. As of 23.0.0-charlie.2
it's still not working for me.
jest.mock('some/module')
is able to resolve the module (e.g. does not throw an error) but it doesn't get automocked; the original is still used. Using an inline mock works, e.g.
jest.mock('some/module', () => {
return {
foo: jest.fn()
};
});
I've tried to reproduce it in isolation but haven't been able to yet, using both relative & aliased/rooted paths for the original import. So it's doesn't seem like it's quite as simple as how @alex-mironov initially observed it, or maybe it manifests differently for when using a custom resolver?
Additional info:
After a bit of tracing I think this is a result of circular dependencies, which while probably not good are valid in ES6 modules. If I can repro in isolation will file a specific issue.
Update:
Figured out the cause here. I'm not actually sure if this is a bug. I have a module that depends on another module which fails when loaded in the testing environment, because of globals that aren't defined. Automocking tries to load all the modules, and fails when it gets to a dependent module that fails while loading.
So for example
module1
-> depends on module2
module2
throws an error when loaded
The test code has
jest.mock('module2')
jest.mock('module1')
I would have expected that module2
wouldn't be loaded since I already mocked it. But during the resolution process of module1
, even though I've automocked module2
, it still loads it during this process, and it fails. If I provide a manual mock, it wouldn't try to load module2
so it works:
jest.mock('module2', () => { return {} });
jest.mock('module1')
This makes sense, in a way, but I guess a future enhancement might be to use an AST to parse the public API of mocked modules instead of trying to load them. Having to actually load a module to mock it seems likely to fail in some scenarios. It's possible I just don't understand how this feature is expected to be used.
Another enhancement would be to provide output that the test failed during the module resolution/mocking process-- it's not at all clear that's what's happening; when looking at the stack trace, it just looks like the module didn't get mocked, but it's actually failing while trying to load dependencies of the module during mocking.
In any event the problem I'm having doesn't seem to be related to this bug any more, so it's possible this has been fixed already.
Hello everyone, I just ran into this issue today. Is there anything I can do to help push this issue forward?
@jamietre
This makes sense, in a way, but I guess a future enhancement might be to use an AST to parse the public API of mocked modules instead of trying to load them. Having to actually load a module to mock it seems likely to fail in some scenarios.
That's doesn't really seem feasible - to actually support all ways of exports.bla =
, module.exports =
, module.exports.bla =
not to start with if (maybe) module.exports =
and whatever export
might be transpiled to from different dialects, seems to me like an endless rabbit hole. Maybe if we enforced export
syntax, but that isn't really widespread yet, especially for node_modules
. And having that constraint before proper ESM support in Jest also seems weird.
Another enhancement would be to provide output that the test failed during the module resolution/mocking process-- it's not at all clear that's what's happening; when looking at the stack trace, it just looks like the module didn't get mocked, but it's actually failing while trying to load dependencies of the module during mocking.
That makes a lot of sense to me, would you mind creating a PR for that? Maybe provide some hint that you might not be able to rely on automocking and that you have to provide a mock factory inline?
That's doesn't really seem feasible - to actually support all ways of exports.bla =, module.exports =, module.exports.bla = not to start with if (maybe) module.exports = and whatever export might be transpiled to from different dialects, seems to me like an endless rabbit hole. Maybe if we enforced export syntax, but that isn't really widespread yet, especially for node_modules. And having that constraint before proper ESM support in Jest also seems weird.
You're completely correct of course - I write almost exclusively ES201?/TypeScript these days and when I wrote that, in my mind, a module's public API would always be well-defined ;)
That makes a lot of sense to me, would you mind creating a PR for that? Maybe provide some hint that you might not be able to rely on automocking and that you have to provide a mock factory inline?
I can take a shot for sure when I get a little free time.
I've made a minimal example repo where the ModuleNameMapper does not resolve correctly for imports. https://github.com/Kruptein/jest-test-stuff
Running 'npm run test' results in:
Track.test has behaviour I expect but uses relative imports, whereas the TrackExpected.test is the behaviour with mapped names with wrong behaviour.
Additionally this output shows that something does not seem to resolve correctly:
```
Cannot find module '@@storage/track/Track' from 'TrackExpected.test.ts'
4 | it('', () => {
5 | const track = new Track();
> 6 | console.log( jest.genMockFromModule('@@storage/track/Track'))
| ^
7 | console.log( jest.genMockFromModule('../../../src/storage/track/Track'))
8 | // console.log(typeof track);
9 | // console.log(typeof (Track as any).mock);```
I have to confirm that currently Jest has serious issues with aliases defined in a webpack config:
jest.mock('aliased/module')
- doesn't do automockingjest.genMockFromModule('aliased/module')
- cannot find the moduleThis issue is 1.5 years old. Will it be ever fixed?
I can confirm I have the same problems stated by @pribilinskiy.
aliases defined in a webpack config
Jest does not support webpack aliases - you need to use moduleNameMapper
(which is what this issue is about).
That said, I dug into this a tiny bit, and I'm not sure why it fail 馃槄 However, I've put together a failing integration test based on @Kruptein's excellent reproduction (removing typescript and logging), so maybe it will lower the barrier for people wanting to send a PR to fix this 馃檪 Please see #7668
We import a shared _json_ file with aliases in _webpack.config.js_ and _jest.config.js_
I can try to tackle this one.
@grosto that would be awesome 馃憤
I was facing this issue with
{
"jest": "23.5.0",
"ts-jest": "23.1.3"
}
I just update both dependencies to 24.7.1 and 24.0.2 and solved
I'm having this issue with [email protected]
, [email protected]
and @vue/[email protected]
.
Adding moduleNameMapper: { '@/(.*)$': '<rootDir>/src/$1' }
to jest config doesn't make a difference...
UPDATE:
It seems I was looking at an error message due to a different reason.
Mocking modules with jest.mock('@/myPath')
actually works out of the box with vue-cli-plugin-unit-jest. You don't even need the moduleNameMapper
setting.
is there any solution for this issue
I have the same issue, want to use moduleNameMapper
to alias an external module, seems not to work
moduleNameMapper: {
'@stuff(.*)$': '@scope/stuff',
},
Most helpful comment
I have to confirm that currently Jest has serious issues with aliases defined in a webpack config:
jest.mock('aliased/module')
- doesn't do automockingjest.genMockFromModule('aliased/module')
- cannot find the moduleThis issue is 1.5 years old. Will it be ever fixed?