简体   繁体   English

redux-thunk结构和测试副作用

[英]redux-thunk structure and test side effects

I am using redux-thunk and not sure if side effects ( showAlertError function) are structured properly. 我正在使用redux-thunk ,不确定副作用( showAlertError函数)的结构是否正确。 Although my jest test setup seems to be fine at first glance, I get an error: 尽管乍看之下我的笑话测试设置似乎还不错,但我得到一个错误:

jest.fn() value must be a mock function or spy. jest.fn()值必须是模拟函数或间谍。 Received: undefined` 收到:未定义

Is the showAlertError function is at the right place or it should be in the action creator or somewhere else? showAlertError函数是在正确的位置还是应该在操作创建者中或其他位置? Also if this is the right place for it then how I can test if it's called. 另外,如果这是正确的位置,那么我如何测试它是否被调用。

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

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

    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(jsonResponse));
    } 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';

import { showAlertError } from '../../../../_helpers/alerts';
jest.mock('../../../../_helpers/alerts');

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

describe('submitTeammateInvitation', () => {
   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 = [
      submitTeammateInvitationRequestObject,
      submitTeammateInvitationErrorObject
    ];
    const showAlertError = jest.fn();

    return store.dispatch(submitTeammateInvitation(inviteTeammateEndpoint))
      .then(() => {
        expect(showAlertError).toBeCalled(); // this doesn't work
        expect(store.getActions()).toEqual(expectedActions); // this works
      });
  });
});

You can mock showErrorAlert function manually. 您可以手动模拟showErrorAlert函数。 Here is the solution: 解决方法如下:

actionCreators.ts : actionCreators.ts

import fetch from 'node-fetch';
import { showErrorAlert } from './showErrorAlert';

const SUBMIT_TEAMATE_INVITATION_REQUEST = 'SUBMIT_TEAMATE_INVITATION_REQUEST';
const SUBMIT_TEAMATE_INVITATION_SUCCESS = 'SUBMIT_TEAMATE_INVITATION_SUCCESS';
const SUBMIT_TEAMATE_INVITATION_ERROR = 'SUBMIT_TEAMATE_INVITATION_ERROR';

export const submitTeammateInvitationRequest = data => ({ type: SUBMIT_TEAMATE_INVITATION_REQUEST, payload: { data } });
export const submitTeammateInvitationSuccess = data => ({ type: SUBMIT_TEAMATE_INVITATION_SUCCESS, payload: { data } });
export const submitTeammateInvitationError = data => ({ type: SUBMIT_TEAMATE_INVITATION_ERROR, payload: { data } });

export const submitTeammateInvitation = data => {
  const config = {
    // config code
  };

  const inviteTeammateEndpoint = 'https://github.com/mrdulin';

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

    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(jsonResponse));
    } catch (error) {
      if (process.env.NODE_ENV === 'development') {
        console.log('Request failed', error);
      }
    }
  };
};

showErrorAlert.ts : showErrorAlert.ts

export function showErrorAlert(jsonResponse) {
  console.log(jsonResponse);
}

actionCreators.spec.ts : actionCreators.spec.ts

import {
  submitTeammateInvitation,
  submitTeammateInvitationRequest,
  submitTeammateInvitationSuccess,
  submitTeammateInvitationError
} from './actionCreators';
import createMockStore from 'redux-mock-store';
import thunk, { ThunkDispatch } from 'redux-thunk';
import fetch from 'node-fetch';
import { AnyAction } from 'redux';
import { showErrorAlert } from './showErrorAlert';

const { Response } = jest.requireActual('node-fetch');

jest.mock('node-fetch');
jest.mock('./showErrorAlert.ts', () => {
  return {
    showErrorAlert: jest.fn()
  };
});

const middlewares = [thunk];
const mockStore = createMockStore<any, ThunkDispatch<any, any, AnyAction>>(middlewares);

describe('submitTeammateInvitation', () => {
  it('dispatches the correct actions on a failed fetch request', () => {
    const mockedResponse = { data: 'mocked response' };
    const mockedJSONResponse = JSON.stringify(mockedResponse);
    const mockedData = { data: 'mocked data' };
    (fetch as jest.MockedFunction<typeof fetch>).mockResolvedValueOnce(
      new Response(mockedJSONResponse, { status: 500, statusText: 'Internal Server Error' })
    );

    const intialState = {};
    const store = mockStore(intialState);
    const expectedActions = [
      submitTeammateInvitationRequest(mockedData),
      submitTeammateInvitationError(mockedResponse)
    ];
    return store.dispatch(submitTeammateInvitation(mockedData)).then(() => {
      expect(store.getActions()).toEqual(expectedActions);
      expect(showErrorAlert).toBeCalledWith(mockedResponse);
    });
  });
});

Unit test result with coverage report: 带有覆盖率报告的单元测试结果:

 PASS  src/stackoverflow/47560126/actionCreators.spec.ts
  submitTeammateInvitation
    ✓ dispatches the correct actions on a failed fetch request (11ms)

-------------------|----------|----------|----------|----------|-------------------|
File               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files          |    89.29 |       50 |    83.33 |    90.91 |                   |
 actionCreators.ts |    89.29 |       50 |    83.33 |    90.91 |             32,35 |
-------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.864s

Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47560126 这是完整的演示: https : //github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47560126

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM