在 Jest 中异步测试 React Navigation 5:NavigationContainer 导致控制台错误
Async testing React Navigation 5 in Jest: NavigationContainer causes console error
我正在使用 react-native-testing-library
,在将 react-navigation
从 4 升级到 5 之后,我按照以下说明进行操作:https://callstack.github.io/react-native-testing-library/docs/react-navigation 升级了我的大部分测试套件。
到目前为止一切顺利。这里的关键基本上是将测试包装在 NavigationContainer
中,这样我的组件就可以访问以前来自 react-navigation-hooks
.
的那些挂钩
当我的测试是同步的时,这工作正常,但是一旦我将 async
关键字添加到测试函数,我就会收到以下警告:
console.error
Warning: An update to ForwardRef(NavigationContainer) inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/docs/test-utils.html#act
in ForwardRef(NavigationContainer)
我 运行 同步进行了很多测试并且成功了。但是在某些组件中,我执行 运行 一些异步逻辑以获得所需的结果。
据我所知,我应该将所有异步代码包装在 act
调用中。但是,即使在这种情况下,我也无法摆脱这个错误。
我继续尝试缩小问题范围。现在,我所做的就是像这样渲染包装的组件:
test('a simple test', async () => {
const component = (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
const {queryByText} = render(component);
expect(queryByText('test')).toBeNull();
});
而且我还在运行陷入同样的问题。请注意,实际测试成功,只是我仍然收到此控制台错误。
接下来,我尝试将 render
调用包装在 act
和 waitForElement
中,因为这是我在 运行 宁异步逻辑时应该做的。但似乎这里的异步代码是在 渲染发生后 执行的。
所以我继续调查 NavigationContainer
的哪一部分负责触发导致错误的异步逻辑,似乎这段代码(第 49-51 行)做了一些有趣的事情:
const [isReady, initialState = rest.initialState] = useThenable(
getInitialState
);
getInitialState
是在 (43-47) 之前的某些行 useLinking
调用的 return 值的解构结果。没有进一步的细节, getInitialState
被包裹在一个承诺里面,所以它变成了 "thenable".
现在,如果我取消注释 useThenable
,控制台错误就会消失。但显然,这不是我可以从该文件外部轻松实现的。所以我有点卡在这里,因为我不知道如何以异步方式编写我的测试代码,而不会一直 运行ning 进入这个错误,我不想忽略或抑制它也是个好主意。
如有任何帮助,我们将不胜感激。
我从 react-native-testing-library
调用 render
后对执行异步工作的组件、useEffect
(充当 componentDidMount
)、更改状态等的建议:
await act(async () => {})
甚至:
await act(async () => await flushMicrotasksQueue())
如果你有一些超时。
Test Renderer 的实例具有卸载 in-memory 树的 unmount() 方法,触发适当的生命周期事件。在测试结束时添加:
component.unmount()
您可以在 https://reactjs.org/docs/test-renderer.html#testrendererunmount 获得更多信息。
我只能通过将 expect
和 render
调用放在同一个函数中才能让这个按钮消失。从共享函数返回渲染结果导致 ForwardRef
错误。很奇怪,但我把范围缩小到这个。
我还在渲染后调用此 wait()
函数,这让 Apollo 运行 也可以进行 GraphQL 查询:
export async function wait(ms = 0): Promise<void> {
return await act(async () => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
});
}
我正在使用 react-native-testing-library
,在将 react-navigation
从 4 升级到 5 之后,我按照以下说明进行操作:https://callstack.github.io/react-native-testing-library/docs/react-navigation 升级了我的大部分测试套件。
到目前为止一切顺利。这里的关键基本上是将测试包装在 NavigationContainer
中,这样我的组件就可以访问以前来自 react-navigation-hooks
.
当我的测试是同步的时,这工作正常,但是一旦我将 async
关键字添加到测试函数,我就会收到以下警告:
console.error
Warning: An update to ForwardRef(NavigationContainer) inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/docs/test-utils.html#act
in ForwardRef(NavigationContainer)
我 运行 同步进行了很多测试并且成功了。但是在某些组件中,我执行 运行 一些异步逻辑以获得所需的结果。
据我所知,我应该将所有异步代码包装在 act
调用中。但是,即使在这种情况下,我也无法摆脱这个错误。
我继续尝试缩小问题范围。现在,我所做的就是像这样渲染包装的组件:
test('a simple test', async () => {
const component = (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
const {queryByText} = render(component);
expect(queryByText('test')).toBeNull();
});
而且我还在运行陷入同样的问题。请注意,实际测试成功,只是我仍然收到此控制台错误。
接下来,我尝试将 render
调用包装在 act
和 waitForElement
中,因为这是我在 运行 宁异步逻辑时应该做的。但似乎这里的异步代码是在 渲染发生后 执行的。
所以我继续调查 NavigationContainer
的哪一部分负责触发导致错误的异步逻辑,似乎这段代码(第 49-51 行)做了一些有趣的事情:
const [isReady, initialState = rest.initialState] = useThenable(
getInitialState
);
getInitialState
是在 (43-47) 之前的某些行 useLinking
调用的 return 值的解构结果。没有进一步的细节, getInitialState
被包裹在一个承诺里面,所以它变成了 "thenable".
现在,如果我取消注释 useThenable
,控制台错误就会消失。但显然,这不是我可以从该文件外部轻松实现的。所以我有点卡在这里,因为我不知道如何以异步方式编写我的测试代码,而不会一直 运行ning 进入这个错误,我不想忽略或抑制它也是个好主意。
如有任何帮助,我们将不胜感激。
我从 react-native-testing-library
调用 render
后对执行异步工作的组件、useEffect
(充当 componentDidMount
)、更改状态等的建议:
await act(async () => {})
甚至:
await act(async () => await flushMicrotasksQueue())
如果你有一些超时。
Test Renderer 的实例具有卸载 in-memory 树的 unmount() 方法,触发适当的生命周期事件。在测试结束时添加:
component.unmount()
您可以在 https://reactjs.org/docs/test-renderer.html#testrendererunmount 获得更多信息。
我只能通过将 expect
和 render
调用放在同一个函数中才能让这个按钮消失。从共享函数返回渲染结果导致 ForwardRef
错误。很奇怪,但我把范围缩小到这个。
我还在渲染后调用此 wait()
函数,这让 Apollo 运行 也可以进行 GraphQL 查询:
export async function wait(ms = 0): Promise<void> {
return await act(async () => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
});
}