2

为什么解构需要waitFor?

代码沙盒

所有测试都做同样的事情。在我使用 renderHook的'ok.test.ts'result.current[1]文件中,我 用来设置状态并result.current[0]获取状态的值,到目前为止一切顺利。

'not-ok'测试中,我会解构 renderHook 的结果并且测试失败,因为状态值不正确。

“resolved.test.ts”中使用 waitFor 进行解构测试时有效。我知道设置状态是异步的。我不明白为什么'ok.test.ts'在没有waitFor 和没有解构的情况下工作,但如果我进行解构,我需要waitFor。

4

1 回答 1

1

这里的作者react-hooks-testing-library

TL;博士; 您无法解构result.currentget收到更新的值。

这出现了很多,所以我会花一些时间为遇到这个问题的任何人提供更详细的答案。

首先,在您的示例中,resolved测试通过,因为返回一个您必须看到失败waitFor的承诺:await

// ...
    await waitFor(() => {
      expect(get).toStrictEqual({
        data1: 1,
        data2: 2,
        data3: 3
      });
    });
// ...

在这种情况下,它会超时等待期望通过,因为值永远不会改变。

所以真正的问题是为什么不get(奇怪的名字顺便说一句......state在这个例子中更合适)在set被调用时更新?

好吧,让我们看看这段代码:

const result = {
  state: 0,
  setState(newState: number) {
    this.state = newState;
  }
};

const { state, setState } = result;

setState(1);

expect(state).toBe(1); // fails

测试失败的原因与您的示例相同。你能看出为什么吗?

好吧,解构将的值result 锁定result.state在一个名为 的新变量中,无论它当时是什么state。调用setState(or result.setState) 将成功 update result.state,但没​​有指向state变量的链接,因此值不会改变。

因此,通过让const { result: { current: [get, set] } } = renderHook(...)您也锁定hasget的初始值result.current而不是setting 的数量,这将允许更新新变量,因为它的连接result.current已丢失。

最后,我认为这是一个常见的意外,尤其是在使用来自钩子的元组结果时(例如const [state, setState] = useState())。给出的常见原因是人们不喜欢在他们的测试中result.current[0]提到它们。result.current[1]我可以对此表示同情。

许多人没有意识到的另一件事是,值result.current是您从renderHook回调返回的任何内容,因此您可以通过将renderHook调用更改为以下内容轻松获得命名良好的值:

// ...
    const { result } = renderHook(() => {
      const [get, set] = React.useState({
        data1: 0,
        data2: 0,
        data3: 0
      })
      return { get, set }
    });

    act(() => {
      result.current.set({ data1: 1, data2: 2, data3: 3 });
    });

    expect(result.current.get).toStrictEqual({
      data1: 1,
      data2: 2,
      data3: 3
    });
  });
// ...

无论如何,希望清除它并进行愉快的测试!

于 2021-10-14T11:56:40.573 回答