I have a file named app.js
. Immediately adjacent to that I have a manual __mocks__/app.js
file. I have a test that both requires this app
module and requires a module that has an export function that requires this app
module when called (only happens at runtime, it's not a circular dependency issue).
I have attached an isMock: true
property to my manual mock. Here is the other submodule I am including in my test:
exports.obj = function() {
var app = require('./app/app');
console.log("Is this a mock in my submodule: " + app.isMock);
console.log(app);
}
I then run my test. I require('../../app/app.js')
from my test, and print the isMock
property on it and it shows as true, and thus is being mocked correctly there. However, it is logging the unmocked version of app
from the above submodule when the test is run. The only way I resolved this issue was by doing jest.setMock('../../app/app.js', require('../../app/__mocks__/app.js'))
in my test. When I do this, the mock is properly being used directly in my test file and in my submodule in the test file.
Am I doing something wrong? The docs are very unclear as to the use of the __mocks__
folder, there is only one mention of it. I am fairly certain this is unintended behaviour, the file in the __mocks__
folder should be used across and inside all modules in my test.
+1 I have the same problem, can't seem to get manual mocks to work, docs really aren't great at explaining what's going on here.
+1, I have a similar problem. It is not loading the mock from my mocks folder and I can't say what is the problem.
+1
+1 T_T
I recommend using jest.mock('path/to/module/name', () => {鈥) for this. I don't think we'll add support for nested manual mock files.
@cpojer Why not?
We aren't currently investing in improvements to the mock system heavily. If you'd like to work on this please join us on discord (#jest on reactiflux) and I'm happy to help you get a PR ready :)
Doesn't seem to be fixed yet...??? (Jest CLI v0.7.1)
Modules that are mocked with jest.mock are mocked only for the file that calls jest.mock. Another file that imports the module will get the original implementation even if run after the test file that mocks the module.
http://facebook.github.io/jest/docs/en/jest-object.html#jestmockmodulename-factory-options
I found this while searching through the docs. My guess is that is also the official way of thinking with these nested submodules and manual mocking. Maybe this will help clarify for some people, maybe not. Hoping it's helpful to someone.
I have been having this problem and found this comment, which solved it for me. It should be in the docs.
@benadamstyles That only works if you're using the mocked module directly in test. It doesn't work when the mocked module is a dependency of a different module that is the one under test. In that case, the dependency won't use its __mocks__
file when called from the module under test.
@cpojer I really like jest, but the documentation around manual mocking seems to be a sore point in a lot of github issues. I'd love to help, but the behaviour is too cryptic. I agree with @MattyKuzyk that it seems counterintuitive that a module under test wouldn't use a manual mock defined for a dependency when the test explicitly says to jest.mock
that module.
Conversely, a manually mocked node_modules dependency IS used when it is called in a module under test, where no jest.mock
is needed.
This behavior feels odd to me. Wouldn't it make sense for __mocks__
to be used all the time in replacement for the actual module, _even without_ the requirement of telling jest to do so? I thought of the mocks in the __mocks__
folder as some kind of global replacement. Limiting the scope of these mocks as discussed here seems broken.
A way to use __mocks__
as a global replacement I stumbled upon is to define such mocks in the jest.setup.js
file like so:
jest.mock('../src/some-module', () => jest.requireActual('../src/__mocks__/some-module'));
jest.mock('../src/other-module', () => jest.requireActual('../src/__mocks__/other-module'));
This certainly requires us to re-define each mock in the __mocks__
directory but is a nice combination of being able to define global mocks of a file and defining the actual mock in a dedicated file close to the real module.
Is it expected that this works
// in the test
beforeAll(() => {
saga2.foo = function * () {
yield 'something'
return 'fake foo'
}
}
and this doesn't?
// in the test
jest.mock('./saga2', () => jest.requireActual('./__mocks__/saga2.js'))
// in `./__mocks__/saga2.js`
export function * foo () {
yield 'something'
return 'fake foo'
}
I thought they should be equivalent from the mocking perspective.
I'd love to be able to reuse mocks without having to write them in every test that needs the mocked code, but there doesn't seem to be an easy way of doing so. It's possible that I'm missing something here.
I found a way to implement the desired behaviour by adding the below to a setup file:
import fs from 'fs';
import path from 'path';
const isDirectory = (dir, file) =>
fs.statSync(path.join(dir, file)).isDirectory();
const mockExists = (dir, file) =>
fs.existsSync(path.join(dir, '__mocks__', file));
const mockModule = (dir, file) => {
jest.doMock(path.join(dir, file), () =>
jest.requireActual(path.join(dir, '__mocks__', file)));
};
const initMocks = (dir) => {
fs.readdirSync(dir)
.forEach((file) => {
if (isDirectory(dir, file)) {
initMocks(path.join(dir, file));
} else if (mockExists(dir, file)) {
mockModule(dir, file);
}
});
};
// This will check all directories below the current directory (__dirname).
initMocks(__dirname);
@JamesPlayer I'm not sure if I got this right, but the solution you propose will automatically mock any file that has a __mocks__/{sameFileName}
sibling, correct?
If that is the case modules will be implicitly mocked, and explicitly unmocked. For example for an integration test you'll have to call jest.dontMock(module)
.
I think that behaviour is reversed to what most people would expect, and inconsistent with the standard jest behaviour. So even people familiar with Jest would find it confusing.
Edit: After trying that method, calls to jest.dontMock(module)
don't seem to do anything and the modules are still mocked. It might be something I'm doing wrong, but so far this would prevent me from doing any integration test.
calls to
jest.dontMock(module)
don't seem to do anything
You may want to use jest.unmock()
to be sure the actual unmocking gets hoisted to the top of the module. dontMock
doesn't get hoisted, so you might have it actually running but occurring much later than you expected, resulting in a failed unit test. It says this is only for babel-jest, but it's worth a shot.
Indicates that the module system should never return a mocked version of the specified module from require() (e.g. that it should always return the real module).
The most common use of this API is for specifying the module a given test intends to be testing (and thus doesn't want automatically mocked).
Returns the jest object for chaining.
When using babel-jest, calls to unmock will automatically be hoisted to the top of the code block. Use this method if you want to explicitly avoid this behavior.
Returns the jest object for chaining.
For the ones researching, the way I solved my problem: (Want to define only 1 mock, to be used in all my tests) was to import all my mocks into setupTests.ts
file.
// Content of setupTests.js
import "@testing-library/jest-dom/extend-expect";
import "./tests/mocks/aws-sdk";
// Content of /tetsts/mock/aws-sdk.ts
import "@testing-library/jest-dom/extend-expect";
jest.mock("aws-sdk", () => ({
CognitoIdentityCredentials: jest.fn(),
config: {},
S3: jest.fn().mockImplementation(() => ({
foo: "bar",
listObjectsV2: (options: any, callback: any) =>
callback(null, { Contents: [] }),
})),
}));
This allowed me to centralize the definition of my mocks for all my testing for easier maintenance. I agree with previous commenters that the __mocks__
behavior is poorly defined in the documentation. It took me many hours of trial and errors and mind-boggling confusion to get to a working solution
Most helpful comment
This behavior feels odd to me. Wouldn't it make sense for
__mocks__
to be used all the time in replacement for the actual module, _even without_ the requirement of telling jest to do so? I thought of the mocks in the__mocks__
folder as some kind of global replacement. Limiting the scope of these mocks as discussed here seems broken.A way to use
__mocks__
as a global replacement I stumbled upon is to define such mocks in thejest.setup.js
file like so:This certainly requires us to re-define each mock in the
__mocks__
directory but is a nice combination of being able to define global mocks of a file and defining the actual mock in a dedicated file close to the real module.