React-router-dom按钮点击导航测试失败问题求助
问题描述
我用React Router实现了页面跳转功能,点击按钮可导航至/creation页面,组件代码如下:
export const Index = () => { return ( <Box> <h1>Some title</h1> <Button component={Link} to={'/creation'}>Créer</Button> </Box> ) }
但编写测试用例验证导航行为时失败了,测试代码如下:
it("Should navigate to page 2 on button click", async() => { render(<Index />, {wrapper: BrowserRouter}) const user = userEvent.setup() expect(screen.getByText(/Créer/i)).toBeInTheDocument() // 这一步正常 await user.click(screen.getByText(/Créer/i)) expect(screen.getByText(/Page 2/i)).toBeInTheDocument() // 这一步失败 })
补充:该功能在生产环境可以正常使用,请问怎么解决测试失败的问题?
解决方案
测试失败的核心原因是:你只给Index组件套了BrowserRouter,但没有定义/creation路由对应的页面组件,React Router无法匹配路由并渲染目标页面。以下是几种解决方式:
1. 配置完整的路由规则
在测试中完整配置路由表,把Index和目标页面都注册到路由里,这样点击跳转后React Router能正确渲染目标页面:
import { Index } from './Index'; import { CreationPage } from './CreationPage'; // 导入你的目标页面组件 import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; it("Should navigate to page 2 on button click", async() => { render( <BrowserRouter> <Routes> <Route path="/" element={<Index />} /> <Route path="/creation" element={<CreationPage />} /> </Routes> </BrowserRouter> ); const user = userEvent.setup(); expect(screen.getByText(/Créer/i)).toBeInTheDocument(); await user.click(screen.getByText(/Créer/i)); // 用waitFor等待异步渲染完成 await waitFor(() => { expect(screen.getByText(/Page 2/i)).toBeInTheDocument(); }); });
2. 用waitFor处理异步渲染
路由跳转和组件渲染是异步过程,直接断言可能会因为目标组件还没渲染好而失败,用waitFor包裹断言,确保等待元素出现后再验证。
3. 可选:改用MemoryRouter优化测试
MemoryRouter是React Router专为测试设计的组件,它在内存中管理路由状态,不依赖浏览器的history对象,测试更稳定:
import { MemoryRouter, Routes, Route } from 'react-router-dom'; // 替换BrowserRouter为MemoryRouter,initialEntries设置初始路由 render( <MemoryRouter initialEntries={['/']}> <Routes> <Route path="/" element={<Index />} /> <Route path="/creation" element={<CreationPage />} /> </Routes> </MemoryRouter> );
4. 另一种思路:验证导航函数调用
如果不想渲染完整的目标页面,可以通过监听useNavigate的调用情况来验证导航行为,这种方式更轻量化:
import { useNavigate } from 'react-router-dom'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Index } from './Index'; // Mock useNavigate jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: jest.fn(), })); it("Should navigate to /creation when button is clicked", async() => { const mockNavigate = jest.fn(); (useNavigate as jest.Mock).mockReturnValue(mockNavigate); render(<Index />, {wrapper: BrowserRouter}); const user = userEvent.setup(); await user.click(screen.getByText(/Créer/i)); // 验证导航函数是否被调用,参数是否正确 expect(mockNavigate).toHaveBeenCalledWith('/creation'); });
内容的提问来源于stack exchange,提问作者Antoine Grenard
相关产品推荐
相关产品推荐

