React 测试库如何断言子属性和 Redux 存储更新?

How React Testing Library can assert children props and Redux store updates?

我刚刚开始探索我的 React 应用程序的单元测试框架。我将我的选择锁定在 @testing-library/react 而不是 Enzyme,因为它是 React 推荐的,有助于编写更健壮的测试。我还打算使用 Jest 来确保完整性。

但在我继续 React Testing Library 之前,我遇到了几个问题。有人可以帮忙吗?

例如,

  1. 有一个 Editor 组件可以根据用户输入更新 Redux 存储。
  2. 还有另一个组件 Preview 直接从存储中读取值。
  3. 还有第三个组件Container,它包含上述两个传递一些道具的组件。

问题:

  1. 如何测试 Editor 组件中的用户输入是否实际更新商店?
  2. 如何测试 Preview 组件是否可以呈现从存储中读取的值?
  3. 如何测试 Container 组件是否正确地将 props 传递给它的子组件?


Container.jsx

import React from 'react';
import Editor from './Editor';
import Preview from './Preview';

const Container = ({editorType}) => {
  return (
    <div>
      <Editor type={editorType} />
      <Preview />
    </div>
  );
};
export default Container;

Editor.jsx

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {setName} from './actions';

const Editor = ({type}) => {
  const name = useSelector(state => state.name);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Type: {type}</h1>
      <input value={name} onChange={evt => dispatch(setName(evt.target.value))} />
    </div>
  );
};
export default Editor;

Preview.jsx

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

const Editor = ({type}) => {
  const name = useSelector(state => state.name);

  return (
    <div>
      <h1>Name: {name}</h1>
    </div>
  );
};
export default Preview;

这是我的做法:

如何测试编辑器组件中的用户输入是否实际更新存储?

查看您的代码,Editor 不会更新存储,它不会调用 useDispatch。但假设它确实如此,使用 https://github.com/reduxjs/redux-mock-store 我会为测试中的组件设置一个模拟商店提供者,然后触发用户输入并检查模拟商店是否已调度正确的操作,并使用正确的有效负载:

describe('<Editor />', () => {
  let store: MockStoreEnhanced;
  let rtl: RenderResult;

  beforeEach(() => {
    store = mockStore({ /* your store structure */ });

    rtl = render(
      <Provider store={store}>
        <Editor type={...} />
      </Provider>
    );
  });

  test('dispatch action correctly', () => {
    fireEvent.change(rtl.container.querySelector('input'), { target: {value: 'test' } });

    // check actions that were dispatched by change event
    // getActions return an array avec redux actions (type, payload)
    expect(store.getActions()).toEqual(...);
  }
}

除此之外你应该测试你的 store reducer 和 action creators,以确保 action 正确地修改了 store。

如何测试预览组件是否可以呈现从存储中读取的值?

相同的原则,使用模拟商店设置测试,使用相关值初始化该商店,然后测试组件是否显示商店中的内容:

describe('<Preview />', () => {
  let store: MockStoreEnhanced;
  let rtl: RenderResult;

   beforeEach(() => {
     store = mockStore({ name: 'This is name from store' });

     rtl = render(
       <Provider store={store}>
         <Preview type={...} />
       </Provider>
     );
   });

   test('displays store content correctly', () => {
     expect(rtl.getByText('This is name from store')).toBeTruthy();
   }
 }

如何测试 Container 组件是否正确地将 props 传递给它 children?

在这里你应该一起测试Container + Preview + Editor,并找到一些可视化的东西来测试(作为一个真实的用户会感知它),包括Container传递给它的道具children。

例如,如果预览显示 props.type,它来自 Container editorType props :

describe('<Container />', () => {
  // mocked store may not be necessary here, depending on your use case
  let store: MockStoreEnhanced;
  let rtl: RenderResult;

   beforeEach(() => {
     store = mockStore({ name: 'This is name from store' });

     rtl = render(
       <Provider store={store}>
         <Container editorType={'toTest'} />
       </Provider>
     );
   });

   test('displays store content correctly', () => {
     // check that 'toTest' exists in DOM because it is rendered by Preview component, a child of Container
     expect(rtl.getByText('toTest')).toBeTruthy();
   }
 }

总而言之,我的方法是:

  • 单独测试动作和缩减器(测试非常简单,状态机,只是简单的 Jest 测试)
  • 测试组件是否在正确的用户输入上使用正确的负载发送正确的操作
  • 模拟商店为从商店读取数据的组件设置相关用例(初始商店值)

最后 2 项我使用 https://github.com/reduxjs/redux-mock-store