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?
16 Answers
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 === ') { 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:
- Jest mocking documentation
- A GitHub discussion that explains about the scope of the
jest.mock("axios")line. - A related question which addresses applying the techniques above to Axios request interceptors.
- Using jest functions like
mockImplementationin TypeScript: Typescript and Jest: Avoiding type errors on mocked functions
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(').reply(200, data); chatbot.sendMessage(0, 'any').then(response => { expect(response).toEqual(data); done(); }); }); }); You can see it the whole example here:
2I could do that following the steps:
- Create a folder __mocks__/ (as pointed by @Januartha comment)
- Implement an
axios.jsmock file - 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; }) }; 4I'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(') .get('/example') .reply(200, 'some payload') // test... }) }) 2Look at this
- The function to test
album.js
const fetchAlbum = function () { return axios .get("") .then((response) => { return response.data; }); }; - 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); }); 0For those looking to use axios-mock-adapter in place of the mockfetch example in the Redux documentation for async testing, I successfully used the following:
File actions.test.js:
describe('SignInUser', () => { var history = { push: function(str) { expect(str).toEqual('/feed'); } } it('Dispatches authorization', () => { let mock = new MockAdapter(axios); mock.onPost(`${ROOT_URL}/auth/signin`, { email: '', password: 'test' }).reply(200, {token: 'testToken' }); const expectedActions = [ { type: types.AUTH_USER } ]; const store = mockStore({ auth: [] }); return store.dispatch(actions.signInUser({ email: '', password: 'test', }, history)).then(() => { expect(store.getActions()).toEqual(expectedActions); }); }); In order to test a successful case for signInUser in file actions/index.js:
export const signInUser = ({ email, password }, history) => async dispatch => { const res = await axios.post(`${ROOT_URL}/auth/signin`, { email, password }) .catch(({ response: { data } }) => { ... }); if (res) { dispatch({ type: AUTH_USER }); // Test verified this localStorage.setItem('token', res.data.token); // Test mocked this history.push('/feed'); // Test mocked this } } Given that this is being done with jest, the localstorage call had to be mocked. This was in file src/setupTests.js:
const localStorageMock = { removeItem: jest.fn(), getItem: jest.fn(), setItem: jest.fn(), clear: jest.fn() }; global.localStorage = localStorageMock; 2