我正在使用useDispatch自定义钩子,并在测试中遇到此错误:操作必须是普通对象。使用自定义中间件进行异步操作

时间:2019-07-18 17:36:19

标签: reactjs redux react-redux jestjs react-testing-library

我正在尝试测试是否使用正确的参数调用了函数,但是由于我使用的是来自react-redux的useDispatch,因此出现以下错误:操作必须是普通对象。使用自定义中间件执行异步操作。

我已经按照文档中的说明将测试组件包装在renderWithRedux中。

测试设置:

const renderWithRedux = (
    ui,
    { initialState, store = createStore(reducer, initialState) } = {}
  ) => {
    return {
      ...render(<Provider store={store}>{ui}</Provider>),
      store,
    };
  };
  const templateId = faker.random.number();
  const setup = () => {
    const props = {
      history: {
        push: jest.fn(),
      },
    };
    viewTemplateUrl.mockImplementationOnce(() => jest.fn(() => () => {}));
    templatePostThunk.mockImplementationOnce(
      jest.fn(() => () => Promise.resolve(templateId))
    );
    const {
      container,
      getByText,
      getByLabelText,
      rerender,
      debug,
    } = renderWithRedux(<NewTemplateForm {...props} />);
    return {
      debug,
      templateId,
      props,
      container,
      rerender,
      getByText,
      getByLabelText,
      templateNameTextField: getByLabelText('Template Name'),
      templateNameInput: getByLabelText('Template Name Input'),
      saveTemplateButton: getByText('Save Template'),
      cancelButton: getByText('Cancel'),
    };
  };


Failing test:
  test('save template calls handleSubmit, push, and viewTemplateUrl', async () => {
    const { templateNameInput, saveTemplateButton, props } = setup();
    fireEvent.change(templateNameInput, { target: { value: 'Good Day' } });
    fireEvent.click(saveTemplateButton);
    await expect(templatePostThunk).toHaveBeenCalledWith({
      name: 'Good Day',
    });
    expect(props.history.push).toHaveBeenCalled();
    expect(viewTemplateUrl).toHaveBeenCalledWith({ templateId });
  });

应该过去了。

2 个答案:

答案 0 :(得分:0)

您正试图派遣一个笨拙的动作创建者:

await expect(templatePostThunk).toHaveBeenCalledWith({
      name: 'Good Day',
    });

但是您要设置的商店没有笨拙的中间件:

store = createStore(reducer, initialState)

您需要将thunk中间件添加到createStore()调用中,以使其正常工作。

答案 1 :(得分:0)

答案是模拟useDispatch并将父组件包装在renderWithRedux中。

import { render, fireEvent } from '@testing-library/react';
import '@testing-library/react/cleanup-after-each';

import { useDispatch } from 'react-redux';
import faker from 'faker';
import { NewTemplateForm } from './NewTemplateForm';

import { templatePostThunk } from '../../../redux/actions/templatePost';
import { viewTemplateUrl } from '../../../utils/urls';

jest.mock('../../../redux/actions/templatePost');
jest.mock('../../../utils/urls');
jest.mock('react-redux');

describe('<NewTemplateForm/> controller component', () => {
  useDispatch.mockImplementation(() => cb => cb());
  const setup = () => {
    const props = {
      history: {
        push: jest.fn(),
      },
    };
    const templateId = faker.random.number();
    viewTemplateUrl.mockImplementationOnce(() => () => {});
    templatePostThunk.mockImplementationOnce(() => async () => ({
      data: { id: templateId },
    }));
    const { container, getByText, getByLabelText, rerender, debug } = render(
      <NewTemplateForm {...props} />
    );