解构需要waitFor



为什么解构需要waitFor?

Codesandbox

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

在<<p> strong> '不可以' 我解构renderHook的结果,测试失败,因为状态值不正确。 在<<p> strong>"resolved.test.ts"当使用waitFor时,具有解构工作的测试。我知道集合状态是异步的。我不明白为什么'ok.test.ts'可以在没有waitFor和解构的情况下工作,但是如果我做了解构,我需要waitFor。

react-hooks-testing-library作者在此

TL,博士;你不能解构result.current而让get接收更新的值。

这个问题经常出现,所以我将花一些时间给每个遇到这个问题的人一个更详细的答案。

首先,在您的示例中,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(或result.setState)将成功更新result.state,但没有链接到state变量,因此值不会改变。

因此,通过const { result: { current: [get, set] } } = renderHook(...),您也将get锁定为result.current的初始值,而不是set的数量将允许新变量更新,因为它与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
});
});
// ...

无论如何,希望澄清和愉快的测试!

最新更新