【问题标题】:Destructuring need waitFor解构需要waitFor
【发布时间】:2021-09-17 02:47:49
【问题描述】:

为什么解构需要waitFor?

Codesandbox

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

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

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

【问题讨论】:

  • 您需要使用waitFor,因为设置状态(在您的情况下调用set)是一个异步操作。详情请见React setState not Updating Immediately
  • @juliomalves 我编辑了问题以便更好地解释它。

标签: destructuring react-hooks-testing-library


【解决方案1】:

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

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

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

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

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

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

所以真正的问题是为什么在调用set 时不更新get(顺便说一句...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 的值在一个名为state 的新变量中的任何时刻。调用setState(或result.setState)将成功更新result.state,但没有指向state变量的链接,因此值不会改变。

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

最后,我认为这是一个常见的意外,尤其是在使用来自钩子的元组结果时(例如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
    });
  });
// ...

无论如何,希望能解决问题并祝测试愉快!

【讨论】:

  • 这是一个很棒的答案,现在很清楚了。谢谢你。 PS 真的get 是个坏名字,我现在明白了。
猜你喜欢
  • 1970-01-01
  • 2014-08-28
  • 1970-01-01
  • 1970-01-01
  • 2015-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多