Search code examples
javascriptreactjsreduxjestjsredux-thunk

Testing a redux action


I am trying to implement jest with our redux actions. Given the below action foo and it's following test, the following test is failing because store.getActions() is only returning me [{"type": "ACTION_ONE"}] as supposed to [{"type": "ACTION_ONE"}, {"type": "ACTION_TWO"}]. How do I get both dispatched actions when testing? Thanks!

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';

export const foo = () => {
  return (dispatch) => {
    dispatch(actionOne());
    return HttpService.get(`api/sampleUrl`)
      .then(json => dispatch(actionTwo(json.data)))
      .catch(error => handleError(error));
  };
};

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

beforeEach(() => {
  store = mockStore({});
});

describe('sample test', () => {
  test('validates foo complex action', () => {
    const expectedActions = [
      {type: actionTypes.ACTION_ONE},
      {type: actionTypes.ACTION_TWO},
    ];

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

Solution

  • You haven't mocked the API call and since it won't success without a mock, the action dispatched when the promise resolves is not fired. You can use fetchMock to mock the API call. Once you do that correctly, your test will work

    import configureMockStore from 'redux-mock-store';
    import thunk from 'redux-thunk';
    import fetchMock from 'fetch-mock';
    import fetch from 'node-fetch';
    
    export const foo = () => {
      return (dispatch) => {
        dispatch(actionOne());
        return fetch(`api/sampleUrl`)
          .then(r => r.json())
          .then(json => dispatch(actionTwo(json)))
          .catch(error => handleError(error));
      };
    };
    
    const middlewares = [thunk];
    const mockStore = configureMockStore(middlewares);
    
    beforeEach(() => {
      store = mockStore({});
      fetchMock.restore()
    });
    
    describe('sample test', () => {
      test('validates foo complex action', () => {
    
        fetchMock.getOnce('api/sampleUrl', {
          body: { sample: ['do something'] }
        })
    
        const expectedActions = [
          {type: actionTypes.ACTION_ONE},
          {type: actionTypes.ACTION_TWO},
        ];
    
        return store.dispatch(actions.foo())
          .then(() => {
            expect(store.getActions())
              .toEqual(expectedActions);
          });
      });
    });