jest: jest.mock factory doesn't work inside a test
Do you want to request a feature or report a bug? Bug
What is the current behavior?
It seems the way to create a mock with a factory doesn’t work inside test
or it
. It works only when the mock is defined at the root level of the file.
Here’s my example of a mock:
jest.mock('services/feature', () => ({
isEnabled: () => true
}));
What is the expected behavior?
Mocking a file inside a test should work.
Please provide your exact Jest configuration and mention your Jest, node, yarn/npm version and operating system.
Jest 18.0.0, Node 7.4, macOS
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 100
- Comments: 54 (4 by maintainers)
To change return value of a mock between tests, you can do something like this:
If you were to do this in beforeEach, I’m unclear how you’d differentiate tests (so how would you be giving a different mock for each test?)
Putting it inside the tests themselves works of course.
This is because you are requiring your modules when the module initializes (using import).
jest.mock
gets called way later. The way to solve this is:etc.
As many times as I’ve run into this problem, I’m now convinced I’m either not testing properly, not using
jest
as the authors intended, or some combination of both. Further proof is that almost none of the mock related examples injest
’s documentation seem like real world examples to me…they probably are and my approach is probably incorrect.That said, the following works for me, and all of the following tests pass. Note that to get back to the original version of
ModuleB
, I have to call bothjest.resetModules()
andjest.unmock('./moduleB')
…the order of those doesn’t matter.What if I am not importing/requiring the file I want to mock (e.g. a dependency of other file I am importing) but I want it scoped to a describe/it block? Or even if I want to mock differently for beforeEach/beforeAll test? Are those cases possible?
Glad I found this issue, I was breaking my head why
jest.mock()
didn’t work in mydescribe
scope. Moved it to the top (below my imports in the test file) and it works.For me it also applies to
jest.mock()
without a factory, using a__mocks__
folder containing the mocked file.–edit
It’s obviously necessary to hoist the
jest.mock()
statement to before the import statements. However @tleunen, this probably means it’s not possible to mock the same file more then once, with different responses. Maybe you are best served by making the factory function more dynamic, so it can serve you different results in each test case.In my mind it would make it more explicit if
jest.mock()
is always put outside thedescribe
andit
blocks. But this should then be clearly stated in the docsIn that case, you need to require A after mocking B. (Not using
import
, butrequire
).Any advice @thymikee @cpojer for this issue? I have several tests in the same file and I’d like to have different mock responses for each of them.
I think this is still an issue that should maybe be reopened as a feature request. I want to write tests in isolation. Dumping things in a mocks folder or rewiring with a beforeEach usually ends up with a junk drawer of mocks/weird data instantiation that gets lugged around into every test. I want to write a small mock and make a small test pass.
@rafaeleyng but @SimenB doesn’t work if what you export from the module is not a function…
Module example based on https://github.com/facebook/jest/issues/2582#issuecomment-378677440 ❤️
Heya, found this via the linked issue and I figured it out:
If you need to mock multiple functions/methods on the required code, you need to set them up separately instead of using the factory when you do it globally.
If you like me just need a single function, you can simplify the whole thing:
Hey,
Nothing here works for me. Can someone please explain why it is not possible to use jest.mock inside it?
Thank you
Same thing with
doMock
.In the docs, I can read
But… A test is a code block, right? So in my case, I don’t expect to see any differences.
Here’s a full test
didn’t work for me, was still seeing the original mock of B pass through to the result
If you want to mock an object that is used indirectly by the code tested the
jest.doMock()
function won’t work:As of Jest 26 there is no way to mock more than once a module exporting an
Object
that is used indirectly (mocking something else than aFunction
since there is nomockFn.mockImplementation(fn)
forObject
s).The only solution then is having more than one test file to test the same module.
what about mocking non function dependencies like json files, or mapped constants. Please make the documentation more clear on how to handle this…
jest.mock
calls are automatically hoisted to the top of the file with babel-jest transform. You can omit this behaviour withjest.doMock
. Have you tried that?What I don’t quite understand when it comes to mocking modules is that it is always described as if you want to use the module primarily in your test-functions. E.g. if you look on the example code for the
doMock
function in the docs:In this example, you have access to the newly mocked version of
"moduleName"
inside the test function only. For me it is way more important that my “non-test”-code would have access to the mocked version of the module as well. E.g. a Class that I am using inside my test, that has imported"moduleName"
would still be using the original version, not the mocked one.Seems to be related: https://github.com/facebook/jest/issues/3236
Tip - if you have a module that exports a primitive value, e.g.:
And you want to use a mock value instead, in the test, then a simple require and assignment seems to do the trick:
Another solution could be using an external variable that is changed inside each test.
None of the solutions mentioned seemed to work for me, so I added this above my
describe
Then I updated the mocked data that was being passed into the
getTimezoneOffset
function in each test and that worked.In my case I was mocking and importing the wrong path to the module I wanted to stub. I had different casing in the file path so my editor thought it was okay but just was failing.
Was
Changed to (change casing of
File
tofile
):Hope this helps someone else.
@gcox Your solution is the only one I’ve found for when an imported module under test imports another module that I had a manual mock for in a
__mocks__
folder.For example, the test file calls
jest.mock('./ModuleA')
, which has a mock in__mocks__/ModuleA.js
. But ModuleA is not under test, ModuleB - which requires ModuleA - is what’s under test. Without your solution, ModuleB would get the actual implementation of ModuleA, not the mock.This seems like really odd behaviour from jest. I would expect that when I call jest.mock on a module, any module under test that has a dependency on the mocked module would use the mock. Does this seem bizarre that it doesn’t work that way, or am I going about this completely incorrectly?
@SimenB In your example, you’re requiring the mocked module, and executing it in the test, which does work. Would you expect the scenario I described above to work as well? Thanks so much.
@schumannd is right. Please make the official documentation more clear and crisp.
So
jest.mock
is being hoisted to the function scope, that’s why it won’t work withrequire
s (and definitely notimport
s which are hoisted to module scope) if you call it inside a function other thandescribe
(which is treated specially by Jasmine). Yourjest.mock
call will be hoisted to the top of that very function (not the module), that’s why it won’t work the way you expect.Generally we advise to setup different mocks in
beforeEach
andafterEach
if you want them different across test cases.@cpojer could elaborate on this in detail, and if we want to hoist the calls to the upper scopes.
This is what worked for me to mock a custom hook being used inside code for specific test suite.
and
useCustom
hook would be something like thisand the component under testing
MyComponent
will be something like thisJust encountered this really tedious bit of error (react), but I think I figured it out. The solution was staring at me all this time. this bit of info in the documentation is the key:
Warning: Importing a module in a setup file (as specified by setupFilesAfterEnv) will prevent mocking for the module in question, as well as all the modules that it imports.
This means that if you happen to have imported a module that also uses/imports that module (that you are about to mock) in the setup file, you will not be able to mock that module! In my case, I was refactoring my code so that everything that relates to testing is in one export (index) file (including the methods I was about to mock! It’s a Graphql + MSW setup).
@gcox example contains most of the information which I have been searching for in the docs for the past few hours. I suggest that it should be included in the official documentation which is very sparse at the moment anyway.
@baspinarenes 's solution worked for me! Thanks!
worked like magic very good @SimenB
I will share my example for those in the same situation. I tried with the following codes:
And I couldn’t mock it. I realized later. I needed to mock axios before importing the file I’m using it. So:
I can move it to
beforeEach
:And I can override the global mock (simplified):
mock
anddoMock
difference is only about hoisting. I hope it solves some people’s problem.You have to import myModuleToTest after your mock because if it imports before the mock does not make sense. So, don’t use import … on top or inside the callback because it’s hoisted anyway.
On Tue, Jul 7, 2020, 10:24 PM Antonio Redondo notifications@github.com wrote:
Had a struggle with multiple methods here to refactor a test previously written in mocha and proxyquire, end up with separating the test into different files for different mock.
Sure. Here it is: https://github.com/tleunen/jest-issue-2582
Both tests render “Disabled” even though one of then has a mock to renders “Enabled” instead. See these: https://github.com/tleunen/jest-issue-2582/blob/master/src/MyComponent.js https://github.com/tleunen/jest-issue-2582/blob/master/src/__tests__/MyComponent.spec.js
Thanks.