-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jest.clearAllMocks(); does not remove mock implementation within afterEach
#7136
Comments
As I understand the parallel execution model of jest the tests inside each suite are run sequentially so you should be able to mock per individual test. |
FYI The mocking documentation and API is extremely unclear, and overly complicated IMHO. |
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 |
@rickhanlonii my issue is not yet answered. I want to remove the mocks. |
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) |
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.....????? |
This should be reopened |
+1 |
2 similar comments
+1 |
+1 |
I have a similar issue, when I mock an implementation in previous it case, the next it case will be affected. |
+1 |
also struggling with this! |
+1 please update the docs to explain how to REMOVE a mock/spy |
Isn't this what mockRestore is for? https://jestjs.io/docs/en/mock-function-api#mockfnmockrestore |
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. |
`
}) console.log test/routes.test.js:36 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 |
+1 🥂 |
+1 |
+1 |
+1 |
functions mocked with I agree that mocks should be cleared automatically between tests, though. |
+1 |
1 similar comment
+1 |
Is there a fix for this issue? +1 |
Facing the same issue! |
mockClear clears only data pertaining to mock calls mockReset resets to mock to its initial implementation. Have a read of this on SO basically if you change mocks between tests then your mock changes, but the mock is not reset as its not been used (at least my understanding) resetModules and resetMocks is i think the right setup - keen to get a consensus though. |
As explained in the link you sent, I'm understanding that the I've been using the |
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 // /__mocks__/fs.ts
// here we declare mocks we want persisted
const mockFs = {
stat = jest.fn(() => ({ size: 100, blocks: 2, ... })
}
export default mockFs and depend on that mock to test ./do-something.ts // /do-something.test.ts
// declare 'let' for each dependency
let fs: jest.MockedObject<typeof import('fs')>
let doSomething: typeof import('./do-something')
beforeEach(() => {
jest.resetAllMocks()
jest.resetModules()
fs = require('fs').default
doSomething = jest.requireActual('./do-something').default
})
describe('some block', () => {
it('should return a 404', () => {
fs.stat.mockImplementation(() => throw new Error('file not found'))
doSomething() // will have the mock implementation above
})
it('should work', () => {
doSomething() // will have the mock implementation from /__mocks__/fs.ts
})
}) |
I think if you used |
@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. |
I really have to wonder why facebook does not seem to have those problems? How are they testing over there?! |
This is a good imo |
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. |
This worked for me ! |
^^ this should really be considered. |
But even this default config does not work reliably :( How is facebook working with such a broken test framework? |
I think after whichever test you want to reset/clear the mock, you should add there
Because that did the job for me. |
@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. |
- now that the integration tests exist, we can actually test this scenario - refactor: give each test their own `onwarn` mock when necessary - while `restoreMocks` is set in the `jest.config.js`, Jest apparently has poor isolation of mocks: jestjs/jest#7136 - if two tests ran in parallel, `onwarn` was getting results from both, screwing up the `toBeCalledTimes` number - couldn't get the syntax error to work with `toBeCalledTimes` either - if no mock is given, it _does_ print warnings, but if a mock is given, it doesn't print, yet isn't called? - I think the mock is getting screwed up by the error being thrown here; maybe improperly saved or something
…es) (#345) * fix: type-check `include`d files missed by transform (type-only files) - type-only files never get processed by Rollup as their imports are elided/removed by TS in the resulting compiled JS file - so, as a workaround, make sure that all files in the `tsconfig` `include` (i.e. in `parsedConfig.fileNames`) are also type-checked - note that this will not catch _all_ type-only imports, in particular if one is using `tsconfig` `files` (or in general _not_ using glob patterns in `include`) -- this is just a workaround, that requires a separate fix - we do the same process for generating declarations for "missed" files right now in `_onwrite`, so basically do the same thing but for type-checking in `_ongenerate` (_technically_ speaking, there could be full TS files (i.e. _not_ type-only) that are in the `include` and weren't transformed - these would basically be independent TS files not part of the bundle that the user wanted type-checking and declarations for (as we _already_ generate declarations for those files)) * move misssed type-checking to `buildEnd` hook, remove declarations check - `buildEnd` is a more correct place for it, since this does not generate any output files - (unlike the missed declarations) - and this means it's only called once per build, vs. once per output - remove the check against the `declarations` dict as one can type-check without outputting declarations - i.e. if `declaration: false`; not the most common use-case for rpt2, but it is one * add new checkedFiles Set to not duplicate type-checking - since `parsedConfig.fileNames` could include files that were already checked during the `transform` hook - and because `declarations` dict is empty when `declaration: false`, so can't check against that * move checkedFiles.add to the beginning of typecheckFile - because printing diagnostics can bail if the category was error - that can result in a file being type-checked but not added to checkedFiles * wip: fuse _ongenerate functionality into buildEnd, _onwrite into generateBundle - per ezolenko, the whole generateRound etc stuff was a workaround because the buildEnd hook actually _didn't exist_ before - so now that it does, we can use it to simplify some logic - no longer need `_ongenerate` as that should be in `buildEnd`, and no longer need `_onwrite` as it is the only thing called in `generateBundle`, so just combine them - importantly, `buildEnd` also occurs before output generation, so this ensures that type-checking still occurs even if `bundle.generate()` is not called - also move the `walkTree` call to above the "missed" type-checking as it needs to come first - it does unconditional type-checking once per watch cycle, whereas "missed" only type-checks those that were, well, "missed" - so in order to not have duplication, make "missed" come after, when the `checkedFiles` Set has been filled by `walkTree` already - and for simplification, just return early on error to match the current behavior - in the future, may want to print the error and continue type-checking other files - so that all type-check errors are reported, not just the first one NOTE: this is WIP because the `cache.done()` call and the `!noErrors` message are incorrectly blocked behind the `pluginOptions.check` conditional right now - `cache.done()` needs to be called regardless of check or error or not, i.e. in all scenarios - but ideally it should be called after all the type-checking here - `!noErrors` should be logged regardless of check or not - and similarly, after the type-checking * call `cache().done()` and `!noErrors` in check and non-check conditions - instead of making a big `if` statement, decided to split out a `buildDone` function - to always call at the end of the input phase - we can also move the `cache().done()` in `emitSkipped` into `buildEnd`, as `buildEnd` gets called when an error occurs as well - and this way we properly print for errors as well - `buildDone` will have more usage in other PRs as well, so I figure it makes sense to split it out now as well * use `RollupContext` for type-only files - i.e. bail out when `abortOnError: true`, which `ConsoleContext` can't do - `ConsoleContext` is basically meant for everywhere `RollupContext` can't be used - which is effectively only in the `options` hook, per the Rollup docs: https://rollupjs.org/guide/en/#options * 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 `restoreMocks` is set in the `jest.config.js`, Jest apparently has poor isolation of mocks: jestjs/jest#7136 - if two tests ran in parallel, `onwarn` was getting results from both, screwing up the `toBeCalledTimes` number - couldn't get the syntax error to work with `toBeCalledTimes` either - if no mock is given, it _does_ print warnings, but if a mock is given, it doesn't print, yet isn't called? - I think the mock is getting screwed up by the error being thrown here; maybe improperly saved or something
Yea I have I've tried calling
@SimenB I reproduced this pretty consistently in ezolenko/rollup-plugin-typescript2#345 (comment) / ezolenko/rollup-plugin-typescript2@01373c1 if that helps with narrowing this down. At least in my case, basically, if two tests ran in parallel, the top-level mock would have state from both tests, instead of isolated state in each test. The workaround I used for this was to create mocks per-test (i.e. inside each individual test's scope, instead of using a top-level mock). That's in the commit linked above, without that workaround, the tests will fail due to the mock sharing state between parallel tests. That sounds like possibly correct behavior (given concurrency constraints), but it also sounds like |
@agilgur5 for me |
@paulmax-os
I'm not sure that these are related? I don't have a need or use-case for these |
@agilgur5 yeah, I just wanted to share a (another) working "solution" for anyone reaching this page. I am using the |
did you find a solution in the end? nothing seems to work |
For me it worked in the end by doing this: let wrapper;
beforeEach(() => {
wrapper = null;
jest.clearAllMocks();
})
it('makes bar out of foo', async () => {
const mockMethod = jest
.spyOn(Class, 'methodName')
.mockImplementation();
wrapper = someActionYouWantToPerform('foo');
await flushPromises(); // depends on your implementation
expect(mockMethod).toHaveBeenCalledWith('foo');
}); |
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 😊 |
my function is still being mocked after calling: jest.restoreAllMocks()
jest.resetAllMocks()
jest.clearAllMocks() am i missing something? |
I too can call all three function and set the equivalents in config, and my call counts still retain their increments from one test to the next. The only thing that works for me to to create new mocks in beforeEach: import createMockInstance from "jest-create-mock-instance";
describe("MyUnitUnderTest", () => {
let reservationRepo: jest.Mocked<ReservationRepository>;
let eventPublisher: jest.Mocked<EventPublisherService>;
let usecase: MyUnitUnderTest;
beforeEach(() => {
reservationRepo = createMockInstance(ReservationRepository);
eventPublisher = createMockInstance(EventPublisherService);
usecase = new MyUnitUnderTest(reservationRepo, eventPublisher);
}); |
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. |
I solve my issue saving the original behavior from my function in another const and after it restore my behavior to original function. const MyObject = {
getValue() {
return 'original value'
}
}
describe('Test restore original implementation', function () {
const originalObjectState = {...MyObject}
test('Mock original function', async function () {
MyObject.getValue = jest.fn(() => 'mocked value')
const value = MyObject.getValue()
expect(value).toBe('mocked value')
});
test('Restore original function', async function () {
MyObject.getValue = originalObjectState.getValue
const value = MyObject.getValue()
expect(value).toBe('original value')
});
}); |
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. |
🐛 Bug Report
jest.clearAllMocks(); does not remove mock implementation within
afterEach
To Reproduce
I have a file called src/layouts/index.js
It utilizes webpack
require.context
so I am trying to mock with jest.mock.I have another file... say file util.js
in my test I'm trying to clear the mocks after each test
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)
https://repl.it/@CharlieHoover/SorrowfulBackSandboxes
The text was updated successfully, but these errors were encountered: