I currently have all my app source code under app/
and all my tests source code under tests/
. These folders follow the same folder structure. Everything is working fine with the following Jest configuration:
{
"collectCoverageFrom": [
"app/**/*.{ts,tsx}"
],
"coverageDirectory": "build/coverage/",
"coverageReporters": [
"html",
"text-summary"
],
"moduleFileExtensions": [
"js",
"ts",
"tsx"
],
"moduleNameMapper": {
"^.+\\.css$": "identity-obj-proxy"
},
"modulePaths": [
"<rootDir>/app/"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"transform": {
"^.+\\.(ts|tsx)$": "./utils/jest-typescript-transformer.js",
"^.+\\.(gif|jpg|png)$": "./utils/jest-image-size-transformer.js"
},
"testPathDirs": [
"<rootDir>/app/",
"<rootDir>/tests/"
],
"testRegex": "tests/.+\\.spec\\.(ts|tsx)$"
}
Now I need to mock some modules and the documentation states:
Manual mocks are defined by writing a module in a
__mocks__/
subdirectory immediately adjacent to the module.
This means that the __mocks__
needs to be inside the app
folder but I'd like to keep everything test related inside the tests
folder. But there's the thing, if I have duplicate mocks on both app
and tests
I get this:
jest-haste-map: duplicate manual mock found:
Module name: DialpadDigits
Duplicate Mock path: C:\SampleApp\tests\constants\dialer\__mocks__\DialpadDigits.ts
This warning is caused by two manual mock files with the same file name.
Jest will use the mock file found in:
C:\SampleApp\tests\constants\dialer\__mocks__\DialpadDigits.ts
Please delete one of the following two files:
C:\SampleApp\app\constants\dialer\__mocks__\DialpadDigits.ts
C:\SampleApp\tests\constants\dialer\__mocks__\DialpadDigits.ts
But the only file actually being used is the one under app
... How do I know this? Say I have the same mock on both folders and this mock fails my tests and if I don't use the mock, the tests pass. If I remove the mocked module from app
, the test passes. Which means the mock from tests
is not being used, despite that Jest warning above.
To sum up, how can I have my mocks in the tests
folder?
I have exactly the same question. I've been struggling with this for a while now, and I just can't put mock folders everywhere. I want them all in one mock folder in my test folder. Anyone know of a way to do this? I've tried everything I can think of, even importing a function then using it as the second argument in jest.mock(), but even then I get an error saying "the second argument of jest.mock() must be a function." It is a function, but for some reason jest doesn't like it.
Specifically, I do not want my mocks to be colocated with implementations, and I don't want any folder names with __
in them.
You can only have one manual mock per module. We will eventually introduce a way to configure it better that will continue to work with how we use mocks at FB (@ColCh has a PR for this). For now, I consider manual mocks broken and they aren't great. If anybody can conceive a model that will work better and enables us to codemod current manual mocks, I'm happy to hear it.
As far as customizing the folder location or name goes, Jest is opinionated about a few things and I'm not interested in supporting complexity around these things.
Any thing needed from me on that PR?
@cpojer it's disappointing that "colocation" and "__tests__
" are considered worth changing for tests, but not for mocks. What opinionated stance supports customizing one, but not the other?
@ljharb totally agree that's disappointing! It's absolutely my own subjective decision to be opinionated about this. If you are willing to build and maintain this feature, for the long-term, to customize both the mocks folder and snapshot folders, with all that comes with it, please be my guest. I won't stop you and I will probably merge it, but I have reservations regarding the necessary complexity this might add.
Understood, thanks! When I have the time I will both prepare a PR and commit to maintaining any complexity around it.
I guess my request:
This means that the __mocks__ needs to be inside the app folder but I'd like to keep everything test related inside the tests folder.
Is not currently possible. Correct?
Maybe this should be closed then?
It'd be nice to keep it open so I can find it more easily when I get to the PR.
Thanks @ljharb, that is very much appreciated. Just for the record: both mocks and snapshots should be configurable and snapshots need to be configurable so you can look up a test from the snapshot file and vice-versa. Also, keep in mind that this cannot be a breaking change.
@rfgamaral : in the meantime, I've come up with a solution that seems to work for me. In my tests folder, I have a file mocks.js
. In that file, I have, for example:
exports.api = {
getWeather: Promise.resolve({sky: 'Sunny', rain: '10%'}),
somethingElse: Promise.resolve([{_id:'yg321i14', name:'example'},{...
}
Then, to mock an api call for any component that imports any function from 'root/api'
, all I need to do is this:
jest.mock('root/api', () => require('../mocks').api)
Hope that helps as a stopgap. You still need to directly mock components, but that's only two lines:
jest.mock('root/components/SomeComponentFolder/SomeComponent')
const SomeComponent = require('root/components/SomeComponentFolder/SomeComponent')
@ljharb @cpojer It seems to me that a good option would be to have an config parameter that allows the mock location to be configured via a regex matcher with capture groups specifying the module that should be mocked. For instance, the existing behavior could be specified with a regex like so:
jest --mockModulesRegex=(^.+)\/__mocks__\/(.+$)
const regex = new RegExp(options.mockModulesRegex);
filePaths.forEach((file) => {
const match = file.match(regex);
if(match){
const mockPath = match.shift();
const moduleName = match.join(''); //concatenate capture groups
//Do mocking
}
})
To keep things sane, we could throw an error if the regexes don't have a single unique match.
Doing it this way would be beneficial for a use case I'm trying to support where I want different mock files for my unit tests (module.unit-mock.js
) _and_ my integration tests (module.e2e-mock.js
)
I'm not sure how this system would work though with node_modules
and the like, since a module isn't always defined by its path. Any jest-haste guru on how node modules like "fs" could be accommodated with a regex scheme?
@scottmas does jest mocking currently work with node_modules? If so, then I'd say that the regex should only apply for relative paths - ie, not for npm-installed things.
Yep, it does per https://facebook.github.io/jest/docs/manual-mocks.html. Just create a __mocks__
folder as a sibling to node_modules
.
Actually, now that I think about it a bit more, as long as the array of files paths filePaths
starts at the cwd, we should be fine with the current proposal as long as we make the first capture group optionally empty:
jest --mockModulesRegex="(^.*)\/__mocks__\/(.+$)"
However, we would need to verify that whatever array of file paths jest-haste is operating on (e.g. filePaths
) does indeed start at the cwd. And we would need to ensure filePaths
does not contain the file extension.
Also, it would be nice if we could support multiple concurrent regex definitions. E.g. Support the existing module system but add on support for module.mock.js
files and the like:
jest --mockModulesRegex="(^.*)\/__mocks__\/(.+$)" --mockModulesRegex="(^.*)\.mock"
ftr, in my case, I would never want a .mock.js
file - I want a mocks
folder that is parallel to my code and to my tests, where every filename is identical to the thing it's mocking.
Hmm, yeah, that would require an additional configuration option, since you'd be adding a custom path. At this point, it's probably worth removing this option from the CLI since it would get ugly on the command line. The config values could be similar to moduleNameMapper
:
{
"mockModulesRegex": {
"^mocks\/(.+$)": "$1"
"default": true //Special flag to enable default Jest mocking
}
}
What do you think? Depending on the implementation details of jest-haste-map
, we may need to support a construct like <rootDir>
in the regex.
For non-node_modules mocks, it should be able to work just like the tests regex does. It makes sense to me to put node_modules mocks under a separate setting.
I've eventually moved all my test files to the same location as the source files and I no longer have this issue. I'm closing it because this was originally a question and not a feature request.
Feel free to reopen it or open a new issue if necessary.
@rfgamaral i'd appreciate it being reopened; this still needs to be fixed.
are mocks global in current jest version ?
@rfgamaral any update or workaround for this?
Also wanna make them in the same dir, called tests
. I don't like those __naming__
at all.
@kuldeepkeshwar I don't know, I just reopened it per @ljharb's comment.
Looking forward to a solution here. Creating a folder __mock__
as a sibling for every component or module that I want to mock really messes up my directory structure.
You can setup .babelrc with module-resolver plugin and add your paths
json
{
"plugins": [
["module-resolver", {
"root": ["./src"],
"alias": {
"^mocks": "./__mock__",
"underscore": "lodash"
}
}]
]
}
import { userMock } from 'mocks';
I found out that specifying
"roots": ["<rootDir>/src/", "<rootDir>/tests/"]
in jest's config would allow to move the uppermost __mocks__
folder to tests directory.
Does it sound like a bug rather than a feature?
@alvis No, it's not a bug. Actually this behavior is documented.
yes, you're right!
Can this be closed now?
Having to define the tests dir as a root dir is a nice workaround, but it doesn鈥檛 do what this issue wants - to change where mocks live, as a direct setting.
FWIW, there's a PR for custom snapshot locations: #6143
And the conclusion in #6193 was that we need to expose the normal resolver - that should potentially allow you to extend ours, and implement your own lookup for mocks. Not sure about that last one, though, but it might be a starting point for anyone wanting to send a PR 馃檪
Greetings gentlemen,
I am really happy with your outstanding efforts with Jest.
I was wondering if we can have something similar to snapshotResolver for mocks? What is the status on this issue?
Thank you!
I was wondering exactly the same as @geekox86. Are there any plans to create a resolver to change the location of mocks? For integration with my IDE it would be a lot better to be able to place mocks just next to the mocked file instead of inside a __mocks__ folder.
Enforcing these __conventions__ __around__ __filenames__ makes Jest grab much more attention to itself than it deserves, making testing a significantly bigger part of an application, and the application significantly less organized.
Compare this:
/
src/
! __tests__
! index.test.js
components/
! __tests__
! some-component.test.js
! another-component.test.js
! __snapshots__
! some-component.test.js.snap
! another-component.test.js.snap
some-component.js
another-component.js
api/
! __tests__
! __mocks__
! some-api-method.js
! another-api-method.js
! some-api-method.test.js
! another-api-method.test.js
some-api-method.js
another-api-method.js
index.js
… to this:
/
src/
components/
some-component.js
! some-component.test.js
! some-component.test.js.snap
another-component.js
! another-component.test.js
! another-component.test.js.snap
api/
some-api-method.js
! some-api-method.test.js
! some-api-method.mock.js
another-api-method.js
! another-api-method.test.js
! another-api-method.mock.js
index.js
! index.test.js
… and this:
/
src/
components/
some-component.js
another-component.js
api/
some-api-method.js
another-api-method.js
index.js
! snapshots/
! components/
! some-component.test.js.snap
! another-component.test.js.snap
! mocks/
! api/
! some-api-method.js
! another-api-method.js
! tests/
! components/
! some-component.test.js
! another-component.test.js
! api/
! some-api-method.test.js
! another-api-method.test.js
! index.test.js
Being highly opinionated about an open source project is always a pain for the users of this project; there has to be some flexibility when it comes to file structure.
Most helpful comment
Specifically, I do not want my mocks to be colocated with implementations, and I don't want any folder names with
__
in them.