当前位置: 首页 > 知识库问答 >
问题:

如何使用useReducer钩子测试组件?

宋典
2023-03-14
// src/reducers/FooReducer.js

export function FooReducer(state, action) {
  switch (action.type) {
    case 'update': {
      return action.newState;
    }
// ... other actions
    default:
      throw new Error('Unknown action type');
  }
}

// src/components/BarComponent.js

export function BarComponent() {
  const [state, dispatch] = useReducer(FooReducer, []);

  return (
    {state.map((item) => (<div />))}
  );
}
// src/components/BarComponent.test.js

it('should render as many divs as there are items', () => {
  act(() => {
    const { result } = renderHook(() => useReducer(FooReducer, [1]));
    const [, dispatch] = result.current;
    wrapper = mount(<BarComponent />);
    dispatch({type: 'update', newState: [1, 2, 3]});
  });

  expect(wrapper.find(div)).toHaveLength(3);
});

上面的测试示例不起作用,但用于演示我试图实现的目标。并实际呈现0 div,因为组件中声明的初始状态包含0项。

>

  • 为了测试的目的,我应该如何修改一个reducer的状态或者更改它部署时的initialState?

    我习惯于在多个组件中使用Redux还原程序,但是useReducer需要一个传递的initialState。。。这就提出了一个问题:react-hook的reducer是作为一个实例通过多个组件使用,还是始终是两个单独的实例?

  • 共有1个答案

    籍英叡
    2023-03-14

    在您的示例中,您试图同时测试两件事情,最好作为单独的测试:减速器的单元测试和组件使用减速器的组件测试。

    1. 为了测试的目的,我应该如何修改一个reducer的状态或者更改它部署时的initialState

    与Redux reducer类似,您的reducer很容易进行单元测试,因为您将它作为纯函数导出。只需将初始状态传递到状态参数,将操作传递到操作

    it('returns new state for "update" type', () => {
      const initialState = [1];
      const updateAction = {type: 'update', newState: [1, 2, 3] };
      const updatedState = fooReducer(initialState, udpateAction);
      expect(updatedState).toEqual([1, 2, 3]);
    });
    

    如果您愿意,还可以在useReducer的上下文中对其进行测试:

    it('should render as many divs as there are items', () => {
      act(() => {
        const { result } = renderHook(() => useReducer(FooReducer, [1]));
        const [state, dispatch] = result.current;
        dispatch({type: 'update', newState: [1, 2, 3]});
      });
    
      expect(state).toEqual([1, 2, 3]);
      // or expect(state).toHaveLenth(3) if you prefer
    });
    

    以下是useReduer与Redux的不同之处:您可以重用减速器本身,但是如果您有多个useReduer,则从每个减速器返回的状态调度以及初始状态,将是单独的实例。

    为了测试BarComponent在reducer更新时是否更新,您需要一种方法从组件内部触发dispatch,因为您正在组件内部调用useReducer。下面是一个例子:

    export function BarComponent() {
      const [state, dispatch] = useReducer(FooReducer, []);
    
      const handleUpdate = () => dispatch({type: 'update', newState: [1, 2, 3]})
    
      return (
        <>
          {state.map((item) => (<div />))}
          <button onClick={handleUpdate}>Click to update state</button>
        </>
      );
    }
    
    it('should render as many divs as there are items', () => {
      wrapper = mount(<BarComponent />);
    
      expect(wrapper.find('div')).toHaveLength(0);
    
      wrapper.find('button').simulate('click');
    
      expect(wrapper.find('div')).toHaveLength(3);
    });
    

    这可能不太现实,因为我正在组件本身中硬编码新数组,但希望它能给你一个想法!

     类似资料:
    • 问题内容: 我有一个使用的组件,然后它的输出取决于上下文中的值。一个简单的例子: 当使用来自react和jest快照的浅色渲染器测试此组件时。如何更改值? 问题答案: 通常,使用钩子应该不会改变测试策略。实际上,这里更大的问题不是问题,而是上下文的使用,这使事情变得有些复杂。 有很多方法可以使这项工作,但是我发现唯一可以使用的方法是注入一个模拟钩子: 但是,这有点脏,并且是特定于实现的,因此,如果

    • 我有一个使用的组件,然后它的输出依赖于上下文中的值。一个简单的例子: 使用react和jest快照中的浅层渲染器测试此组件时。如何更改的值?

    • 到目前为止,在单元测试中,响应路由器匹配参数作为组件的道具被检索。因此,测试一个组件,考虑一些特定的匹配,与特定的url参数,是很容易的:我们只需要精确路由器匹配的道具,因为我们想要在测试中渲染组件(我使用酶库的目的)。 我真的很喜欢检索路由内容的新钩子,但我没有找到关于如何在单元测试中使用新的react路由器钩子模拟react路由器匹配的示例?

    • 2-我在FlatList中实现分页,所以当用户到达数据列表的末尾时,我调用一个函数来增加当前页,并根据当前页更新的情况,再次提取,因为我将to useEffect传递给依赖项数组 所以这里的问题是应该将以前的数据与新数据联系起来,所以我使用方法, 它工作得很好,但有时我收到一个警告,告诉我有一个重复的数据,当我使用扩展时不工作,我得到一个很大的错误,因为Flatlist keyExtractor问

    • 提前谢了。我有一个状态数组,如下所示。 我需要添加一个项目到状态数组,我发现我们不需要做状态突变。如何使用PrevState设置状态。 如何调用set State以追加此状态数组。 像这样的东西?

    • 如果您有一个调用获取数据的自定义钩子的React组件,在测试React组件时,模拟内部自定义钩子结果的最佳方法是什么?我看到了两种主要的方法: 1)Jest.mock自定义钩子。这似乎是最值得推荐的方法,但它似乎需要测试对内部实现细节以及它可能需要模拟的内容有更多的了解,而不是组件的道具接口可能建议的内容(假设使用道具类型或TypeScript) 2) 使用依赖注入方法。将钩子声明为道具,但将其默