Vitest运行React测试时出现Cannot read properties of undefined错误排查
解决Vitest测试中React-Query+useImmer的随机undefined错误
针对你遇到的测试中activeData.section/activeData.page随机变为undefined、导致Cannot read properties of undefined (reading 'name')的问题,从以下几个方向排查和解决:
1. 检查useImmer的状态更新逻辑,避免深层属性被意外覆盖
如果组件中存在监听react-query返回数据并更新activeData的逻辑,不要直接替换整个activeData对象,否则一旦mock数据出现异常(哪怕概率极低)或者时序问题,就会覆盖useImmer初始化的完整结构。
错误示例:
const [activeData, setActiveData] = useImmer({ notebook: {}, section: {}, page: {} }); const { data } = useQuery('your-query-key', fetchData); useEffect(() => { if (data) { // 直接替换会丢失未在data中定义的属性,或者data结构不完整时覆盖为undefined setActiveData(data); } }, [data]);
正确做法:用immer的produce做深层合并,只更新需要的属性:
useEffect(() => { if (data) { setActiveData(draft => { draft.notebook = { ...draft.notebook, ...data.notebook }; draft.section = { ...draft.section, ...data.section }; draft.page = { ...draft.page, ...data.page }; }); } }, [data]);
2. 强制稳定测试中的React-Query异步时序
Vitest中React-Query的异步加载时序可能和浏览器不一致,需要确保测试等待查询完全完成后再断言:
- 初始化QueryClient时关闭重试和自动重取,避免测试中状态波动:
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false, refetchOnMount: false, }, }, }); - 测试中用
queryClient.ensureQueryData替代单纯的waitFor,确保查询数据已就绪:test('组件渲染正常', async () => { render(<YourComponent />, { wrapper: QueryClientProviderWrapper }); // 等待查询完成并返回数据 await queryClient.ensureQueryData(['your-query-key']); // 再执行断言 expect(screen.getByRole('textbox')).toHaveValue('预期的页面名称'); });
3. 验证MSW Mock的稳定性
虽然你说mock返回完整数据,但测试中的异步mock可能存在偶发的结构缺失,建议在mock handler中硬编码完整的返回结构,避免动态生成导致的意外:
rest.get('/api/your-data', (req, res, ctx) => { // 硬编码完整结构,确保每次返回的data都包含notebook/section/page return res(ctx.json({ notebook: { id: '1', name: '测试笔记本' }, section: { id: '1', name: '测试章节' }, page: { id: '1', name: '测试页面' }, })); });
4. 添加防御性编程,避免运行时错误
即使测试问题解决,为了代码健壮性,在JSX中添加可选链和空值合并操作符,避免线上环境出现类似问题:
value={activeData.page?.name ?? ''}
内容的提问来源于stack exchange,提问作者user178456
相关产品推荐
相关产品推荐

