Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock inner axios.create()

I'm using jest and axios-mock-adapter to test axios API calls in redux async action creators.

I can't make them work when I'm using a axios instance that was created with axios.create() as such:

import axios from 'axios';  const { REACT_APP_BASE_URL } = process.env;  export const ajax = axios.create({   baseURL: REACT_APP_BASE_URL, }); 

which I would consume it in my async action creator like:

import { ajax } from '../../api/Ajax'  export function reportGet(data) {   return async (dispatch, getState) => {     dispatch({ type: REQUEST_TRANSACTION_DATA })      try {       const result = await ajax.post(          END_POINT_MERCHANT_TRANSACTIONS_GET,          data,       )       dispatch({ type: RECEIVE_TRANSACTION_DATA, data: result.data })       return result.data     } catch (e) {       throw new Error(e);     }   } } 

Here is my test file:

import {   reportGet,   REQUEST_TRANSACTION_DATA,   RECEIVE_TRANSACTION_DATA, } from '../redux/TransactionRedux' import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk' import { END_POINT_MERCHANT_TRANSACTIONS_GET } from 'src/utils/apiHandler' import axios from 'axios' import MockAdapter from 'axios-mock-adapter'  const middlewares = [thunk] const mockStore = configureMockStore(middlewares) const store = mockStore({ transactions: {} })  test('get report data', async () => {   let mock = new MockAdapter(axios)    const mockData = {     totalSalesAmount: 0   }    mock.onPost(END_POINT_MERCHANT_TRANSACTIONS_GET).reply(200, mockData)    const expectedActions = [     { type: REQUEST_TRANSACTION_DATA },     { type: RECEIVE_TRANSACTION_DATA, data: mockData },   ]    await store.dispatch(reportGet())   expect(store.getActions()).toEqual(expectedActions) }) 

And I only get one action Received: [{"type": "REQUEST_TRANSACTION_DATA"}] because there was an error with the ajax.post.

I have tried many ways to mock the axios.create to no avail without really knowing what I'm doing..Any Help is appreciated.

like image 452
kyw Avatar asked Jul 18 '18 05:07

kyw


People also ask

How do I create an Axios instance?

First, we require Axios as we have already installed it in the previous step. Then, we use axios. create to create a new instance of Axios with a custom config that has a base URL of https://api.GitHub.com/ and a timeout of 1s. The config also has an Accept header with value application/vnd.

How do I use Axios mock adapter?

Setting up Axios Mock AdapterYou can install it using the command npm install --save-dev axios-mock-adapter . Then, you need to create an Axios instance and pass it to the Axio adapter. import axios, { AxiosRequestConfig } from 'axios'; import AxiosMockAdapter from 'axios-mock-adapter';const axiosMockInstance = axios.

Why we use Axios mock adapter?

AXIOS Mock adapter allows you to call API in the test file and you can define the expected response according to your need or the same response which you are getting while calling actual API.


2 Answers

OK I got it. Here is how I fixed it! I ended up doing without any mocking libraries for axios!

Create a mock for axios in src/__mocks__:

// src/__mocks__/axios.ts  const mockAxios = jest.genMockFromModule('axios')  // this is the key to fix the axios.create() undefined error! mockAxios.create = jest.fn(() => mockAxios)  export default mockAxios 

Then in your test file, the gist would look like:

import mockAxios from 'axios' import configureMockStore from 'redux-mock-store' import thunk from 'redux-thunk'  // for some reason i need this to fix reducer keys undefined errors.. jest.mock('../../store/rootStore.ts')  // you need the 'async'! test('Retrieve transaction data based on a date range', async () => {   const middlewares = [thunk]   const mockStore = configureMockStore(middlewares)   const store = mockStore()    const mockData = {     'data': 123   }    /**     *  SETUP    *  This is where you override the 'post' method of your mocked axios and return    *  mocked data in an appropriate data structure-- {data: YOUR_DATA} -- which    *  mirrors the actual API call, in this case, the 'reportGet'    */   mockAxios.post.mockImplementationOnce(() =>     Promise.resolve({ data: mockData }),   )    const expectedActions = [     { type: REQUEST_TRANSACTION_DATA },     { type: RECEIVE_TRANSACTION_DATA, data: mockData },   ]    // work   await store.dispatch(reportGet())    // assertions / expects   expect(store.getActions()).toEqual(expectedActions)   expect(mockAxios.post).toHaveBeenCalledTimes(1) }) 
like image 71
kyw Avatar answered Sep 24 '22 12:09

kyw


If you need to create Jest test which mocks the axios with create in a specific test (and don't need the mock axios for all test cases, as mentioned in other answers) you could also use:

const axios = require("axios");  jest.mock("axios");  beforeAll(() => {     axios.create.mockReturnThis(); });  test('should fetch users', () => {     const users = [{name: 'Bob'}];     const resp = {data: users};     axios.get.mockResolvedValue(resp);      // or you could use the following depending on your use case:     // axios.get.mockImplementation(() => Promise.resolve(resp))      return Users.all().then(data => expect(data).toEqual(users)); }); 

Here is the link to the same example of Axios mocking in Jest without create. The difference is to add axios.create.mockReturnThis()

like image 24
Saša Avatar answered Sep 22 '22 12:09

Saša