jest: [bug] duplicate manual mock found in separate directories
Do you want to request a feature or report a bug? Bug
What is the current behavior?
Given a file tree:
src/app/modules
├── module1
│ ├── index.js
│ ├── __tests__/
├── module2
│ ├── index.js
│ ├── __tests__/
I use the modules outside of the modules
directory by importing them by directory name:
import Module1 from '../modules/module1';
import Module2 from '../modules/module2';
I’d like to be able to mock module1
and module2
. However, if I create src/app/modules/module1/__mocks__/index.js
and src/app/modules/module2/__mocks__/index.js
, I’m given the duplicate manual mock found
error from jest-haste-map
.
If, however, I try to create src/app/modules/__mocks__/{module1.js,module2.js}
, the mocked files are not used.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal repository on GitHub that we can npm install
and npm test
.
See above behavior.
What is the expected behavior?
I would expect either approach to work, given that the first case uses different paths and the second case uses the pathname of the module.
Run Jest again with --debug
and provide the full configuration it prints. Please mention your node and npm version and operating system.
node v6.2.0 npm v3.8.9 OS X 10.11.6
> NODE_ENV=test jest --env jsdom "--debug" "src/app/redux/modules/devices"
jest version = 17.0.0
test framework = jasmine2
config = {
"moduleFileExtensions": [
"js",
"json"
],
"moduleDirectories": [
"node_modules"
],
"moduleNameMapper": [
[
"^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$",
"/Users/paul/dev/tools/jest/mock-assets.js"
],
[
"^.+\\.css$",
"identity-obj-proxy"
]
],
"name": "dev",
"setupTestFrameworkScriptFile": "/Users/paul/dev/tools/jest/setup-framework.js",
"testPathDirs": [
"/Users/paul/dev/src"
],
"testRegex": "/__tests__/.*\\.test\\.js$",
"timers": "fake",
"rootDir": "/Users/paul/dev",
"setupFiles": [],
"testRunner": "/Users/paul/dev/node_modules/jest-jasmine2/build/index.js",
"testEnvironment": "/Users/paul/dev/node_modules/jest-environment-jsdom/build/index.js",
"transform": [
[
"^.+\\.jsx?$",
"/Users/paul/dev/node_modules/babel-jest/build/index.js"
]
],
"usesBabelJest": true,
"automock": false,
"bail": false,
"browser": false,
"cacheDirectory": "/var/folders/dm/vt920lmd6tzdq_709zkykwx40000gn/T/jest",
"coveragePathIgnorePatterns": [
"/node_modules/"
],
"coverageReporters": [
"json",
"text",
"lcov",
"clover"
],
"expand": false,
"globals": {},
"haste": {
"providesModuleNodeModules": []
},
"mocksPattern": "__mocks__",
"modulePathIgnorePatterns": [],
"noStackTrace": false,
"notify": false,
"preset": null,
"resetMocks": false,
"resetModules": false,
"snapshotSerializers": [],
"testPathIgnorePatterns": [
"/node_modules/"
],
"testURL": "about:blank",
"transformIgnorePatterns": [
"/node_modules/"
],
"useStderr": false,
"verbose": null,
"watch": false,
"cache": true,
"watchman": true,
"testcheckOptions": {
"times": 100,
"maxSize": 200
}
}
jest-haste-map: duplicate manual mock found:
Module name: index
Duplicate Mock path: /Users/paul/dev/src/app/modules/push-notification-manager/__mocks__/index.js
This warning is caused by two manual mock files with the same file name.
Jest will use the mock file found in:
/Users/paul/dev/src/app/modules/push-notification-manager/__mocks__/index.js
Please delete one of the following two files:
/Users/paul/dev/src/app/modules/image-file/__mocks__/index.js
/Users/paul/dev/src/app/modules/push-notification-manager/__mocks__/index.js
No tests found
1 file checked.
testPathDirs: /Users/paul/dev/src - 1 match
testRegex: /__tests__/.*\.test\.js$ - 0 matches
testPathIgnorePatterns: /node_modules/ - 1 match
About this issue
- Original URL
- State: open
- Created 8 years ago
- Reactions: 216
- Comments: 77 (24 by maintainers)
Commits related to this issue
- (refs #377) Upgrade jest to 18 (bug remains: https://github.com/facebook/jest/issues/2070) — committed to asha-nepal/AshaFusionCross by whitphx 8 years ago
- (refs #377) Upgrade jest to 18 (bug remains: https://github.com/facebook/jest/issues/2070) — committed to asha-nepal/AshaFusionCross by whitphx 8 years ago
- (refs #377) Upgrade jest to 18 (bug remains: https://github.com/facebook/jest/issues/2070) — committed to asha-nepal/AshaFusionCross by whitphx 8 years ago
- (refs #377) Upgrade jest to 18 (bug remains: https://github.com/facebook/jest/issues/2070) — committed to asha-nepal/AshaFusionCross by whitphx 8 years ago
- Support disabling global filenames within the haste map Addresses: https://github.com/facebook/jest/issues/2070 — committed to mwildehahn/jest by deleted user 7 years ago
- Support disabling global filenames within the haste map Addresses: https://github.com/facebook/jest/issues/2070 — committed to mwildehahn/jest by deleted user 7 years ago
- test(rn): update snapshot — committed to ant-design/ant-design-mobile by paranoidjk 7 years ago
- work around jest bug https://github.com/facebook/jest/issues/2070 — committed to soap-bubble/morpheus by CaptEmulation 7 years ago
- FIxed the duplicate files warning by changing mockPath to filePath (#2070) — committed to cuvelierm/jest by cuvelierm 6 years ago
- Fix: `core` method mocks have haste priority This is due to the way Jest treats mock file imports. If there are more than one with the same name, they will conflict. A solution for this is to rename... — committed to JoinColony/purser by rdig 6 years ago
- Fix: `core` method mocks have haste priority This is due to the way Jest treats mock file imports. If there are more than one with the same name, they will conflict. A solution for this is to rename... — committed to JoinColony/purser by rdig 6 years ago
- Fix: `core` method mocks have haste priority This is due to the way Jest treats mock file imports. If there are more than one with the same name, they will conflict. A solution for this is to rename... — committed to JoinColony/purser by rdig 6 years ago
- [C] Prevent jest duplicate mock warning See https://github.com/facebook/jest/issues/2070 — committed to ManifoldScholar/manifold by zdavis 6 years ago
- [C] Prevent jest duplicate mock warning See https://github.com/facebook/jest/issues/2070 — committed to ManifoldScholar/manifold by zdavis 6 years ago
- [C] Prevent jest duplicate mock warning See https://github.com/facebook/jest/issues/2070 — committed to ManifoldScholar/manifold by zdavis 6 years ago
- Rename mocks file names to avoid JEST error: https://github.com/facebook/jest/issues/2070 — committed to liamqma/habits by liamqma 4 years ago
This seems to work for me. in jest.config.js:
I’m not sure of the the scope or impact of this change, because I have a small project.
3 years and 10 months
This solution works although it made my top level mocks for node modules fail. So I changed it to not ignore my root mock folder with:
"modulePathIgnorePatterns": ["<rootDir>/src/react/.*/__mocks__"],
. Still it’s quite weird that mocks are not just unique based on the full path from the root. It’s pretty common to have:users/helper.js
&posts/helper.js
. The warning does take quite some space, and I don’t want to completely hide actual warnings.Any updates on how to fix this problem? This turns out to be really painful if you follow a structure like this:
Right now I have to manually mock a module in the test if I’m using two with a ‘conflicting’ name even though they actually don’t have conflicting names since the path should be considered.
Cheers, Dominik
Any update on this?
Yes this does suck indeed. The manual mocking system is really not good and I’m happy to accept PRs that will improve the situation, assuming we can make sure we don’t break all of FB (but I can take care of that 😃 )
+1
And one of the messages 3 years ago was “I might find some time tomorrow to cook up a patch, but no promises though”… 😛
@masoudcs I think this got rid of the warning:
package.json
Add the “duplicate” folders in the
modulePathIgnorePatterns
array and the warning will be goneHere’s the offending code:
https://github.com/facebook/jest/blob/cd8976ec50dbed79cfe07f275052cdd80d466e73/packages/jest-haste-map/src/index.js#L98
But it looks like the behavior might be explicitly wanted as there is a test confirming it:
https://github.com/facebook/jest/blob/8de90b320c87a0a36d68f6bd8177620a985df269/packages/jest-haste-map/src/__tests__/__snapshots__/index-test.js.snap#L15
Which was added in:
https://github.com/facebook/jest/commit/cfade282fbbe2737b6dd2cee1cf3da3ee8624512
I wonder why we are using
basename
rather than the whole path as the key?/cc @flarnie
A little workaround for me is to mock the modules with require
jest.mock('models/index', () => require('models/index/_mocks_/index'));
I renamed the
__mocks__
folder name to_mocks_
so that jest does not catch the files.One day when this will work I will rename
_mocks_
to__mocks__
and remove the require part from jest.mockThis means that
basename
s for modules need to be globally unique in a project when using manual mocks. For my use case, it means I can’t do something like:and use manual mocks at the same time. Jest will currently see them both as mocking
schema
and complain.Though the workaround is trivial (s/schema/MyWhateverSchema/), it feels like a bug to rename and restructure non-test code to make jest happy 🐞 .
This issue is super frustrating, but I think I’ve found a nice workaround that results in a cleaner naming convention.
In
package.json
This will allow you to mock
anything.ts
by creating a siblinganything.mock.ts
and adding the path to the original in the top-leveltest.mocks
’smockedModules
array.We have found that in spite of the warnings, our actual tests succeed and thus the individual manual
index
mocks are actually being used. What then does the warnings mean?So what is the current status of PR? Is there any proper solution or just some hacks?
Guys any update?
Yes, mocks are “global” as well. This is a terrible design that we have to live with, unfortunately. At FB we have 4000+ mock files in the wrong location (and often there isn’t even a proper location). It is likely we will fix this early next half, so this should improve in Jest. I’m happy to support PRs that improve the behavior in Jest for open source – if we can retain the old behavior for Jest at FB for now.
To ask the stupid question… Would using the whole path instead of just the filename not solve this?
Hey everyone, sorry for the delay, I’m pretty backed up with a ton of stuff right now.
I think I’m fine if you guys decide to do whatever breaking change in Jest that is necessary to improve this system. Manual mocking is really messed up and doesn’t work well. One thing we kind of want to do is limit the scope of “haste modules” (internal FB module system) using a config option, like
"haste_modules": ['path/a', 'path/b']"
and then only look at haste modules in those folders, including this weird mocking behavior. If anybody wants to make this change, that would be amazing.One thing to be figured out then, is this: If all manual mocks are local, like
__mocks__/a.js
maps toa.js
, what do we do with node_module mocks? For this there are a couple of ways:__node_modules_mocks__
folder but that is ugly.__mocks__
folder as seen fromrootDir
(project root) could act as a global folder.So to summarize:
["<rootDir>"]
for us for now, I guess)What do you think?
Is there no workaround (without changing your implementation).
index
exports are really useful and being able to mock them throughout…A flag to turn off the warning would be good enough for us. Or its outright removal. There’s no added value from this warning. Having two identically named files is impossible on a standard file system. My concern is that if we keep investing in manual mocks we’re going to get flooded by these warnings. They make the DX poor and make our project look clunky and broken.
+1
+1, is there a way to fix this?
When this bug will be fixed? I have
__mocks__
folders mocking the same module differently in different folders that conflict with each other. The first one that is resolved when test run is executed is used for all mocking fo that module.+1 very frustrating to see these warnings. Can’t wait for a fix.
Cool. I might find some time tomorrow to cook up a patch, but no promises though 😅
I think the issue I’m having is related:
if I have a jest.mock(‘src/utils/history’), it also incorrectly mocks the ‘history’ node_module.
https://github.com/cwmoo740/jest-manual-mocks-node-modules
Valid
This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.
this is what worked for me 😃
@karomancer I’ve submitted PR #6037 which will allow you to use a configuration to remove the warnings. As of yet, it hasn’t been merged; I’m waiting for a response from the contributors.
Firstly: Thanks for all the awesome work. Secondly: This is really, quite frustrating. I find myself forced to use jest.mock in the test file when the mocked file shares a name with any other file in the entire codebase that also gets mocked. The hoisting disallows the actual mock to be imported too, so it forces you to duplicate the mock in any two tests that require that file to be mocked, adding to the fragility of the test suite. Are we looking at addressing this? Does FB use this stuff? If yes, then how? 😞
We cannot break the current behavior as we rely on it extremely heavily at Facebook.
What about just a config option to change the behavior ofgetMockName
?Not too familiar with the internals of jest, but it looks like that is the simplest solution to fix the issue without breaking jest for FB.This is going to be more complicated than I originally thought. To me, manual mocks should replace the file they’re closest too, ie. something like this:
require('aws-sdk')
should resolve to the/Users/project/__mocks__/aws-sdk.js
this is a mock for anode_module
.require('./db')
(or any path todb
) should resolve to:/Users/project/db/__mocks__/index.js
.My understanding of the way to setup jest manual mocks (and there should probably be more documentation if something like the above is used) was that they should be as close to the file being mocked as possible within a
__mocks__
directory.Given that, the above behavior makes the most sense to me.
Thoughts?
here’s what I came up with 💩
Heh, I’ve left many such comments myself.
Alternatively, it would be nice if we could force Jest to throw an error when this issue comes up, rather than just warning. Warnings are easily ignored; on my project, I’d prefer that an error be thrown, so the dev who introduced it has to deal with it.
Our directory structure looks the same as @dkundel 's referenced here https://github.com/facebook/jest/issues/2070#issuecomment-301332202 with models and components in their own namespaces with
index.js
being the default export.Would prefer to not silence warnings or throw all mocks into a flat directory. Some of our mocks are deeply nested, and the workaround suggested would likely look like
jest.mock('pages/index/components/Component', () => require('pages/index/components/Component/_mocks_/index'));
in our structure.Any word?
cc @voideanvalue this may be something you’ll have to think about (namespace manual mocks as part of the new haste implementation).
what about two new config options:
fullPathMockResolution
(defaulted tofalse
to keep existing behavior) coupled with:namedMockDirectories
: iffullPathMockResolution
is enabled, any directories within that array will be resolved with the existing behavior. For the FB use case, this would just be[<rootDir>]
like you mention above.This lets devs opt into the full path resolution so it doesn’t require changes by existing jest installs and also enables the existing behavior for specific directories if they want that.
I think these are some larger changes on the way to get this resolved but I think we need both the singular globalMocks option (could be a string or array of strings) and the hasteModules option which would be an array of paths of haste modules. Most of this code lives in jest-haste-map and jest-resolve. I’m not 100% sure what the right solution will look like yet.
From: Max Sysoev notifications@github.com Sent: Friday, December 9, 2016 8:18:44 AM To: facebook/jest Cc: Christoph Pojer; Mention Subject: Re: [facebook/jest] [bug] duplicate manual mock found in separate directories (#2070)
I can work on PR this sunday, I’m kinda free
@cpojerhttps://github.com/cpojer just to recap - create globalMocks config entry with default value of <rootDir>/mocks. This option regulates use of node-haste within jest by specifying path? Or it will be array of paths?
You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/facebook/jest/issues/2070#issuecomment-265958606, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AAA0KAMFc34iKqBDLHZzgaGHqyc3WkAzks5rGQ7kgaJpZM4Kt2DW.
Let’s keep this focused on changing how haste works (whitelist/blacklist rather than on by default). I do think I’d prefer to maintain that
<rootDir>/__mocks__
should be the default for node module mocks. We could make this a configuration option as well: “globalMocks” that defaults to<rootDir>/__mocks__
. Is anybody willing to work on this?I fully agree with
"haste_modules"
.We personally don’t use automocking that much, so I can’t say what’s better, my wild guess is that the
"autoMockingPaths"
var could be useful and elastic enough. On the contrary I find"automock": "app"
too stiff (jest already disabled automocking by default).The
__node_modules_mocks__
could be an option, I agree that rareness compensate for ugliness (in my particular case, we rarely mocknode_modules
, and when we have to do it, we usejest.mock(...)
). The only caveat is: what happens when you have a nestednode_modules
folder (e.g.src/node_modules
), do you have to mock its modules from the global__node_modules_mocks__
, a nested version of it, or normally with__mocks__
co-located?In order:
HURRAY 😄 🎉
I’m not sure I understand the needs with haste. What you mean is to give the possibility to say “those modules are haste modules”? If we have four modules:
/path_1/a
,/path_1/b
,/path_2/a
,/path_2/c
, and the setting isonly
/path_1/a
and/path_1/b
are restricted to exist only in/path_1
, so/path_2/c
is valid, and/path_2/a
raises an error/warning.I’d say, targets could easily be specific files and entire directories, even with single/double
*
.I’d maintain the current behavior: