首页 > 解决方案 > 如何告诉 Jest/RTL 适当地等待非 UI 异步操作完成?

问题描述

更新

经过一番挖掘,似乎我的效果层(SheetEffects.clearAll)中的间谍方法实际上并没有被嘲笑,这就是expect失败的原因,所以这不是 RTL 的问题。

原帖

我不认为我在考虑这个问题,但是如果您不同意,请给出一个彻底和深思熟虑的答复。KCD 的react-testing-library 文档提供了在执行 Jest 之前异步等待 DOM 更新的示例expect。我的问题与如果在类似的异步过程中没有UI 更新(这可能超出 RTL 的预期范围)有关怎么办?

鉴于:

  it('should dispatch the correct action when clicked', async () => {
    const { container } = renderWithReduxProvider(<ClearAllButton />, {}, true)

    // spying on this and checking if it's been called in the `wait` block fails
    // jest.spyOn(SheetEffects, 'clearAll')

    // this works within `wait`, but I don't need/want to test this here
    const spy = jest.spyOn(SheetApiV2, 'clearAll').mockReturnValue(Promise.resolve())

    fireEvent.click(container.firstChild as HTMLElement)

    // this works, but I'm fairly certain it's a race condition
    // and I'm just getting lucky
    await wait(() => expect(spy).toHaveBeenCalledTimes(1))
  })

由于我已经对效果层进行了单元测试,我真的只想能够明确确认组件调度了正确的操作(通过mapDispatchToProps)。还有其他副作用方法可以查看这是否已完成,但我想专门测试组件是否调度了正确的操作,而不是由于此操作而调用了 reducer,或者调用了效果。

NBrenderWithReduxProvider函数使用我们的效果中间件创建一个 Redux 存储,并返回一个<Provider/>包装的连接组件。另请注意,效果函数是异步的。

标签: reactjsjestjs

解决方案


我认为你这样做的方式是正确的,只是wait为了调用方法。

但是,我认为我不同意这种说法

由于我已经对效果层进行了单元测试,我真的只想能够明确确认组件调度了正确的操作

在我看来,你应该测试副作用是否发生。你看,调用SheetEffects.clearAll是一个实现细节。如果你决定重写你的应用程序而不使用 Redux 怎么办?或者如果你重命名clearAllclearEverything? 换句话说,如果你重构代码会发生什么?测试将中断。

但是,如果您测试副作用,测试仍然有效,因为它不关心底层实现。该测试还将使您更有信心,因为您将测试完整功能是否有效。

另外,您可以摆脱单元测试,clearAll因为您正在隐式测试它。


一点旁注:当你使用时,jest.spyOn你应该在测试结束时重置你的间谍。你可以这样做spy.mockRestore()


推荐阅读