React Native导航测试中Animated(View)未包裹act警告的解决方法
问题背景
下面的测试代码实现了从Source页面导航到Target页面:
import 'react-native-gesture-handler/jestSetup'; import React, {Component, useEffect} from 'react'; import {NavigationContainer} from '@react-navigation/native'; import {createStackNavigator} from '@react-navigation/stack'; import {render} from '@testing-library/react-native'; const SourceFunc = ({navigation}) => { useEffect(() => navigation.navigate('Target'), [navigation]); }; class SourceClass extends Component { componentDidMount() { this.props.navigation.navigate('Target'); } render() {} } const Target = () => {}; for (let i = 0; i < 5; i++) { it('', async () => { const Stack = createStackNavigator(); await render( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Source" component={SourceFunc} /> <Stack.Screen name="Target" component={Target} /> </Stack.Navigator> </NavigationContainer>, ); }); } for (let i = 0; i < 5; i++) { it('', async () => { const Stack = createStackNavigator(); await render( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Source" component={SourceClass} /> <Stack.Screen name="Target" component={Target} /> </Stack.Navigator> </NavigationContainer>, ); }); }
测试全部通过,但弹出大量如下警告:
Warning: An update to Animated(View) 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/link/wrap-tests-with-act
虽然已经使用await render,但不清楚警告中提到的Animated(View)更新来源。
问题
如何在React Native测试中执行导航操作,同时避免触发该警告?
补充说明
- 单次测试不会触发警告(因此用多轮测试来复现问题)
- 若单测执行时间小于约130ms,也不会触发警告
完整复现步骤
pushd $(mktemp -d) npx react-native init test pushd test yarn add @react-navigation/native @react-navigation/stack react-native-gesture-handler react-native-safe-area-context yarn add --dev @testing-library/react-native patch -p1 <<EOF --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,4 @@ module.exports = { preset: 'react-native', + transformIgnorePatterns: [], }; EOF # 添加test.js文件 npx jest test.js
解决方案
这个警告源于React Navigation的页面切换动画在测试结束后仍在执行状态更新,且这些更新未被act()包裹。可以通过以下几种方式解决:
1. 禁用导航动画
在测试时给Stack.Navigator添加screenOptions={{ animationEnabled: false }},直接关闭页面切换动画,从根源避免Animated组件的状态更新:
await render( <NavigationContainer> <Stack.Navigator screenOptions={{ animationEnabled: false }}> <Stack.Screen name="Source" component={SourceFunc} /> <Stack.Screen name="Target" component={Target} /> </Stack.Navigator> </NavigationContainer>, );
2. 用waitFor等待所有更新完成
在render之后调用waitFor,确保所有异步状态更新都执行完毕,让这些操作自动被act()包裹:
import {render, waitFor} from '@testing-library/react-native'; // ...测试代码 await render(/* 组件内容 */); await waitFor(() => {}); // 等待所有pending的状态更新完成
3. 模拟Animated模块
在jest配置中模拟Animated模块,跳过真实的动画逻辑:
在jest.setup.js中添加:
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
或者直接在测试文件顶部添加模拟:
jest.mock('react-native', () => { const originalRN = jest.requireActual('react-native'); return { ...originalRN, Animated: { ...originalRN.Animated, timing: jest.fn(() => ({ start: jest.fn() })), spring: jest.fn(() => ({ start: jest.fn() })), }, }; });
4. 添加短暂延迟(不推荐)
如果以上方法都不适用,可以在测试末尾添加一个短暂延迟,让动画更新完成:
await new Promise(resolve => setTimeout(resolve, 150));
内容的提问来源于stack exchange,提问作者msbit
相关产品推荐
相关产品推荐

