解构需要waitFor

Destructuring need waitFor

为什么解构需要 waitFor?

Codesandbox

所有测试都做同样的事情。在'ok.test.ts'文件中我使用renderHook,我使用result.current[1]设置state,result.current[0]获取state的值,到目前为止不错。

'not-ok' 测试中,我对 renderHook 的结果进行了解构,但由于状态值不正确,测试失败了。

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

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

TL;DR;您不能解构 result.current 并让 get 接收更新的值。

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

首先,在您的示例中,resolved 测试通过了,因为 waitFor return 承诺您必须 await 才能看到失败:

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

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

所以真正的问题是为什么在调用 setget(奇怪的名字 BTW... state 在这个例子中更合适)不更新?

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

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

const { state, setState } = result;

setState(1);

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

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

好吧,result 的解构将 result.state 的值锁定到一个名为 [=20= 的新变量中当时的值].调用 setState(或 result.setState)将成功更新 result.state,但是 state 变量没有 link,因此值不会改变。

因此,通过 const { result: { current: [get, set] } } = renderHook(...),您还可以将 get 锁定到 result.current 的任何初始值,而不是 setting 的数量将允许新的要更新的变量,因为它与 result.current 的连接已丢失。

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

许多人没有意识到的另一件事是 result.current 的值是您从 renderHook 回调中 return 得到的任何值,因此您可以通过更改您的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
    });
  });
// ...

无论如何,希望一切顺利,测试愉快!