-
-
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 spyOn() calls the actual function instead of the mocked #6972
Comments
@NERDYLIZARD sorry for the delay here! By default jest.spyOn() does not override the implementation (this is the opposite of jasmine.spyOn). If you don't want it to call through you have to mock the implementation: const callApi = jest.spyOn(apiMiddleware, 'callApi').mockImplementation(() => Promise.resolve()); |
I seem to be having this problem as well, but the solution that @rickhanlonii proposed isn't working for me. I'm following the documentation for processing.js const saveVisit = (visit) => {
return database.put(visit)
}
const processVisit = (visit) => {
if (visit.status.includes('PROCESSED') {
saveVisit(visit)
return promise.resolve()
}
saveVisit({ ...visit, status: ['PROCESSED'] })
return visit.status
} processing.test.js const subject = require('../processing')
test('processVisit for processed visit returns null', () => {
const visit = { status: ['PROCESSED'] }
jest.spyOn(subject, 'saveVisit').mockImplementation(() => Promise.resolve())
return subject.processVisit(visit).then(result => expect(result).toBeNull())
}) |
@JonathanHolvey : did you solve this problem ? I seem to have hit it - but the weird thing is that an "it()" above the failing spy does work
|
ah, just forget what I said. Brain fart - my controller was calling the wrong service ... |
Why is this issue closed, since it's not resolved? I opened a question on StackOverflow: Any solutions? |
I am running into the same issue. I even tried the mockImplementation but still it hits the original function. |
I'm having the same issue with something like this: original.js
original.test.js
The output is
|
Same issue here! |
I have same issue when try mocking
|
i solved same problem by exporting default object with all methods, so @NERDYLIZARD's code would look like that:
apiMiddleware.spec.js
|
@tranvansang try |
Hello everyone 😊 As I was taking a look into this I first tried to add a very simple test to check whether this specific behaviour was present in the current version of master. The test-case below is based on one of the comments in this issue. it('does not call the mocked function', () => {
let originalCallCount = 0;
let fakeCallCount = 0;
const obj = {fn: () => originalCallCount++};
moduleMocker.spyOn(obj, 'fn').mockImplementation(() => fakeCallCount++);
obj.fn();
expect(originalCallCount).toBe(0);
expect(fakeCallCount).toBe(1);
obj.fn();
expect(originalCallCount).toBe(0);
expect(fakeCallCount).toBe(2);
}); I also tried the test-case suggested by @tranvansang and I didn't find problems: it('works for dates', () => {
moduleMocker.spyOn(Date, 'now').mockImplementation(() => 1);
expect(Date.now()).toBe(1);
}); This test passes just fine, demonstrating that the original function is never actually called. This means the behaviour seems correct on jest's side. Then I went on to check for edge-cases but none caused the tests to call the original function. I even checked whether it could be because
However, tests would indeed fail when the function property we're trying to mock is not For this, I used a variation of the first test. it('works for non-writable properties', () => {
let originalCallCount = 0;
let fakeCallCount = 0;
const obj = {};
Object.defineProperty(obj, 'fn', {
value: () => originalCallCount++,
writable: false,
configurable: true,
});
moduleMocker.spyOn(obj, 'fn').mockImplementation(() => fakeCallCount++);
obj.fn();
expect(originalCallCount).toBe(0);
expect(fakeCallCount).toBe(1);
obj.fn();
expect(originalCallCount).toBe(0);
expect(fakeCallCount).toBe(2);
}); The test above will fail with the following error:
In the case above it doesn't need to fail. It could simply use I can't think of any other ways of reproducing this. If any of you could provide a minimum reproducible snipped I wouldn't mind looking into it and checking why it happens and if it's a problem in jest's side or not. |
@KateBog that did not work, though. @lucasfcosta have you tried with some babel configuration? I remember while debug, some babel plugins transpile all Date.now to a new variable named The only way I can make it work is here My babel config you can try if want to reproduce
|
Hi, @tranvansang thanks for your clarification 😊 Do you think it would be possible for you to provide a repo with a minimum reproducible? It's a bit difficult to track down the problem by trying to put multiple separate pieces together especially since I don't have the same context as you when it comes to all the post-processing applied to the code or how it gets built before it runs or even what code does As per my post above, I don't think there's anything wrong on Jest's side but instead, I suspect there's something weird happening elsewhere (perhaps on any of the transformations that happen to your code). If that's the case maybe we could suggest adding something specific in Thanks for understanding 💖 |
Here is the minimal repo https://github.com/tranvansang/flip-promise/tree/now It is definitely because of the |
Hi @tranvansang, I just cloned the repo you have mentioned and there are no tests using mocks. I tried to add one myself (the one for Are you sure you linked the correct repo? If you did, how can I reproduce this issue there? |
@lucasfcosta that is the repo for my public package. I made a branch named Did you try this test? https://github.com/tranvansang/flip-promise/blob/now/index.test.ts#L3 |
Ah, it makes sense now, I had tried |
For me, this was an error because of how modules were being imported. I was mocking a function inside the same file as the function I was calling. More details about it here: https://stackoverflow.com/questions/45111198/how-to-mock-functions-in-the-same-module-using-jest Importing the module into itself and using it as a reference seemed to solve it, although kinda janky:
Not the greatest, but works. Otherwise, take the function out into a different file. |
Did anyone figure out why this is happening? |
None of the examples proved in this issue are correct usage of From the OP, #6972 (comment): same issue A PR improving the docs here would be greatly appreciated as it seems we're not clear enough on how it works. There's no magic here - we literally replace a function of the name on the object you pass, and call through to it. If anyone can put together a small repo showing the error (or a code sandbox) showing how https://www.snoyman.com/blog/2017/10/effective-ways-help-from-maintainers |
My solution involved making sure to define the mockImplementation as async correctly. I'm guessing that, since the mocks in these examples return promises they are mocking async functions. So the anonymous mock should also be defined as async: |
I managed to get past this with reference to this blog post like:
|
In case anyone is still plagued by this issue, this short article does a great job of explaining the root cause (it is due to babel compilation). Arguably it's not pretty, but adding the additional layer of indirection worked for me. |
Still having this issue. Not sure why this is closed. |
I found a solution, at least for my use-case. I was trying to mock import React from 'react';
import { render } from '@testing-library/react';
import { MyComponentThatUsesUseEffect } from './MyComponentThatUsesUseEffect'
test('My test case', () => {
const useEffectSpy = jest.spyOn(React, 'useEffect').mockImplementation(() => {});
render(<MyComponentThatUsesUseEffect />);
expect(useEffectSpy).toHaveBeenCalled();
}); Didn't work. But then I was changing - import React from 'react';
+ import * as React from 'react'; So I have this ⬇️ import * as React from 'react';
import { render } from '@testing-library/react';
import { MyComponentThatUsesUseEffect } from './MyComponentThatUsesUseEffect'
test('My test case', () => {
const useEffectSpy = jest.spyOn(React, 'useEffect').mockImplementation(() => {});
render(<MyComponentThatUsesUseEffect />);
expect(useEffectSpy).toHaveBeenCalled();
}); Now it does work 👍🏼 Maybe this will work for your thing to and or give you a clue of what's happening |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
I'm testing
apiMiddleware
that calls its helper functioncallApi
. To prevent the call to actualcallApi
which will issue the api call, I mocked the function. However, it still gets called.apiMiddleware.js
apiMiddleware.spec.js
Please ignore the action's properties and argument of
callApi
function. I don't think they are the concern of the point I'm trying to make.Tell me if you need further elaboration.
stackoverflow
The text was updated successfully, but these errors were encountered: