如何使用React Testing Library正确测试经React Router传参的EditPage组件
测试方案说明
前置准备
首先你需要做两个核心模拟:
- 模拟
axios库,拦截请求避免调用真实接口,同时可以验证请求参数 - 给组件传递正确的路由参数,保证
useParams可以拿到初始的用户数据
注意请将测试代码里的路由path替换为你项目中实际配置的EditPage访问路径
完整测试代码
import { render, screen, fireEvent } from '@testing-library/react'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; import axios from 'axios'; import EditPage from './EditPage'; // 全局模拟axios jest.mock('axios'); // 模拟的初始用户参数 const mockUserParams = { id: '123', name: '初始姓名', email: 'initial@test.com', status: 'active' }; const setup = () => { render( <MemoryRouter initialEntries={[`/edit/${mockUserParams.id}/${mockUserParams.name}/${mockUserParams.email}/${mockUserParams.status}`]}> <Routes> <Route path="/edit/:id/:name/:email/:status" element={<EditPage />} /> {/* 模拟跳转目标路由 */} <Route path="/users" element={<div>用户列表页</div>} /> </Routes> </MemoryRouter> ); // 清空之前的调用记录,避免测试用例互相影响 axios.put.mockClear(); }; describe("edit page", () => { test("renders properly with initial user data", () => { setup(); expect(screen.getByTestId("editpage-title")).toBeInTheDocument(); expect(screen.getByTestId("editpage-inputs")).toBeInTheDocument(); expect(screen.getByTestId("editpage-buttons")).toBeInTheDocument(); // 验证初始值正确填充 expect(screen.getByPlaceholderText("Insert the name...")).toHaveValue(mockUserParams.name); expect(screen.getByPlaceholderText("Insert the email...")).toHaveValue(mockUserParams.email); expect(screen.getByRole('combobox')).toHaveValue(mockUserParams.status); }); test("changing values of inputs works correctly", () => { setup(); const nameInput = screen.getByPlaceholderText("Insert the name..."); const emailInput = screen.getByPlaceholderText("Insert the email..."); const statusSelect = screen.getByRole('combobox'); fireEvent.change(nameInput, { target: { value: "测试姓名" } }); fireEvent.change(emailInput, { target: { value: "test@test.com" } }); fireEvent.change(statusSelect, { target: { value: "inactive" } }); expect(nameInput).toHaveValue("测试姓名"); expect(emailInput).toHaveValue("test@test.com"); expect(statusSelect).toHaveValue("inactive"); }); test("click UPDATE button sends correct put request and jumps to user list", async () => { setup(); const nameInput = screen.getByPlaceholderText("Insert the name..."); const emailInput = screen.getByPlaceholderText("Insert the email..."); const statusSelect = screen.getByRole('combobox'); const updateBtn = screen.getByTestId("editpage-updatebutton"); // 修改输入值 fireEvent.change(nameInput, { target: { value: "测试姓名" } }); fireEvent.change(emailInput, { target: { value: "test@test.com" } }); fireEvent.change(statusSelect, { target: { value: "inactive" } }); // 点击更新按钮 fireEvent.click(updateBtn); // 验证axios.put被正确调用 expect(axios.put).toHaveBeenCalledTimes(1); expect(axios.put).toHaveBeenCalledWith( `https://gorest.co.in/public/v1/users/${mockUserParams.id}`, { name: "测试姓名", email: "test@test.com", status: "inactive" }, expect.objectContaining({ headers: expect.objectContaining({ Authorization: expect.stringContaining("Bearer ") }) }) ); // 验证跳转到用户列表页 expect(await screen.findByText("用户列表页")).toBeInTheDocument(); }); test("click CANCEL button does not send request and jumps to user list", async () => { setup(); const cancelBtn = screen.getByText("CANCEL"); // 点击取消按钮 fireEvent.click(cancelBtn); // 验证没有发送更新请求 expect(axios.put).not.toHaveBeenCalled(); // 验证跳转到用户列表页 expect(await screen.findByText("用户列表页")).toBeInTheDocument(); }); });
关键逻辑说明
- 用
MemoryRouter配置初始路由参数,模拟真实的跳转场景,保证useParams能拿到正确的初始用户数据 - 全局模拟
axios后,通过mockClear清空每次测试的调用记录,避免用例互相干扰 - 更新按钮的测试中,验证
axios.put的调用参数、请求地址、请求头是否符合预期,就能确认数据是否正确提交 - 取消按钮的测试中,验证
axios.put没有被调用,就能确认没有触发数据更新逻辑 - 最后通过查找跳转后的页面内容,验证路由跳转逻辑正常
内容的提问来源于stack exchange,提问作者ahmedskulj10
相关产品推荐
相关产品推荐

