使用Vitest测试React组件时,react-router-dom Mock缺失BrowserRouter报错
解决Vitest测试React组件时react-router-dom模拟错误的问题
我在使用Vitest测试React组件(依赖MSW进行服务端模拟)时,遇到了如下错误:
Error: [vitest] No "BrowserRouter" export is defined on the "/node_modules/react-router-dom/dist/main.js" mock. Did you forget to return it from "vi.mock"?
测试中渲染组件的函数使用Router包裹目标组件,测试代码里尝试通过vi.mock覆盖useParams传入固定articleId,但无论是完全mock模块还是通过importOriginal保留原模块并覆盖useParams,都会触发上述错误。
方案1:使用vi.spyOn单独mockuseParams函数
无需mock整个react-router-dom模块,只针对useParams做局部mock,这样不会影响模块中其他组件(如BrowserRouter/MemoryRouter)的正常导入:
import * as reactRouterDom from 'react-router-dom'; describe('EntryDetail component', () => { beforeAll(() => server.listen()); afterEach(() => { server.resetHandlers(); vi.clearAllMocks(); // 清空mock,避免用例间数据污染 }); afterAll(() => server.close()); it('allows only 150 characters for comments', async () => { // 单独mock useParams返回固定的articleId vi.spyOn(reactRouterDom, 'useParams').mockReturnValue({ articleId: '63d466ca3d00b50db15aed93', }); authorizedServerSetup(); renderComponent(); // 后续测试逻辑 const commentInput = await screen.findByRole('textbox'); // 验证字符限制的测试代码... }); });
方案2:正确mock整个模块并保留所有原导出
如果必须mock整个模块,需确保返回对象包含原模块的所有导出,包括测试用到的路由组件:
vi.mock('react-router-dom', async (importOriginal) => { const originalModule = await importOriginal(); return { // 保留原模块所有命名导出 ...originalModule, // 覆盖useParams useParams: vi.fn(() => ({ articleId: '63d466ca3d00b50db15aed93', })), // 若使用了默认导出的路由组件,需额外保留 default: originalModule.default, }; });
验证要点
- 确认渲染组件时使用的
Router(如BrowserRouter或MemoryRouter)是从react-router-dom正常导入的,未被错误覆盖。 - 若使用
MemoryRouter,直接在测试渲染函数中替换BrowserRouter即可,无需额外调整mock逻辑。
内容的提问来源于stack exchange,提问作者Daniel Tkach
相关产品推荐
相关产品推荐

