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.
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.
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.
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.
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) })
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With