Vitest环境下React+Redux-Toolkit应用useNavigate模拟失效求助
问题修复代码
你的报错根源是mock后的react-router-dom未导出BrowserRouter,而测试工具函数renderWithProviders依赖该组件。修改测试文件中的mock逻辑如下:
import React from 'react'; import { renderWithProviders } from '../../../../tests_setup/test-utils'; import { screen, fireEvent } from '@testing-library/dom'; import { useNavigate } from 'react-router-dom'; import SearchInput from '../SearchInput'; import { resetSearch, updateSearchterm, getData } from '../../../features/data/dataSlice'; const mockUseNavigate = vi.fn(); vi.mock('react-router-dom', async (importOriginal) => { // 导入原模块的所有导出 const actual = await importOriginal(); return { ...actual, // 保留原模块所有导出(包括BrowserRouter) // 覆盖useNavigate钩子,返回mock导航函数 useNavigate: () => mockUseNavigate, }; });
测试时,触发组件中调用导航的逻辑后,可通过以下断言验证:
expect(mockUseNavigate).toHaveBeenCalledWith('/your-target-path');
原理讲解
Vitest模块Mock机制
使用vi.mock会完全替换目标模块的导出。若仅需部分mock(如仅修改useNavigate),必须通过importOriginal导入原模块的完整导出,再覆盖需要自定义的部分。否则原模块的其他导出(如BrowserRouter、Route等)会被清空,导致依赖这些导出的代码报错。useNavigate的Mock逻辑
useNavigate是返回导航函数的React钩子,因此mock时需要让该钩子返回你定义的mockUseNavigate函数。这样组件内调用const navigate = useNavigate()时,navigate就是你的mock函数,可追踪其调用参数和次数。为什么之前的实现失败?
尽管你使用了importActual导入原模块,但在ES模块导出的处理上可能存在隐性问题,导致BrowserRouter未被正确继承。使用importOriginal(Vitest推荐的替代importActual的工具)能更稳定地处理模块导出。
额外优化建议
- 将
react-router-dom的通用mock逻辑抽离到测试工具文件中,避免重复编写。 - 在
beforeEach钩子中重置mock函数,避免测试用例间的状态污染:beforeEach(() => { mockUseNavigate.mockReset(); });
内容的提问来源于stack exchange,提问作者Mawin
相关产品推荐
相关产品推荐

