解构需要waitFor
Destructuring need waitFor
为什么解构需要 waitFor?
所有测试都做同样的事情。在'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
});
});
// ...
在这种情况下,等待期望传递超时,因为值永远不会改变。
所以真正的问题是为什么在调用 set
时 get
(奇怪的名字 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
的任何初始值,而不是 set
ting 的数量将允许新的要更新的变量,因为它与 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
});
});
// ...
无论如何,希望一切顺利,测试愉快!
为什么解构需要 waitFor?
所有测试都做同样的事情。在'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
});
});
// ...
在这种情况下,等待期望传递超时,因为值永远不会改变。
所以真正的问题是为什么在调用 set
时 get
(奇怪的名字 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
的任何初始值,而不是 set
ting 的数量将允许新的要更新的变量,因为它与 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
});
});
// ...
无论如何,希望一切顺利,测试愉快!