Vitest测试TanStack Router Link组件遇错:如何正确Mock与测试?
Mock TanStack Router Link组件的测试方案
问题背景
父组件中使用@tanstack/react-router的Link组件,测试时用vi.mock()Mock该组件出现Uncaught TypeError: Cannot read properties of null (reading 'buildLocation')错误;手动配置路由通过RouterProvider渲染时,仅加载404路由而非目标Link。需解决:
- 如何正确Mock TanStack Router的Link组件;
- 如何在Mock环境下测试包含多个Link的大型组件。
1. 正确Mock TanStack Router的Link组件
方式一:浅Mock为普通<a>标签(推荐简单场景)
直接MockLink组件,将其替换为原生<a>标签,传递to属性作为href,完全脱离TanStack Router的内部上下文依赖:
vi.mock('@tanstack/react-router', () => ({ Link: vi.fn(({ to, children, ...props }) => { // 处理字符串和对象两种形式的to参数 const href = typeof to === 'string' ? to : JSON.stringify(to); return <a href={href} {...props}>{children}</a>; }), }));
这种方式无需配置路由上下文,适合仅需验证Link存在和跳转目标的基础测试。
方式二:模拟完整路由上下文(适合需要路由逻辑的场景)
如果需要保留Link的路由参数解析等功能,可手动创建简易路由并通过RouterProvider提供上下文:
import { RouterProvider, createRouter } from '@tanstack/react-router'; import { render } from '@testing-library/react'; // 配置与组件中Link匹配的路由 const testRouter = createRouter({ routes: [ { path: '/', element: <div>Home</div> }, { path: '/about', element: <div>About</div> }, { path: '/user/:id', element: <div>User</div> }, // 匹配动态路由 ], }); // 测试时用RouterProvider包裹目标组件 test('renders Link without 404', () => { render( <RouterProvider router={testRouter}> <YourParentComponent /> </RouterProvider> ); // 验证目标Link存在 expect(screen.getByRole('link', { name: /user/i })).toBeInTheDocument(); });
注意:若仍加载404路由,需检查路由配置的path是否与Link的to属性完全匹配(包括动态参数格式)。
2. 测试包含多个Link的大型组件
方案一:批量验证Link的跳转目标(基于浅Mock)
利用浅Mock后的<a>标签,通过测试工具批量查询并验证所有Link的属性:
test('all links have correct targets', () => { render(<YourLargeComponent />); // 定义预期的Link映射:显示文本 -> 跳转路径 const expectedLinks = [ { text: '首页', href: '/' }, { text: '关于我们', href: '/about' }, { text: '用户详情', href: JSON.stringify({ to: '/user/123' }) }, ]; // 批量断言 expectedLinks.forEach(({ text, href }) => { const link = screen.getByRole('link', { name: text }); expect(link).toHaveAttribute('href', href); }); });
方案二:验证路由跳转逻辑(基于路由上下文)
若需测试Link点击后的导航行为,可MockuseRouter钩子并断言导航函数的调用:
import { useRouter } from '@tanstack/react-router'; // Mock useRouter钩子,替换navigate方法为模拟函数 vi.mock('@tanstack/react-router', () => ({ ...vi.importActual('@tanstack/react-router'), useRouter: vi.fn(() => ({ navigate: vi.fn(), })), })); test('triggers correct navigation on link click', async () => { const mockNavigate = vi.fn(); useRouter.mockReturnValue({ navigate: mockNavigate }); render( <RouterProvider router={testRouter}> <YourLargeComponent /> </RouterProvider> ); // 点击目标Link await screen.getByRole('link', { name: /用户详情/i }).click(); // 断言导航函数被正确调用 expect(mockNavigate).toHaveBeenCalledWith('/user/123'); });
常见问题排查
buildLocation错误:原因是Link在无路由上下文的环境中渲染,选择浅Mock为<a>标签或提供RouterProvider即可解决。- 404路由加载:检查路由配置的
path与Link的to属性是否完全匹配,动态路由需确保参数定义一致(如/user/:id对应to="/user/123")。
内容的提问来源于stack exchange,提问作者Leonidas
相关产品推荐
相关产品推荐

