Testing Async Redux Action Jest

2019-06-04 02:25发布

问题:

I'm having trouble getting the correct output from an async redux action. I am using Jest, redux-mock-adapter, and thunk as the tools.

According to redux's documentation on testing async thunks (https://redux.js.org/docs/recipes/WritingTests.html#async-action-creators), my tests should be returning an array of two actions. However, my test is only returning the first action, and not the second one that should return on a successful fetch. I think I'm just missing something small here, but it has been bothersome to say the least.

Redux Action

export const getRemoveFileMetrics = cacheKey => dispatch => {
    dispatch({ type: IS_FETCHING_DELETE_METRICS });
    return axios
        .get("GetRemoveFileMetrics", { params: { cacheKey } })
        .then(response => dispatch({ type: GET_REMOVE_FILE_METRICS, payload: response.data }))
        .catch(err => err);
};

Test

it("getRemoveFileMetrics() should dispatch GET_REMOVE_FILE_METRICS on successful fetch", () => {
        const store = mockStore({});
        const cacheKey = "abc123doremi";
        const removeFileMetrics = {
            cacheKey,
            duplicateFileCount: 3,
            uniqueFileCount: 12,
        };
        const expectedActions = [
            {
                type: MOA.IS_FETCHING_DELETE_METRICS,
            },
            {
                type: MOA.GET_REMOVE_FILE_METRICS,
                payload: removeFileMetrics,
            }
        ];
        mockRequest.onGet(`/GetRemoveFileMetrics?cacheKey=${cacheKey}`).reply(200, removeFileMetrics);
        return store.dispatch(MOA.getRemoveFileMetrics(cacheKey)).then(() => {
            const returnedActions = store.getActions();
            expect(returnedActions).toEqual(expectedActions);
        });
    });

The Output

Expected value to equal:
    [{ "type": "IS_FETCHING_DELETE_METRICS" }, { "payload": { "cacheKey": "abc123doremi", "duplicateFileCount": 3, "uniqueFileCount": 12 }, "type": "GET_REMOVE_FILE_METRICS" }]
Received:
    [{ "type": "IS_FETCHING_DELETE_METRICS" }]

回答1:

I am using jest-fetch-mock and no axios. The following is working for me with the actions. You could refactor to async await as first step. For me it only worked that way.

I am now trying to figure out how to test the side effect (showErrorAlert(jsonResponse);). If I mock out the showErrorAlert implementation at the top of the test file (commented out in my example) then I get the same problem just like you. Actions that uses fetch won't get triggered for some reason.

export const submitTeammateInvitation = (data) => {
  const config = {
    //.....
  };

  return async (dispatch) => {
    dispatch(submitTeammateInvitationRequest());

    try {
      const response = await fetch(inviteTeammateEndpoint, config);
      const jsonResponse = await response.json();

      if (!response.ok) {
        showErrorAlert(jsonResponse);
        dispatch(submitTeammateInvitationError(jsonResponse));

        throw new Error(response.statusText);
      }

      dispatch(submitTeammateInvitationSuccess());
    } catch (error) {
      if (process.env.NODE_ENV === 'development') {
        console.log('Request failed', error);
      }
    }
  };
};

test

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

// jest.mock('../../../../_helpers/alerts', ()=> ({ showAlertError: jest.fn() }));

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

......

it('dispatches the correct actions on a failed fetch request', () => {
  fetch.mockResponse(
    JSON.stringify(error),
    { status: 500, statusText: 'Internal Server Error' }
  );

  const store = createMockStore({});
  const expectedActions = [
    {
      type: 'SUBMIT_TEAMMATE_INVITATION_REQUEST',
    },
    {
      type: 'SUBMIT_TEAMMATE_INVITATION_FAILURE',
      payload: { error }
    }
  ];

  return store.dispatch(submitTeammateInvitation(data))
    .then(() => {
      // expect(alerts.showAlertError).toBeCalled();
      expect(store.getActions()).toEqual(expectedActions);
    });
});