How to mock the axios library in jest without mock adapter or library

React Jest provides the methods to mock the library like manual mocks, es6 class mocks. Axios library is used to fetch the data in the React component.

We should not make the http calls inside the unit test files. It helps to test both the success and error conditions of the api calls and subsequent component functionality. That is why it is better to mock the axios library.

In this tutorial, we are going to mock the axios component by using the Jest framework itself. We are not going to use any external library to mock the axios library.

Mocking axios library

We can mock the axios library using the jest.mock() function and providing a mock factory method.

Axios is an es6 class, so mocking axios will be similar to mocking an es6 class in jest. We also have to implement the default method in our mock factory function.

Below is the sample code to mock the axios library.

jest.mock('axios', () => {
  return {
    __esModule: true,
    default: jest.fn()
  }
});

We can mock other methods of axios library like axios.get, axios.post by implementing them inside the mock factory function.

jest.mock('axios', () => {
  return {
    __esModule: true,
    default: jest.fn(),
    get: jest.fn()
    ...
  }
});

Using the mock axios inside the test case

Once we have mocked the axios library in our test case, we can use the mocked library to return the resolved response or the rejected error response for the api call.

We are going to require the axios library in our test case, and provide a mock implementation.

const axios = require('axios');
jest.spyOn(axios, 'default').mockResolvedValue({
  name: 'abc'
})

In the above code snippet, we are returning the resolved value (ie the Promise is resolved with the data {name : abc}

We can also reject the data in similar fashion.

jest.spyOn(axios, 'default').mockRejectedValue()

Complete example of the mock of axios

Now, we are going to write a component which contains the axios code. Then we will write the unit test case for it by mocking the axios library using jest.

The sample component which we are going to write will be a simple React component, which will make a call to local server, and set the state from the response. If the api throws error, then the error state is set to true. Based upon the state value, then output is rendered. We are going to test both the success and error condition of axios.

Sample component is as follows

import { Component } from 'react';
import axios from 'axios';
import './App.css';
class App extends Component{
  state = {
    name: '',
    error: false
  }
  componentDidMount(){
    axios({
      url: 'http://localhost:3000',
    }).then((data)=>{
      const { name } = data;
      this.setState({
        name
      })
    }).catch(()=>{
      this.setState({
        error: true
      })
    })
  }
  render(){
    if(this.state.error){
      return "error";
    }
    return this.state.name;
  }
}
export default App;

In the above component, we import the dependencies of axios, react.

import { Component } from 'react';
import axios from 'axios';
import './App.css';

Then we declare the App component

class App extends Component{

We declare the state variable of name and error. Name will be displayed on success, error will be set when there is error in the axios call.

state = {
    name: '',
    error: false
  }

Then in the component lifecycle method, we call the api http://localhost:3000 to get the data. In the then block, we set the state of name. In the catch block, we set the error state boolean error.

 componentDidMount(){
    axios({
      url: 'http://localhost:3000',
    }).then((data)=>{
      const { name } = data;
      this.setState({
        name
      })
    }).catch(()=>{
      this.setState({
        error: true
      })
    })
  }

In the render function, we return the error message if error state is set, or else we return the name state.

render(){
    if(this.state.error){
      return "error";
    }
    return this.state.name;
  }

Writing unit test case for above sample component

The test case for the above component which mocks the axios and tests the success and error condition are as follows.

import React from 'react';
import axios from 'axios';
import { waitFor } from '@testing-library/dom';
import { render } from '@testing-library/react';
import App from './App';
jest.mock('axios');
beforeEach(()=>{
  jest.clearAllMocks()
})
test('show name', async () => {
  jest.spyOn(axios, 'default').mockResolvedValue({
    name: 'abc'
  })
  const wrapper = render(<App />);
  await waitFor(() => expect(wrapper.queryAllByText('abc')).toHaveLength(1));
});
test('show name error', async () => {
  jest.spyOn(axios, 'default').mockRejectedValue(()=>({}));
  const wrapper = render(<App />);
  await waitFor(() => expect(wrapper.container.innerHTML).toEqual('error'));
});

I am going to explain the above code one by one.

If you have written the unit test case before, then you will be familier with some of the code above.

beforeEach runs the callback function before every test. test contains the test.

Here we are going to focus on the mocking aspect.

We have imported the axios library from 'axios' dependency. Then we have mocked the library using jest.mock. This will replace the methods of axios with mock methods.

import axios from 'axios';
...
jest.mock('axios');

After mocking the axios library, we can spy on it and provide our own implementation for the methods.

For the first test case about the, we have resolved the value (so it will return success condition).

jest.spyOn(axios, 'default').mockResolvedValue({
  name: 'abc'
})

Then we check if the name is properly displayed or not using the following code

const wrapper = render(<App />);
await waitFor(() => expect(wrapper.queryAllByText('abc')).toHaveLength(1));

For the error condition, we are going to spy on axios and reject the value. This will mock the error in response.

jest.spyOn(axios, 'default').mockRejectedValue(()=>({}));

Then we are going to test if the error is displayed in the output using the following code

const wrapper = render(<App />);
await waitFor(() => expect(wrapper.container.innerHTML).toEqual('error'));