Jest模拟useNavigate未更新路径,取消模拟后遇Request未定义错误
问题分析与解决方案
1. 多步骤表单跳转后状态与路由不同步问题
你遇到的核心问题是:提交后currentStep状态已更新(标题显示Step2),但表单元素仍停留在step1,且路由路径未更新。结合代码来看,问题出在以下几点:
问题根源
- 路由路径格式错误:
navigate(step${currentStep + 1})生成的是相对路径,会在当前路径/signup/step1基础上拼接成/signup/step1/step2,和预期的/signup/step2不匹配。 - 测试未验证路由跳转:现有测试只检查了标题更新,未确认路由路径是否正确,也没等待路由跳转完成后再校验表单元素。
- 组件渲染逻辑不匹配:手动修改路径能显示正确表单,说明
Form组件是基于路由参数渲染步骤,但提交时仅更新了currentStep状态,未同步路由与状态的关联。
修复步骤
调整提交函数的路由跳转逻辑
改用绝对路径确保跳转到正确路由:
const onSubmit = () => { nextStep(); // 使用绝对路径替代相对路径,避免嵌套路由错误 navigate(`/signup/step${currentStep + 1}`); };
完善测试逻辑,等待路由更新
测试中需同时验证路由路径和对应步骤的表单元素:
import { MemoryRouter, Routes, Route } from 'react-router-dom'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; test('Move to the next step after form field is valid & submitted', async () => { const user = userEvent.setup(); render( <MemoryRouter initialEntries={['/signup/step1']}> <Routes> <Route path="/signup/*" element={<Form />} /> </Routes> </MemoryRouter>, ); await fillUserInfo(user); // 确保使用userEvent处理用户操作 await clickSubmit(user); await waitFor(() => { // 验证路由路径是否正确 expect(window.location.pathname).toBe('/signup/step2'); // 验证Step2专属表单元素存在(替换为你实际的元素标识) expect(screen.getByLabelText('Step2 手机号')).toBeInTheDocument(); expect(screen.getByText('Step2')).toBeInTheDocument(); }); });
同步路由与组件状态
在Form组件中添加路由监听,确保路由变化时同步更新currentStep:
import { useLocation } from 'react-router-dom'; const Form = () => { const location = useLocation(); const [currentStep, setCurrentStep] = useState(1); // 组件挂载或路由变化时,根据路径更新currentStep useEffect(() => { const stepMatch = location.pathname.match(/step(\d+)/); if (stepMatch) { setCurrentStep(Number(stepMatch[1])); } }, [location]); // 其余逻辑... };
2. 取消模拟useNavigate后出现ReferenceError: Request is not defined
Node.js 18+环境下出现该错误,是因为Jest默认的jsdom环境未提供全局Request对象,而React Router v6+依赖该对象。
修复方案
添加Request polyfill
- 安装依赖:
npm install --save-dev @remix-run/web-fetch
- 在Jest配置文件(
jest.config.js)中指定初始化文件:
module.exports = { setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'], // 其他配置... };
- 在
src/setupTests.js中添加polyfill:
import { Request, Response, Headers } from '@remix-run/web-fetch'; if (!globalThis.Request) { globalThis.Request = Request; globalThis.Response = Response; globalThis.Headers = Headers; }
内容的提问来源于stack exchange,提问作者SlugLord
相关产品推荐
相关产品推荐

