如何基于React Router v6的RouterProvider创建Testing Library路由测试方法?
适配RouterProvider的React Router v6测试方案
问题根源
项目使用createBrowserRouter+RouterProvider后,组件树已内置Router实例,测试时嵌套MemoryRouter会触发You cannot render a <Router> inside another <Router>错误,需改用内存路由实例直接注入RouterProvider。
实现renderWithRouter工具函数
import { render, RenderOptions } from '@testing-library/react'; import { createMemoryRouter, RouterProvider, RouteObject } from 'react-router-dom'; import userEvent from '@testing-library/user-event'; type RenderWithRouterOptions = Omit<RenderOptions, 'wrapper'> & { initialEntries?: string[]; routeConfig: RouteObject[]; }; export const renderWithRouter = async ({ initialEntries = ['/'], routeConfig, ...renderOptions }: RenderWithRouterOptions) => { const router = createMemoryRouter(routeConfig, { initialEntries }); const result = render(<RouterProvider router={router} />, renderOptions); const navigate = (to: string) => router.navigate(to); return { ...result, navigate, user: userEvent.setup(), router, }; };
测试用例示例
先复用项目中的路由配置(确保测试与生产路由一致):
// 项目路由配置文件 export const appRoutes: RouteObject[] = [ { path: '/', element: <HomePage /> }, { path: '/about', element: <AboutPage /> }, ];
编写测试逻辑:
import { screen } from '@testing-library/react'; import { renderWithRouter } from './test-utils'; import { appRoutes } from '../routes'; test('初始路由渲染首页,跳转后验证页面与URL', async () => { // 初始化测试,指定初始路由 const { user, router, navigate } = await renderWithRouter({ initialEntries: ['/'], routeConfig: appRoutes, }); // 验证初始状态 expect(screen.getByRole('heading', { name: /首页/i })).toBeInTheDocument(); expect(router.state.location.pathname).toBe('/'); // 模拟用户点击跳转 await user.click(screen.getByRole('link', { name: /关于/i })); // 验证跳转结果 expect(screen.getByRole('heading', { name: /关于/i })).toBeInTheDocument(); expect(router.state.location.pathname).toBe('/about'); // 手动调用navigate跳转 navigate('/'); expect(router.state.location.pathname).toBe('/'); });
核心注意点
- 直接复用项目的
RouteObject数组,避免测试路由与生产路由脱节 - 通过
router.state.location获取当前URL状态,替代v5中history对象的用法 - 使用
userEvent.setup()模拟真实用户交互,测试逻辑更贴近实际场景 renderWithRouter返回Promise,测试用例需用async/await处理异步逻辑
内容的提问来源于stack exchange,提问作者lzl124631x
相关产品推荐
相关产品推荐

