How do I test axios in Jest?

173,554

Solution 1

I used axios-mock-adapter. In this case the service is described in ./chatbot. In the mock adapter you specify what to return when the API endpoint is consumed.

import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import chatbot from './chatbot';

describe('Chatbot', () => {
    it('returns data when sendMessage is called', done => {
        var mock = new MockAdapter(axios);
        const data = { response: true };
        mock.onGet('https://us-central1-hutoma-backend.cloudfunctions.net/chat').reply(200, data);

        chatbot.sendMessage(0, 'any').then(response => {
            expect(response).toEqual(data);
            done();
        });
    });
});

You can see it the whole example here:

Service: https://github.com/lnolazco/hutoma-test/blob/master/src/services/chatbot.js

Test: https://github.com/lnolazco/hutoma-test/blob/master/src/services/chatbot.test.js

Solution 2

Without using any other libraries:

import * as axios from "axios";

// Mock out all top level functions, such as get, put, delete and post:
jest.mock("axios");

// ...

test("good response", () => {
  axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
  // ...
});

test("bad response", () => {
  axios.get.mockImplementation(() => Promise.reject({ ... }));
  // ...
});

It is possible to specify the response code:

axios.get.mockImplementation(() => Promise.resolve({ status: 200, data: {...} }));

It is possible to change the mock based on the parameters:

axios.get.mockImplementation((url) => {
    if (url === 'www.example.com') {
        return Promise.resolve({ data: {...} });
    } else {
        //...
    }
});

Jest v23 introduced some syntactic sugar for mocking Promises:

axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));

It can be simplified to

axios.get.mockResolvedValue({ data: {...} });

There is also an equivalent for rejected promises: mockRejectedValue.

Further Reading:

Solution 3

I could do that following the steps:

  1. Create a folder __mocks__/ (as pointed by @Januartha comment)
  2. Implement an axios.js mock file
  3. Use my implemented module on test

The mock will happen automatically

Example of the mock module:

module.exports = {
    get: jest.fn((url) => {
        if (url === '/something') {
            return Promise.resolve({
                data: 'data'
            });
        }
    }),
    post: jest.fn((url) => {
        if (url === '/something') {
            return Promise.resolve({
                data: 'data'
            });
        }
        if (url === '/something2') {
            return Promise.resolve({
                data: 'data2'
            });
        }
    }),
    create: jest.fn(function () {
        return this;
    })
};

Solution 4

I've done this with nock, like so:

import nock from 'nock'
import axios from 'axios'
import httpAdapter from 'axios/lib/adapters/http'

axios.defaults.adapter = httpAdapter

describe('foo', () => {
    it('bar', () => {
        nock('https://example.com:443')
            .get('/example')
            .reply(200, 'some payload')

        // test...
    })
})

Solution 5

Look at this

  1. The function to test album.js
const fetchAlbum = function () {
 return axios
   .get("https://jsonplaceholder.typicode.com/albums/2")
   .then((response) => {
     return response.data;
   });
};
  1. The test album.test.js
const axios = require("axios");
const { fetchAlbum } = require("../utils.js");

jest.mock("axios");

test("mock axios get function", async () => {
    expect.assertions(1);
    const album = {
      userId: 1,
      id: 2,
      title: "sunt qui excepturi placeat culpa",
    };
    const payload = { data: album };
    // Now mock axios get method
    axios.get = jest.fn().mockResolvedValue(payload);
    await expect(fetchAlbum()).resolves.toEqual(album);
  });
Share:
173,554
Adear
Author by

Adear

Hey, Im a React js and Java developer currently working on clearhub.tech. I'm currently resifting my focus on the back end to node js due to my stronger knowledge of javascript

Updated on January 17, 2022

Comments

  • Adear
    Adear over 2 years

    I have this action in React:

    export function fetchPosts() {
        const request = axios.get(`${WORDPRESS_URL}`);
        return {
            type: FETCH_POSTS,
            payload: request
        }
    }
    

    How do I test Axios in this case?

    Jest has this use case on their site for asynchronous code where they use a mock function, but can I do this with Axios?

    Reference: An Async Example

    I have done this so far to test that it is returning the correct type:

    it('should dispatch actions with the correct type', () => {
        store.dispatch(fetchPosts());
        let action = store.getActions();
        expect(action[0].type).toBe(FETCH_POSTS);
    });
    

    How can I pass in mock data and test that it returns?

  • Adear
    Adear almost 7 years
    I did try this but i seems that axios does not play well with nock.github.com/node-nock/nock/issues/699 but thank you for your help none the less
  • Kermit_ice_tea
    Kermit_ice_tea over 6 years
    How did you use the localStorageMock
  • vapurrmaid
    vapurrmaid over 6 years
    @Kermit_ice_tea src/setupTests.js is documented in create-react-app as a global setup for jest/enzyme testing. In that file I created an object that I arbitrarily called localStorageMock with dummy functions (getItem, setItem). The magic is at the bottom where I set global.localStorage equal to this object. I could've done this in one line instead of naming the object localStorageMock. The purpose of this entire setup was to simply avoid any code dealing with localstorage from breaking during tests.
  • Amadeu Cavalcante Filho
    Amadeu Cavalcante Filho almost 6 years
    Hi @shorif2000 I implemented it here github.com/vspedr/movile-messaging/pull/8/files
  • Januartha
    Januartha almost 6 years
    writing manual mocks inside mocks is not a good practice as the manual mocks documentation says to writing manual mocks inside __mocks__
  • Amadeu Cavalcante Filho
    Amadeu Cavalcante Filho almost 6 years
    @Januartha sorry, for my mistype. I'm gonna to correct it here. I typed on the response "____mock___" and it put my word as bold. Sorry
  • Januartha
    Januartha almost 6 years
    @AmadeuCavalcanteFilho ah sure, no problem :)
  • Máxima Alekz
    Máxima Alekz about 3 years
    What if I dont want to mock axios instead, and want it to make a real request?
  • pravindot17
    pravindot17 almost 3 years
    nock is the best way to handle http calls in tests
  • Slobodan Krasavčević
    Slobodan Krasavčević over 2 years
    Really nice answer, thank you!
  • Brent
    Brent almost 2 years
    @MáximaAlekz, I believe for unit tests, you shouldn't make actual API calls. You should always mock.
  • Janac Meena
    Janac Meena almost 2 years
    In typescript, there is no mockImplementation property. Any suggestions?
  • A Jar of Clay
    A Jar of Clay almost 2 years
    @JanacMeena good question; I've added a link (final bullet point) to address this
  • Fiddle Freak
    Fiddle Freak almost 2 years
    @MáximaAlekz Real axios calls performing real CRUD on a backend should be used for end-to-end tests, not a unit tests.
  • Fiddle Freak
    Fiddle Freak almost 2 years
    In the link you provided, I'm getting the same error as Safa Alai TypeError: mockedAxios.get.mockImplementation is not a function
  • Máxima Alekz
    Máxima Alekz almost 2 years
    I don't want to sound rude, but fetchAlbum is NOT being exported, so test will fail