使用React Router v6.4测试时出现ReferenceError: Request is not defined
解决React Router v6测试中
ReferenceError: Request is not defined错误 问题背景
使用React Testing Library结合Vitest测试React Router v6的路由跳转逻辑时,采用RouterProvider+createMemoryRouter配置,点击路由链接后触发未处理拒绝错误:ReferenceError: Request is not defined,初始页面渲染正常,但跳转时失败。
错误原因
React Router v6.4+引入的loader/action机制依赖浏览器原生的Request API,但Vitest运行在Node.js环境中,该环境默认未全局提供Request对象,当路由跳转触发loader执行时,内部创建Request实例就会抛出此错误。
可行解决方案
1. 全局polyfill Request对象
React Router内部使用@remix-run/web-fetch实现fetch相关功能,我们可以直接用这个包来polyfill:
- 安装依赖:
npm install -D @remix-run/web-fetch
- 在测试文件顶部添加:
import { Request } from '@remix-run/web-fetch'; globalThis.Request = Request;
如果需要全局生效,可创建vitest.setup.ts文件:
import { Request } from '@remix-run/web-fetch'; globalThis.Request = Request;
然后在vite.config.ts的测试配置中指定:
export default defineConfig({ test: { setupFiles: ['./vitest.setup.ts'], // 其他测试配置 }, });
2. Mock路由loader(仅测试跳转逻辑时适用)
如果测试只需要验证路由跳转后的组件渲染,不需要测试loader的业务逻辑,可以mock掉loader:
const router = createMemoryRouter( routes.map(route => ({ ...route, loader: route.loader ? () => Promise.resolve({}) : undefined, })), { initialEntries: ['/'] } );
3. 使用React Router官方测试工具包
React Router提供了@remix-run/testing包,内置了测试所需的环境polyfill:
- 安装依赖:
npm install -D @remix-run/testing
- 替换
createMemoryRouter为createTestRouter:
import { createTestRouter } from '@remix-run/testing'; const router = createTestRouter(routes, { initialEntries: ['/'] });
测试示例
修改配置后,重新编写测试验证跳转:
import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { RouterProvider } from 'react-router-dom'; import { createMemoryRouter } from 'react-router-dom'; import { routes } from '../path-to-routes'; import { Request } from '@remix-run/web-fetch'; globalThis.Request = Request; test('点击登录链接跳转到登录页', async () => { const router = createMemoryRouter(routes, { initialEntries: ['/'] }); const user = userEvent.setup(); render(<RouterProvider router={router} />); await user.click(screen.getByText('登录')); expect(screen.getByRole('form', { name: /登录/i })).toBeInTheDocument(); });
内容的提问来源于stack exchange,提问作者Thenlie
相关产品推荐
相关产品推荐

