Thanks for this, very useful. I'm having a bit of trouble with this though...
my mockResolvedResponse is being returned undefined and I have no idea why!
importaxiosfrom"axios";import{Users}from"./api-call"jest.mock('axios')describe('axios tests with mocking',()=>{test('should fetch posts',async()=>{constfakeResp=[{"userId":1,"id":2,"title":"qui est esse","body":"est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"}]mockedAxios.get.mockRejectedValue('Network error: Something went wrong');mockedAxios.get.mockResolvedValue(fakeResp)constaxiosSpy=spyOn(mockedAxios,'get')constresult=awaitUsers.all()expect(result).toEqual(fakeResp)//❌Fails....expect(axiosSpy).toHaveBeenCalledTimes(1)//✔Passes!});});
Full stack developer building things to make life a little easier. Huge fan of JavaScript, React, Node.js, and testing my code. • twitter.com/ZakLaughton • zaklaughton.dev
Sure! I'm not sure exactly what the root cause is, but I've got some troubleshooting steps to start.
My observations
jest.mock() vs jest.spyOn()
Looks like here you are using jest.mock() and jest.spyOn() here on the same function. Usually, these are used interchangeably, but not together. Both functions let you inspect how the function was called. The difference between the 2 is that jest.mock() completely blows away the original function being mocked, while jest.spyOn() keeps the original implementation so the function runs as it is was written. In most cases, I find I only need jest.mock(). (This article seems to do a good job diving into the comparison a bit more Understanding Jest mocks)
Here, it looks like you're spying on your mock, which is redundant, and might have unpredictable results. I'm not sure if that's the issue here, but it's a layer of complexity I'd take out. You should be able to check on the number of calls without the spy (see my suggestion in "What I'd do" below).
Mocking resolved and rejected values
Here, you're using mockedRejectedValue() and mockResolvedValue() on the same function:
mockedAxios.get.mockRejectedValue('Network error: Something went wrong');mockedAxios.get.mockResolvedValue(fakeResp)
This is redundant because each one will completely overwrite the mocked implementation, so first you set it to reject (no matter what), then you set it to resolve no matter what. Since your expected output (mockResolvedValue(fakeResp)) comes second, the .mockRejectedValue('Network error: Something went wrong') has no impact here. It won't change the output, but I'd remove it just to reduce the complexity for troubleshooting.
- mockedAxios.get.mockRejectedValue('Network error: Something went wrong');
If the issue still isn't resolved, you can dig into what axios.get is being called with and what it's returning:
console.log("axios.get() called with>>>",axios.get.mock.calls[0]);console.log("axios.get() returns>>>",axios.get.mock.results[0]);
This should show exactly how axios.get() is being called in Users.all() (see more details on this type of mock call inspection in the jest docs here: Mock Functions). You can also throw some console.logs in the actual Users.all() function, too, which will also output to the terminal during the test.
can i except the data in the screen to bind in the front end like
expect(screen.getByText(''my first album')).toBeInTheDocument();
but i try this above line ,it should not work .give any soltuion for that?
I forgot to mention one crucial piece of information. I'm trying to do this with TypeScript! ** plot-twist! **
This means I get errors when trying to use axios.get.mock. I think this why I started playing around with jest spies, as it a bit more of type friendly method of getting the assertion metadata out.
Full stack developer building things to make life a little easier. Huge fan of JavaScript, React, Node.js, and testing my code. • twitter.com/ZakLaughton • zaklaughton.dev
That should at least pass type checking and give you the auto-complete in your editor for mock functions. This should be good enough to at least get it working. If I remember correctly though, it won't actually check the types on the resolved value, so fakeResp could be any type, even if it doesn't match the return type of Users.all(). You'll also have to add as jest.Mock everywhere you call axios.get
If you want stricter typing for this without needing to cast as jest.Mock each time, I've had a great experience with ts-jest. Looks like they've updated a lot since I used it last, so I can't give a syntax example, but you can check out their docs.
tl;dr: use (axios.get as jest.Mock) for generic mock function types, or use a tool like ts-jest for stricter types of that specific mock function.
Thank you so much! Was finally able to get the test passing! The trick of using (axios.get as jest.Mock) was the key to letting me debug this thoroughly.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Thanks for this, very useful. I'm having a bit of trouble with this though...
my
mockResolvedResponse
is being returned undefined and I have no idea why!any ideas if I'm doing something silly?
Sure! I'm not sure exactly what the root cause is, but I've got some troubleshooting steps to start.
My observations
jest.mock()
vsjest.spyOn()
Looks like here you are using
jest.mock()
andjest.spyOn()
here on the same function. Usually, these are used interchangeably, but not together. Both functions let you inspect how the function was called. The difference between the 2 is thatjest.mock()
completely blows away the original function being mocked, whilejest.spyOn()
keeps the original implementation so the function runs as it is was written. In most cases, I find I only needjest.mock()
. (This article seems to do a good job diving into the comparison a bit more Understanding Jest mocks)Here, it looks like you're spying on your mock, which is redundant, and might have unpredictable results. I'm not sure if that's the issue here, but it's a layer of complexity I'd take out. You should be able to check on the number of calls without the spy (see my suggestion in "What I'd do" below).
Mocking resolved and rejected values
Here, you're using
mockedRejectedValue()
andmockResolvedValue()
on the same function:This is redundant because each one will completely overwrite the mocked implementation, so first you set it to reject (no matter what), then you set it to resolve no matter what. Since your expected output (
mockResolvedValue(fakeResp)
) comes second, the.mockRejectedValue('Network error: Something went wrong')
has no impact here. It won't change the output, but I'd remove it just to reduce the complexity for troubleshooting.mockRejectedValue()
is typically only needed if you are explicitly testing an error state (See also: Jest docs for mockRejectedValue() and mockResolvedValue()).What I'd do
With the notes above, I'd remove some of the redundant code, then if it's still not working, dig into how the mocked function is being called:
Remove the
spyOn()
Remove the
mockRejectedValue()
If the issue still isn't resolved, you can dig into what
axios.get
is being called with and what it's returning:This should show exactly how
axios.get()
is being called inUsers.all()
(see more details on this type of mock call inspection in the jest docs here: Mock Functions). You can also throw some console.logs in the actual Users.all() function, too, which will also output to the terminal during the test.Here's an example of what that console.log output looks like when I add it to the sample code from this article:
I hope this helps!
can i except the data in the screen to bind in the front end like
expect(screen.getByText(''my first album')).toBeInTheDocument();
but i try this above line ,it should not work .give any soltuion for that?
Wooah thanks for such a detailed reply!
I forgot to mention one crucial piece of information. I'm trying to do this with TypeScript! ** plot-twist! **
This means I get errors when trying to use
axios.get.mock
. I think this why I started playing around with jest spies, as it a bit more of type friendly method of getting the assertion metadata out.Ah, got it! Yeah, how to type mock functions is not immediately clear. Try this:
That should at least pass type checking and give you the auto-complete in your editor for mock functions. This should be good enough to at least get it working. If I remember correctly though, it won't actually check the types on the resolved value, so
fakeResp
could be any type, even if it doesn't match the return type ofUsers.all()
. You'll also have to addas jest.Mock
everywhere you call axios.getIf you want stricter typing for this without needing to cast as jest.Mock each time, I've had a great experience with ts-jest. Looks like they've updated a lot since I used it last, so I can't give a syntax example, but you can check out their docs.
tl;dr: use
(axios.get as jest.Mock)
for generic mock function types, or use a tool like ts-jest for stricter types of that specific mock function.Thank you so much! Was finally able to get the test passing! The trick of using
(axios.get as jest.Mock)
was the key to letting me debug this thoroughly.