Cover image for The only 3 steps you need to mock an API call in Jest

The only 3 steps you need to mock an API call in Jest

zaklaughton profile image Zak Laughton Updated on ・6 min read

I recently found myself working in a Javascript codebase where I needed to implement new Jest tests. I knew very little at the time about writing tests, so I looked to Jest docs and existing patterns in the codebase to figure out best practices and how to do it. It was fairly straightforward, and I even found myself enjoying testing. But I could not for the life of me reliably mock an API call.

Dog with caption "I have no idea what I'm doing"

The docs seemed clear, and the existing code appeared to have good patterns, but there were just so many ways to mock things. The existing tests used all sorts of mocking methods such as jest.genMockFromModule(), jest.spyOn(), and jest.mock(). Sometimes the mocks were inline, sometimes they were in variables, and sometimes they were imported and exported in magical ways from mysterious __mocks__ folders. I used these techniques interchangeably every time I got a burst of confidence in understanding, only to find myself stumbling over the different methods and their effects. I had no idea what I was doing.

The issue

The issue was that I was trying to learn how to run before I even knew how to walk. Jest has many powerful ways to mock functions and optimize those mocks, but they're all useless if you don't know how to make a simple mock in the first place. And while the Jest documentation provides a lot of great insight and techniques, I couldn't figure out where to start.

In this article, I hope to give you absolute basics to mock an API call so you can benefit from my 2020 hindsight (heh). If you're going crazy like I was because you can't figure out how to just make a simple damn mock, Start here…

(NOTE: The code below was written in Node.js, but the mocking concepts also apply to frontend Javascript and ES6 modules)

The unmocked code

We're going to be testing this getFirstAlbumTitle() function, which fetches an array of albums from an API and returns the title of the first album:

// index.js
const axios = require('axios');

async function getFirstAlbumTitle() {
  const response = await axios.get('https://jsonplaceholder.typicode.com/albums');
  return response.data[0].title;

module.exports = getFirstAlbumTitle;

...and here's our initial mock-less test for this function, which verifies the function actually returns the title of the first album in the list:

// index.test.js
const getFirstAlbumTitle = require('./index');

it('returns the title of the first album', async () => {
  const title = await getFirstAlbumTitle();  // Run the function
  expect(title).toEqual('quidem molestiae enim');  // Make an assertion on the result

The test above does its job, but the test actually makes a network request to an API when it runs. This opens the test up to all sorts of false negatives if the API isn't working exactly as expected (e.g. the list order changes, API is down, dev machine loses network connection, etc.). Not to mention, making these requests in a large number of tests can bring your test runs to a slow crawl.

But how can we change this? The API request is being made with axios as a part of getFirstAlbumTitle(). How in the world are we supposed to reach inside the function and change the behavior?

Mock it in 3 steps

Alright, here it is. This is the big secret that would have saved me mountains of time as I was wrestling with learning mocks. To mock an API call in a function, you just need to do these 3 steps:

1. Import the module you want to mock into your test file.
2. jest.mock() the module.
3. Use .mockResolvedValue(<mocked response>) to mock the response.

That's it!

Here's what our test looks like after doing this:

// index.test.js
const getFirstAlbumTitle = require('./index');
const axios = require('axios');


it('returns the title of the first album', async () => {
    data: [
        userId: 1,
        id: 1,
        title: 'My First Album'
        userId: 1,
        id: 2,
        title: 'Album: The Sequel'

  const title = await getFirstAlbumTitle();
  expect(title).toEqual('My First Album');

What's going on here?

Let's break this down. The most important part to understand here is the import and jest.mock():

const axios = require('axios');


When you import a module into a test file, then call it in jest.mock(<module-name>), you have complete control over all functions from that module, even if they're called inside another imported function. Immediately after calling jest.mock('axios'), Jest replaces every function in the axios module with empty "mock" functions that essentially do nothing and return undefined:

const axios = require('axios');

// Does nothing, then returns undefined:

// Does nothing, then returns undefined:
axios.post('https://jsonplaceholder.typicode.com/albums', {
    id: 3,
    title: 'Album with a Vengeance'

So now that you've eliminated the default behavior, you can replace it with your own...

    data: [
        userId: 1,
        id: 1,
        title: 'My First Album'
        userId: 1,
        id: 2,
        title: 'Album: The Sequel'

The mocked replacement functions that Jest inserted into axios happen to come with a whole bunch of cool superpower methods to control their behavior! The most important one here, for the purposes of a simple beginner mock, is .mockResolvedValue(). When you call this on a mocked method, anything you pass in will be the default return value when the mocked function is called for the remainder of the test. Simply put: you can make axios.get() return whatever you want! And it doesn't matter whether it's called directly in your test file or as a part of a function imported into your test – Jest will mock the function no matter where it's called!

Use this newfound power to give your functions exactly what they should expect from the API calls. Stop worrying about what the network requests return, and just focus on what YOUR code does once it gets the response!

If you want to play around with the examples, feel free to use this demo repository:

GitHub logo ZakLaughton / simple-api-mocking-with-jest

A simple API mocking example with Jest.

Wrapping up

There you have it! This is the very basics of what you need to mock functions from another module: import the module, jest.mock() the module, then insert your own return values with .mockResolvedValue()!

I recommend starting here, using only these techniques as you start building out your first mocks for your network calls. Once you have a foundational understanding of what's going on here, you can slowly start adding the other robust mocking features included in Jest.

See also: Mocking Modules (Jest documentation).

Where to go from here

Alright, you've learned the basics of mocking and successfully implemented the strategies above in several tests. You can import and mock resolved values for all your API calls like an old pro. What's next?

While the methods described above will cover most simple use cases, Jest has a lot of mocking functionality and methods to do some really powerful things. You can incrementally add some of the concepts below to super-charge your mocks:

  1. Check out the other mock function methods listed in the Jest docs: Mock Functions. You can use methods such as mockReturnedValue() to mock synchronous returns and mockResolvedValueOnce() to only return a value the first time it's called.
  2. Want to see how many times a mocked function is called, what it was called with, and what it returned? Check out the mock.calls and mock.results properties (also in the Mock Functions documentation)
  3. Do you have your own custom functions that make network requests? You can mock your own modules too after they're imported into the test file: jest.mock('./path/to/js/module/file')! Careful here though that you're only mocking what's necessary. Your tests should make sure your functions do what's expected with a given mock input, and it can be easy to end up writing tests that instead just confirm you passed in mocked data.
  4. Want a function to act as it was originally written, but still want to see how many times it was called? Check out jest.spyOn().
  5. Find yourself mocking the same function over and over in multiple tests? Give it default mock responses in __mocks__ folders using Manual Mocks!

I hope this saves others some of the wasted time and frustration I went through! If anything doesn't make sense here, please leave a comment and I'd be happy to try to answer any questions. Also, let me know if there's anything else that helped you have an "Aha!" moment while learning to mock!

Did you find this this article useful? Feel free to subscribe to my articles below or follow me on Twitter for more developer tips and article announcements!

Posted on by:

zaklaughton profile

Zak Laughton


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


markdown guide

Hey Zak, this is really great! I've been recently facing a similar problem, what would you think it's the best approach when the API also has some kind of auth system, like jwt for example? Right now, the API I'm talking about is tested with supertest and I'd like to switch to jest (with its mocks, because it's a pain sometimes run the tests), and this article is going to be super-helpfull! Thanks for writing and sharing this!


Hi Florian!

For this, I'd recommend abstracting out the API call into a separate module. This gives you a single place to test the authentication, and leaves the rest of your tests cleaner and easier to maintain.

For the example in the article, this would mean having an apiProxy.js module that we send the request to instead of axios. The proxy module would handle fetching and authentication, and in the test, we'd be mocking apiProxy instead of axios.

If you want to test the authentication in apiProxy.js, this is probably one of the few instances where you would actually want to make a network call to ensure the authentication is happening as expected at the end point. This can get complex based on exactly how the authentication is taking place and how your application is structured. But essentially, you'll want to use network requests to mimic how an actual logon takes place. In the case of JWT, you can make a login network request, then save the token in a variable and send it in the header for the rest of your authentication tests.


I think I get it! Thanks for the detailed explanation! I have a middleware that checks the tokens, so I think I'm closer to the solution than I thought I was. This saved me a lot of try/error! Cheers! And again, thanks!


Is it possible to make jest.mock(<module>) call to create function calls which emits fail instead of returning null?

If you use such a scheme you know that all the function calls into mocked module are covered by user defined mocks. Would it make any sense?


I think I see what you're saying: Returning undefined in a mocked endpoint is ambiguous, and it would be nice to instead return an error that clearly says "This endpoint/mock is not defined". I hadn't thought about before. Great idea!

Doing some research, I can't find a built-in Jest method to automatically make all function calls in a module fail, but you can create a manual mock file that will return an error for all functions using .mockImplementation():

// __mocks__/axios.js
const axios = jest.genMockFromModule('axios');

const throwUnmockedError = () => {
  throw new Error(`This endpoint has been mocked, but hasn't been given a manual response`);

// Make all axios methods return the unmocked error
// List of axios methods taken from README at https://github.com/axios/axios

module.exports = axios;

Then, when you try to call a mocked function without a user-defined mock, the error will look something like this:

Jest unmocked output error screenshot

I created a branch on the demo repository that uses this strategy: mock-with-failed-requests. If you clone the repo, switch to that branch, and run npm run test:mocked, you'll get the error in the screenshot above.

If you play around with it a bit, there might also be a way to more clearly show exactly which mocked function triggered the error. You could also create a function to map through all the methods, which would clean up the manual mock and automatically include any additional methods added in the future.

I hope this helps!


Throwing an exception is one solution butcode under test might catch exceptions but I have not found any nice way to do something simple like fail().

Looks like there has been plans for fail(<message>) in jest-extended(1) but is it still unimplemented.

(1) npmjs.com/package/jest-extended#fa...

Looks like:

const throwUnmockedError = () => {

does the trick but is not really pretty and I'm sure that there are use cases when that approach just will not work.

Oh you're right! There's not a great way to fail a test from an imported module when the tested code is in a try/catch. I found some suggestions in this Github issue thread about using fail() or done.fail(), but I was unable to get this to fail the test from the imported module.

Best alternative I could think of would be to throw a console.warn() message so at least there's an obvious indication in the terminal of the missing mock. Otherwise, I'd imagine you'd have to build some sort of custom global Jest rule that fails when it hits an unmocked end point. This blog also looked like it might have some solutions, but I didn't have time to test them: Jest explicitly or arbitrarily force fail() a test.

I'm very curious about this. Let me know if you find any better solutions!


Thanks for that! That's helpful. I've tried what you said but I'm having a hard time to integrate the ts-jest. Could you take a look at stackoverflow.com/questions/626040...


Just posted an answer on that question. Hope it helps!



Great article, but I think you're missing a critical 4th step - resetting the mocks.

I just came across your post. I sure wish I'd found it earlier. Even though I'm an experienced programmer, I went through the same confusing process you describe when learning how to test Javascript with Jest. However, I knew enough about testing to know I needed to reset mocks after each test. There are subtle differences between the various reset options, but I generally do something like jest.resetAllMocks(); in a beforeEach(). I think you should at least mention the need for resetting, else the second test you write may not behave as expected.


Great call-out! This is actually a best practice I've been ignoring in some of my own tests ("SHAME!"). I'll make an addendum to this article soon to add this detail and credit you for it. Thanks!


Nice one!

I am going to try this out tomorrow. :)

I just want to mention that a false-negative test is a test which is green but it should not be.
A false-positive test is red but it should not be.

The test case where you don't mock Axios is not a false-negative but a false-positive one. :)


i need to test response, Is mocking is requiered. Because I need to check actual response not mocked data. Please explain Iam a beginner it will be helpful.And iam not getting any jest resource reagarding api testing.It will be helpful.Thanks in advance


Hi hareeshmhegde! Mocking is not required If you build the tests without mocks, the code will fetch data from the actual API endpoint just as it would when you are running the actual program.

These tests can be useful, but you want to keep them at a minimum to avoid slowing down your tests of making repeated calls and hammering the API. A common practice is to only hit the API in testing when running end-to-end tests ((such as with Cypress). These tests run slower, but are typically run less often than you'd run tests in Jest.

For example, you may run jest tests every time you save or commit with mocked APIs, then before you merge your branch into master, you can run the end-to-end tests to make sure everything works with the actual API.


Hi Zak,

Thank you very much for your article, it helped me a lot.
I am having trouble replicating this with typescript, it complains when I try to set the mockResolvedValue into axios get.

test("it should return permission true", async() => {
axios.get.mockResolvedValue({ //type error here.

expect(await wrapper.obterPermissaoUsuario("token","COD_APLIC","LIMIT")).toBe(true);



Hi Victor! Glad the article helped!

Typescript isn't great at determining the types of mocked values, but there are some great libraries to help. Personally, I've had great success using the mocked method from ts-jest. See details and usage examples here: ts-jest/test-helpers


Hey Zak, I wanted to tell you that i open this account just to comment on your article.
I was trying to understand how to mock a function's return value and was looking for it for hours.
I must say that your explanation was short and sweet.
Thank you.


Good to hear I'm not the only one who found this so difficult to figure out at first! 😁 Glad I could save you some time in the end!


Hey Zak,

Thanks for sharing this. I have a question - apologies if it was already asked.

I have a react-redux component that makes triggers multiple Axios calls (to a 3rd party API) both within the components method and via redux actions. Is there a way to use jest mock to specifically intercept each call and have different responses for each one?

I've been struggling with this and seeing how active you are in helping others and replying has given me hope! Thanks again.


Hey Sebastian!

Unfortunately, I don't have too much experience with testing async redux functionality, and I think some of the solution would likely depend on exactly how your calls are implemented. You should be able to mock axios in the exact same way, but it may be a little trickier to predict exactly what is going to be called and in what order.

Unfortunately, I'm not the one who will have a helpful answer for you here, but I found a few resources that may help, in case you haven't seen them yet:

Sorry I don't have a better answer, but best of luck to you in finding a solution!


Thank you for the clean explanation


Thanks for the very clear explanation, Zak!
I would like to mention two additional ways to mock:

  • mock the API responses at the HTTP level, to make the test agnostic to the library used to send those requests. E.g. « nock »
  • use dependency injection in your code, do you can inject a mock directly from your test, without having to rely on jest for this.

enjoy this blog. could you share how you would do a mock post request. thanks.


Sure! Mocking the post request is exactly the same as mocking the get request, except you'll want to mock the post method:

    data: [
        userId: 1,
        id: 1,
        title: 'My First Album'
        userId: 1,
        id: 2,
        title: 'Album: The Sequel'

In this case, you'll want the mocked value to be whatever you get back from the real post response. I've found console.log()-ing the response to a real post request a good way to get a response to copy into the code.

If you want the mock to return a dynamic value based on the input, you could instead use axios.post.mockImplementation(...) This will allow you to create a custom function to build a response based on the input given to axios.post(). You can see the full documentation for mockImplementation() here.

I hope this helps!


Thank you for your post, it so help me to understand about testing API call


This was a great article! After a week of searching/sulking found exactly what I needed! Thanks @zaklaughton !


throw err;
i am getting this error. Please help


Hi Sutar. Not sure what the context is here. Is this related to the mocking in this article? What steps did you take that triggered the error?


Gotta do lunch and learn on this!


Great article!

I like to wrap Axios functions under my own functions so I can mock them instead.


Agreed! I usually like to abstract away axios functionality in custom functions. I mocked axios directly in this article though just for the purposes of keeping the mocking example simple.


Thank you! This is the best article about Jest!


Glad you found it helpful!


Made this account just to say THANK YOU! I was up last night trying to test my fetch request using Thunks and this post was exactly what I needed and it works now!


Awesome to hear! Glad I could help!