Home > Software design >  How to test asynchronous action?
How to test asynchronous action?

Time:03-01

I have an action:

export const GetChatList = userStatus => {
  return dispatch => {
    dispatch({
      type: MessagesActionTypes.GET_MESSAGES_LIST.REQUEST,
      payload: {}
    });

    axios
      .get(config.apiUrl   config.methods.getMessagesList, { params: { accountType: userStatus } })
      .then(res => {
        dispatch({
          type: MessagesActionTypes.GET_MESSAGES_LIST.SUCCESS,
          payload: res.data
        });
      })
      .catch(err => {
        dispatch({
          type: MessagesActionTypes.GET_MESSAGES_LIST.ERROR,
          payload: 'error text'
        });
      });
  };
};

And I tried to write a test for this action:

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

describe('Messages actions', () => {
  afterEach(() => {
    fetchMock.restore();
  });

  it('GetChatList', () => {
    fetchMock.get(config.apiUrl   config.methods.getMessagesList, { params: { accountType: 1 } });

    const expectedActions = [
      { type: MessagesActionTypes.GET_MESSAGES_LIST.REQUEST },
      {
        type: MessagesActionTypes.GET_MESSAGES_LIST.SUCCESS,
        payload: ...somePayload
      },
      {
        type: MessagesActionTypes.GET_MESSAGES_LIST.ERROR,
        payload: 'error text'
      }
    ];

    const store = mockStore({...initialState});
    return store.dispatch(GetChatList(1)).then(() => expect(store.getActions()).toEqual(expectedActions));
  });
});

And then I get an error: TypeError: Cannot read property 'then' of undefined Why is this happening and how to properly test this action? What are my mistakes?

CodePudding user response:

  • fetch-mock mocks HTTP requests made using fetch. But you are using axios.

  • You should return the promise created by axios.get() in the thunk. So that you can call store.dispatch(GetChatList(1)).then() method.

  • You can use jest.spyOn(axios, 'get') to mock axios.get() method and its resolved/rejected value.

E.g.

thunk.ts:

import axios from 'axios';

export const MessagesActionTypes = {
  GET_MESSAGES_LIST: {
    REQUEST: 'REQUEST',
    SUCCESS: 'SUCCESS',
    ERROR: 'ERROR',
  },
};
const config = {
  apiUrl: 'http://localhost:8080/v1/api',
  methods: {
    getMessagesList: '/messages',
  },
};
export const GetChatList = (userStatus) => {
  return (dispatch) => {
    dispatch({ type: MessagesActionTypes.GET_MESSAGES_LIST.REQUEST, payload: {} });
    return axios
      .get(config.apiUrl   config.methods.getMessagesList, { params: { accountType: userStatus } })
      .then((res) => dispatch({ type: MessagesActionTypes.GET_MESSAGES_LIST.SUCCESS, payload: res.data }))
      .catch((err) => dispatch({ type: MessagesActionTypes.GET_MESSAGES_LIST.ERROR, payload: 'error text' }));
  };
};

thunk.test.ts:

import { GetChatList, MessagesActionTypes } from './thunk';
import configureStore from 'redux-mock-store';
import thunk, { ThunkDispatch } from 'redux-thunk';
import { AnyAction } from 'redux';
import axios from 'axios';

interface AppState {}
type DispatchExts = ThunkDispatch<AppState, void, AnyAction>;
const mws = [thunk];
const mockStore = configureStore<AppState, DispatchExts>(mws);

describe('71296970', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('should pass', () => {
    jest.spyOn(axios, 'get').mockResolvedValue({ data: 'fake data' });
    const store = mockStore({});
    const expectedActions = [
      { type: MessagesActionTypes.GET_MESSAGES_LIST.REQUEST, payload: {} },
      { type: MessagesActionTypes.GET_MESSAGES_LIST.SUCCESS, payload: 'fake data' },
    ];

    return store.dispatch(GetChatList(1)).then(() => {
      const actions = store.getActions();
      expect(actions).toEqual(expectedActions);
    });
  });
});

Test result:

 PASS  stackoverflow/71296970/thunk.test.ts
  71296970
    ✓ should pass (5 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 thunk.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.383 s
  • Related