Testing Axios API Calls with Jest Mocks

Testing API calls is a fundamental part of building robust applications, ensuring your code handles network responses and errors predictably. This article demonstrates how to unit test Axios HTTP requests using Jest by creating mock implementations of the Axios client. You will learn how to mock network responses, verify request parameters, and test both successful responses and error states without sending actual HTTP requests to an external server.


1. The Module Under Test

Consider a simple service file, userService.js, that uses Axios to fetch and post user data:

// userService.js
import axios from 'axios';

export const getUser = async (id) => {
  try {
    const response = await axios.get(`https://api.example.com/users/${id}`);
    return response.data;
  } catch (error) {
    throw new Error('Failed to fetch user');
  }
};

export const createUser = async (userData) => {
  const response = await axios.post('https://api.example.com/users', userData);
  return response.data;
};

2. Mocking Axios with jest.mock()

To prevent actual network requests during testing, use jest.mock('axios'). This replaces the Axios module with an auto-mocked version where all methods (get, post, put, delete, etc.) are Jest mock functions.

// userService.test.js
import axios from 'axios';
import { getUser, createUser } from './userService';

// Mock the entire axios module
jest.mock('axios');

describe('userService', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  // Tests go here...
});

Using jest.clearAllMocks() in the afterEach hook ensures that call counts and mock implementations do not leak across different tests.


3. Testing Successful GET Requests

To test a successful API call, mock the resolved value of the Axios method using mockResolvedValue or mockResolvedValueOnce:

test('getUser fetches successfully data from an API', async () => {
  const mockUser = { id: 1, name: 'Jane Doe' };

  // Set up the mock response structure
  axios.get.mockResolvedValueOnce({ data: mockUser });

  const result = await getUser(1);

  // Assertions
  expect(axios.get).toHaveBeenCalledTimes(1);
  expect(axios.get).toHaveBeenCalledWith('https://api.example.com/users/1');
  expect(result).toEqual(mockUser);
});

4. Testing Error Scenarios and Rejections

To verify that your application handles network failures or API errors gracefully, use mockRejectedValue or mockRejectedValueOnce:

test('getUser throws an error when the API call fails', async () => {
  // Simulate a network failure or 500 status code
  axios.get.mockRejectedValueOnce(new Error('Network Error'));

  await expect(getUser(1)).rejects.toThrow('Failed to fetch user');
  expect(axios.get).toHaveBeenCalledWith('https://api.example.com/users/1');
});

5. Testing POST Requests and Payloads

When testing requests that send data (such as POST or PUT), verify that the payload passed to the Axios method matches the expected schema:

test('createUser sends the correct payload and returns new user', async () => {
  const newUser = { name: 'John Doe', email: 'john@example.com' };
  const mockResponse = { id: 2, ...newUser };

  axios.post.mockResolvedValueOnce({ data: mockResponse });

  const result = await createUser(newUser);

  expect(axios.post).toHaveBeenCalledTimes(1);
  expect(axios.post).toHaveBeenCalledWith('https://api.example.com/users', newUser);
  expect(result).toEqual(mockResponse);
});

6. Mocking Axios Instances (axios.create)

If your application uses custom Axios instances created via axios.create(), you must mock the create method to return an object containing mocked methods:

// If using custom instances:
jest.mock('axios', () => {
  const mAxios = {
    get: jest.fn(),
    post: jest.fn(),
  };
  return {
    create: jest.fn(() => mAxios),
    ...mAxios,
  };
});

This pattern guarantees that whether your application code calls axios.get() directly or calls methods on an instance generated by axios.create(), the mock functions intercept the execution.