Search code examples
reactjsunit-testingreduxmockingfetch-mock

How to test asynchronous action?


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?


Solution

    • 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