jestjs / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
44.25k stars 6.46k forks source link

[bug] duplicate manual mock found in separate directories #2070

Open paularmstrong opened 8 years ago

paularmstrong commented 8 years ago

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
Axlle commented 6 years ago

+1

IgorLeshchenko commented 6 years ago

Any update on this?

cuvelierm commented 6 years ago

Also still looking for a fix so that my test files can be immported in a regular fashion, not by using the more dirty way that was suggested above.

jest.mock('models/index', () => require('models/index/_mocks_/index'));

karomancer commented 6 years ago

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?

kgroat commented 6 years ago

@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.

g-harel commented 6 years ago

This issue is super frustrating, but I think I've found a nice workaround that results in a cleaner naming convention.

In package.json

{
  "jest": {
    "setupFiles": [
      "<rootDir>/test.mocks.ts"
    ]
  }
}
/* test.mocks.ts */

// modules mocked before every test
// use `jest.unmock(...)` to undo for any single test case
const mockedModules = [
    "./path/to/module1/index.ts",
    "./path/to/module2/index.ts",
];

mockedModules.forEach((path) => {
    const mockPath = path.replace(/\.ts$/g, ".mock.ts");
    jest.mock(path, () => require(mockPath));
});

This will allow you to mock anything.ts by creating a sibling anything.mock.ts and adding the path to the original in the top-level test.mocks's mockedModules array.

drwatsno commented 6 years ago

Why this issue tagged as enhancement?

amccloud commented 6 years ago

This seems to work for me. in jest.config.js:

module.exports = {
  // ...
  modulePathIgnorePatterns: ["<rootDir>/.*/__mocks__"]
};

I'm not sure of the the scope or impact of this change, because I have a small project.

darkowic commented 5 years ago

@amccloud thanks! This solved my problem! Details below.

I have a module helpers in my project root directory. The helper is exporting function parseNodeFromString. I've created in some other module local file helpers. Then I mocked it for one of my tests. And all of the tests using the function parseNodeFromString started to fail with the following error:

FAIL  src/some_dir/bla/tests/SomeClass.test.js
  ● Test suite failed to run

    TypeError: (0 , _helpers.parseNodeFromString) is not a function

What about this issue? Seem like @amccloud solution is correct.

ngerritsen commented 5 years ago
modulePathIgnorePatterns: ["<rootDir>/.*/__mocks__"]

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.

jozefcipa commented 5 years ago

So what is the current status of PR? Is there any proper solution or just some hacks?

vinodloha commented 5 years ago

In my case, the mock module was copied to Dist dir with every build.

Looks like this is a problem with typescript being unable to exclude paths/patterns that belong to deeper dir structure. Its still a problem with "typescript@^3.4.5".

To fix this I started cleaning my Dist dir with "rimraf dist" before every test run.

"test:unit": "npm run clean && stencil test --spec --snapshot",

I know its a hack, but works.

trackmystories commented 4 years ago

Hey i solved this here is what happened, and maybe it can help you duplicate this.

three solutions or scenarios:

1, I was editing my app on my text editor twice meaning, I was running pod install / update and react-native run-ios from two different windows. and I got this error, I tried searching for the duplicate files in Xcode and on my app but i couldn't find any. so I simply deleted the app from the simulator and re-ran react-native run-ios and it worked, It turned out that two node_modules had been duplicated as such: node_modules and node_modules0 in my scr file.

2, sometimes when I press random keys on my mac the node_modules are duplicated in for example the SRC folder so this also be the case, so it makes sense to have a look at your folders for any node_modules duplications.

3, I could'nt get my app to start until I launched and terminated a different app on the same simulator and then I rebooted the app with the duplication which then fired up without any errors.

goranefbl commented 4 years ago

Still nothing? Cant use modulePathIgnorePatterns in CRA

amedley commented 4 years ago

3 years and 10 months

NickHeiner commented 4 years ago

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.

ymoran00 commented 3 years ago

3 years and 10 months

And one of the messages 3 years ago was "I might find some time tomorrow to cook up a patch, but no promises though"... :-P

NickHeiner commented 3 years ago

Heh, I've left many such comments myself.

adbl commented 3 years ago

Is there no workaround (without changing your implementation). index exports are really useful and being able to mock them throughout...

adbl commented 3 years ago

here's what I came up with 💩

// jest.setup.js

jest.mock('src/my/cool/Scope', () => require('src/my/cool/Scope/__mocks__/Scope.index'))
JeromeS4RB commented 3 years ago

To ask the stupid question... Would using the whole path instead of just the filename not solve this?

holylander commented 3 years ago

"modulePathIgnorePatterns": ["<rootDir>/src/react/.*/__mocks__"],.

Still it's quite weird that mocks are not just unique based on the full path from the root.

this is what worked for me :)

LKay commented 3 years ago

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.

adbl commented 2 years ago

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?

shamilovtim commented 2 years ago

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.

github-actions[bot] commented 9 months ago

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.

shamilovtim commented 9 months ago

Valid