测试React-Navigation:如何验证StackNavigator中旧屏幕已不显示
你遇到的两个现象分别是两个不同的问题导致的:
为什么跳转后Screen A的元素还能被查到?
@react-navigation/native-stack是基于原生系统的导航栈实现的,在Jest测试环境下,原生栈的页面卸载逻辑不会被触发——前一个页面只是被压在栈底不可见,并没有真的从测试的元素树中移除,所以queryByText('Screen A')确实不会返回null,expect(queryByText('Screen A')).not.toBeNull()能通过是符合测试环境下的实际表现的。
为什么toBeNull()断言会报找不到navigation context的错误?
这个报错和你的断言逻辑无关,是Jest的差异打印机制导致的:当toBeNull()断言失败时,Jest会尝试遍历整个元素的属性树来打印差异,而Screen组件挂载的navigation是react-navigation内部的代理对象,Jest读取它的内部属性时会触发context检查,就抛出了这个无关报错。not.toBeNull()断言通过时不会触发差异打印,所以不会报错。
解决建议
按优先级推荐以下方案:
改用可见性断言(最符合你的实际需求)
你要验证的是Screen A不再展示,而不是完全从元素树中卸载,直接用react-native-testing-library提供的toBeVisible匹配器即可:// 跳转后执行这个断言即可 expect(queryByText('Screen A')).not.toBeVisible();这个断言不需要等待额外逻辑,也不会触发context报错,完全符合你的测试目标。
切换为JS实现的栈导航器
如果你确实需要验证前一个页面被卸载,可以把@react-navigation/native-stack替换为@react-navigation/stack,后者是纯JS实现的栈导航,默认跳转后会卸载前一个页面,此时queryByText('Screen A')会正常返回null。配置Jest忽略navigation对象序列化
如果你要保留native-stack的使用,又不想触发报错,可以在Jest配置中添加对react-navigation对象的序列化忽略规则,避免Jest遍历内部代理属性:
在jest.config.js中添加如下配置:module.exports = { // 其余现有配置保持不变 transformIgnorePatterns: [ 'node_modules/(?!(react-native|@react-navigation|react-native-reanimated)/)', ], setupFilesAfterEnv: [ '<rootDir>/jest.setup.js', ], };然后在
jest.setup.js中添加:import mockNavigation from '@react-navigation/native/jest/mock'; jest.mock('@react-navigation/native', () => ({ ...jest.requireActual('@react-navigation/native'), useNavigation: () => mockNavigation, }));即可避免序列化navigation对象时的报错。
内容的提问来源于stack exchange,提问作者Shaddix

