模拟使用react-redux的选择器和jest来使用react测试库进行测试

问题描述 投票:0回答:2

我正在尝试测试一个使用react-redux进行状态管理的组件。

为了快速测试,我想模拟 useSelector,如下所示:

const templates = [
  {
    id: ...,
    name: ...,
    ...
  },
  {
    id: ...,
    name: ...,
    ...
  },
]


jest.mock('react-redux', () => ({
  ...jest.requireActual('react-redux'),
  useSelector: jest.fn(),
}));


describe('some awesome description', () => {
  beforeEach(() => {
    useSelector.mockImplementation(callback => callback(templates));
  });
});

但是在运行测试时,会失败,如下所示:

TypeError: Cannot read properties of undefined (reading 'ids')

  141 | describe('layouts/TemplatesPanel', () => {
  142 |   beforeEach(() => {
> 143 |     useSelector.mockImplementation(callback => callback(templates));
      |                                                ^
reactjs unit-testing react-redux jestjs react-testing-library
2个回答
7
投票

你最好不要mock

useSelector
,mock 的实现可能会破坏它的功能,因为它的功能不仅仅是返回某个状态片。请参阅
useSelector
真正的实现,它不仅仅返回
selectedState

推荐的方法是创建一个模拟商店并为其提供模拟数据。

例如

index.tsx

import React from 'react';
import { useSelector } from 'react-redux';

export type Template = {
  id: string;
  name: string;
};
export type RootState = {
  templates: Template[];
};

export const MyComp = () => {
  const templates = useSelector<RootState>((state) => state.templates);
  console.log('templates: ', templates);
  return <div>MyComp</div>;
};

index.test.tsx

import { render } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { MyComp, RootState, Template } from '.';

describe('73494842', () => {
  test('should pass', () => {
    const templates: Template[] = [
      { id: '1', name: 'a' },
      { id: '2', name: 'b' },
    ];
    const mockStore = createStore<RootState, any, any, any>((state = { templates }, action) => {
      if (action.type === 'UPATE_NAME') {
        return {
          ...state,
          templates: templates.map((t) => (t.id === action.payload.id ? { ...t, name: action.payload.name } : t)),
        };
      }
      return state;
    });
    render(
      <Provider store={mockStore}>
        <MyComp />
      </Provider>
    );
    mockStore.dispatch({ type: 'UPATE_NAME', payload: { id: '1', name: 'c' } });
  });
});

测试结果:

  73494842
    ✓ should pass (44 ms)

  console.log
    templates:  [ { id: '1', name: 'a' }, { id: '2', name: 'b' } ]

      at MyComp (stackoverflow/73494842/index.tsx:14:11)

  console.log
    templates:  [ { id: '1', name: 'c' }, { id: '2', name: 'b' } ]

      at MyComp (stackoverflow/73494842/index.tsx:14:11)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.931 s, estimated 11 s

当我们稍后调度一个动作时,

useSelector
钩子将订阅商店的更改,它将再次执行并获取更新的状态切片。如果你模拟它只是返回一个状态切片,那么这个功能就不再起作用了。


0
投票

您还需要在

jest.mock
中传递回调函数。

useSelector: (callback) => jest.fn(callback)
© www.soinside.com 2019 - 2024. All rights reserved.