jest: jest.clearAllMocks(); does not remove mock implementation within `afterEach`
š Bug Report
jest.clearAllMocks(); does not remove mock implementation within afterEach
To Reproduce
I have a file called src/layouts/index.js
// ./src/layouts/index.js
const importAll = (r) =>
r.keys().reduce(
(acc, key) => ({
...acc,
[key.replace(/^\.\/(.*).json$/, '$1')]: r(key)
}),
{}
);
module.exports = importAll(require.context('./', true, /\.json$/));
It utilizes webpack require.context
so I am trying to mock with jest.mock.
I have another fileā¦ say file util.js
//./src/util.js
import layouts from '../layouts';
export const getLayout(name) {
return layouts[name];
}
in my test Iām trying to clear the mocks after each test
//./src/util.test.js
describe('my test suite', () => {
afterEach(() => {
jest.clearAllMocks();
})
test('test number one', () => {
jest.mock('./layouts', () => ({
layout1 : { a : 1 },
layout2 : { b: 2 },
}));
assert.equals(getLayout('layout1').a, 1);
assert.equals(getLayout('layout2').b, 2);
});
test('test number two', () => {
assert.equals(getLayout('layout1').a, 1);
assert.equals(getLayout('layout2').b, 2);
});
});
Expected behavior
I would expect for the first test to pass and the second test to failā¦ because the mock should have been cleared.
Link to repl or repo (highly encouraged)
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 6
- Comments: 105 (4 by maintainers)
Commits related to this issue
- add test for type-only file with type errors - now that the integration tests exist, we can actually test this scenario - refactor: give each test their own `onwarn` mock when necessary - while `r... — committed to agilgur5/rollup-plugin-typescript2 by agilgur5 2 years ago
- fix: type-check `include`d files missed by `transform` (type-only files) (#345) * fix: type-check `include`d files missed by transform (type-only files) - type-only files never get processed by Ro... — committed to ezolenko/rollup-plugin-typescript2 by agilgur5 2 years ago
FYI The mocking documentation and API is extremely unclear, and overly complicated IMHO.
jest.clearAllMocks
does not remove mock implementations by design - tryjest.resetAllMocks
Here are the relevant docs:
I think the default config should include:
It is shocking that the default behaviour is to vomit state between tests. Can you please just keep my tests isolated by default? Then the [hopeful minority] who want to spread state across multiple tests can do so by opt-in.
IMO this is a super confusing API naming and deserves to be renamed.
This should be reopened
Still does not work with resetAllMocks:
Example included:
https://repl.it/@CharlieHoover/SorrowfulBackSandboxes-2
Aside from that that is extremely ambiguous. Why would a function called clearAllMocks not clear the mocksā¦ Name the function
resetMockState
or something more descriptive.clearAllMocks
implies the mocks are being cleared.@rickhanlonii
omg so #1 it seems like āclearā and āresetā are being used opposite to what their logical meaning is.
Also, itās very clear what heās trying to do; remove the mock implementation, and youāre saying thereās no way to do that orrrā¦???
I agree that it is āunprofessionalā, I and all others who have maintained Jest in the last ~2 years have done it in their free time, thus not professionally. Iād stop short of āincompetenceā though. Either way, please do not use the issue tracker for off-topic comments or (successful or unsuccessful) abuse; such comments will be hidden or reported.
Is anyone ever going to do something about this? I am also facing the same issue.
+1 It seems to me that clearing the mocks after each test should be the default behavior.
For me,
jest.restoreAllMocks();
helped finally clear the spy on jestThis is still a problem
@SimenB would you kindly triage this for us? Itās a very old issue that could be either a serious problem or just a documentation task. It remains untagged with no consensus on what it really is.
Until we get this issue tagged so it becomes reachable, it will remain a mystery whether or not itās actually bugged or thereās a large misunderstanding from lack of documentation. People only end up here because of search engine results.
For anyone running into this, Iāve set the command line flag
--restoreMocks
which can also be set injest.config.js
:As the default for my tests so that mocks are always restored each after test run. Here is the documentation link: https://jestjs.io/docs/en/configuration#restoremocks-boolean
Isnāt this what mockRestore is for? https://jestjs.io/docs/en/mock-function-api#mockfnmockrestore
` describe(ātestā, () => { beforeEach(() => { const WelcomeService = require(ā./ā¦/SOME_MODULEā) WelcomeServiceSpyOfMessage = jest.spyOn( WelcomeService, āmessageā, // some function I mocked ) const IsUserAuthentic = require(ā./ā¦/SOME_MODULEā) IsUserAuthenticSpyOnIsUserAuthentic = jest.spyOn( IsUserAuthentic, āisUserAuthenticā // some function I mocked ) app = require(āā¦/src/serverā) // my Express server })
}) ` Output: console.log test/routes.test.js:36 >>> MOCKED MW 1
console.log test/routes.test.js:36 >>> MOCKED MW 1
Same mocked version of function is called for both the tests. Although I have restored all mocks in afterEach call, still same mock is getting called. Please tell me where I missed.
Thanks
I have a similar issue, when I mock an implementation in previous it case, the next it case will be affected.
@rickhanlonii my issue is not yet answered. I want to remove the mocks.
@SimenB Hi, could you add some labels to this issue? Itās a pretty hot topic and is indexed on google, but it seems like it is outside of the radar of those who can assist with this since it is not tagged with anything.
this worked for me
Anyone looking for a solution in 2021 , this fixed the issue for me š
Are any of the maintainers paying attention? Tests need to run in total isolation otherwise they are worthless.
has anyone found a fix for this ?
I am passing
jest.clearAllMocks
resetAllMocks
underbeforeEach
and it definitely is still not clearing themockImplementation
All other mock frameworks I can remember using across languages hook into the test framework to automatically reset all test doublesā state to the pristine declared form after each individual example run.
Any other behavior results in unexpected non-deterministic and order-dependent behavior when running multiple examples in the same suite.
And in this case, there doesnāt even seem to be a way to manually achieve the desired behavior.
Itās confusing and mystifying why Jest wouldnāt just reset everything after each example by default.
my function is still being mocked after calling:
am i missing something?
@JRRS1982 try doing inside some
it
something like this:you will see that from that moment on, all the tests that are running after this test, will get āfake-valueā if they try to import
someModule
. that means that you have a leak between tests. if your other tests will count on that return value, and youāll ever remove this test, all the other tests will fail. and there are more serious issues that leaks like this can cause.I just came across
mockRestore
, which works if you are usingspyOn
.https://jestjs.io/docs/en/mock-function-api#mockfnmockrestore
I have mocked a module in my jest setup like this
jest.mock('containers/PatientsList/SignalRConnection')
you can unmock it by using
jest.unmock("containers/PatientsList/SignalRConnection")
It didnāt work in beforeEach and beforeAll, so I had to put it above describe and it workedGot a nasty issue where tests work with
.only
but fail in sequence. Tried the clear/reset/restore triad with all sorts of configurations described in this issue page and still no results. Worst part is, I have whole suites that have been working just fine with the same setup/teardown.Unit tests should be isolated from each other on principle, itās a tremendous problem for Jest to not have it. Who knows how many unit tests are out there with strange behavior inherited by this.
With the info on this page, now I canāt even tell if Jest āunitā tests are even to be trusted because this teardown seems so impossible to gauge. Itās that huge.
@SidKhanna296
jest.restoreAllMocks()
is the one youāre looking for.I have no idea why this makes the difference, but I managed to work around this by swapping
for
I assumed they would achieve the same result - make sure the state of the mock at the end of one test doesnāt impact the next - but apparently not š¤·
@pkyeck It seems to depend on the environment. If I run the test suite in my local environment it clears all the mocks, but when I run it inside a docker container it doesnāt seem to reset them properly.
Facing the same issue!
same here, is there a work around for static properties as we shouldnāt have to change our implementation to pass a unit test. Atleast, I never do.
For me the problem was that I had a static property. And the problem happened since they arenāt part of the instance and are remembered. I have changed it to a normal class property. and it worked (clearAllMocks), maybe someone else didnāt pay attention to this and had the same issue š
damn, Iāve just struggled too much trying to get why clear or reset mocks donāt actually CLEAR and RESET mocks, thank you!!! you are my savior
I havenāt been able to find a working way of doing any of those combinations, unfortunately.
I can confirm @Niryo comment. I have 3 tests, one of which needs to mock axios. If I put that test first, all my other tests fail (they use axios but donāt need to mock it for that use case), and if I put it last, when I actually mock the API call they all pass.
As simple as that š @XxAmrIbrahimxX
For what its worth I found that clearAllMocks stopped working properly after an upgrade of our app. replaced is with this and things seem to pass:
afterEach(()=> {jest.restoreAllMocks()});
@ewhauser neither the command line flag nor the config-option is working for me. once I mock a module, it stays mocked till I overwrite the mock š¦
are you sure it is working for you?
functions mocked with
.spyOn()
can be restored:jest.spyOn(object, method).mockImplementation(mockFunction)
.I agree that mocks should be cleared automatically between tests, though.
+1 please update the docs to explain how to REMOVE a mock/spy
Ah, yeah, looks like resetAllMocks does not reset mock module factories just the implementations set by mockImplementation. If you want to post what you want to do to stackoverflow I can help you do what you want there but it doesnāt look like thereās a bug here
I think the confusion is that the āmockā in āclearAllMocksā does not refer to the mock implementations, it refers to the Jest mock objects. So this function means āclear out all jest mock objectsā which is to say call .mockClear on all mock objects (i.e. clear the calls)
For me it worked in the end by doing this:
@agilgur5 for me
jest.restoreAllMocks()
is working fine when itās called from withinafterEach()
. Furthermore I usedmockReturnValueOnce()
andmockResolvedValueOnce
. Maybe this helps?Still canāt find a solution.
Iām testing a class instance and I need to mock one of the class functions that is called by another other function in the same class.
I tried all the ācleanā methods, even together, in the file (before, after) and in the configs.
Nothing worked.
If I change the order of the tests (so, I first test the function (A) and then I test the other function (B) that uses function A and it works.
Not sure what is wrong with it and how to fix it.
I think if you used
clearAllMocks
together withrestoreAllMocks
you wouldnāt need to re-require the dependencies. I may be wrong though, should be tested.to get around the issue, hereās a pattern that works for and makes sense to me
the issue for me was resetting my mocks to those which are declared in __mocks__ directories. The easiest solution I saw was to reset modules and re-require them before each test. This way resetAllMocks didnāt wipe out all the mocks I wanted persisted. Essentially only the one-off mocks I created in the tests are reset.
* the example is in typescript in case anyone has trouble figuring out the syntax there. Using require instead of dynamic import gets around typing nonsense
letās assume I mock fs.stat to return a particular object
and depend on that mock to test ./do-something.ts
Shouldnāt the
clearAllMocks
andrestoreAllMocks
combo work for any use case?clearAllMocks
clears all mock callsrestoreAllMocks
restores all mocked implementations to their default (non-mocked) stateThe way I see it, the
resetAllMocks
still keeps mocked implementations as mocks, only without return values or defined implementation.If Iām wrong here, anyone please correct me
I tried restoreAllMocks and all the other restores, resets, and clears and none of them worked for me.
@JRRS1982 i am using
resetModules
andresetMocks
. Itās not enough in terms of assuring isolation but at least itās not flaky@amirensit Iām using this now:
So you have to keep a list of all modules that you want to mock in one or multiple tests but the order of the tests doesnāt matter anymore (or .only/.skip or running all tests).
try it to solve direct mock implementations
It worked fine to me.
I found this helpful. Call this function with an await every time right after a mocked fn is expected to be called.
flushAllPromises() { return new Promise(resolve => setImmediate(resolve)); }
This should make the last call to YourClass.yourFunction.mockResolvedValue() in the executing test case to work, instead of relying on the resolved value of the last executed unit test.