React中NavLink导航的单元测试问题排查
我正在使用React v18.2.0和React Testing Library v5.17.0,尝试对导航栏中的NavLink进行单元测试,但测试失败,错误信息如下:
Expected: "about" Received: "about", {"preventScrollReset": undefined, "relative": undefined, "replace": false, "state": undefined, "unstable_viewTransition": undefined}
可见调用navigate时除了路由路径还传递了一个配置对象,导致断言不匹配。
NavBar组件代码
const NavBar = () => { return ( <> <div className="navbar"> <ul> <li> <NavLink to="home" className="navlink">Home</NavLink> </li> <li> <NavLink to="about" className="navlink">About</NavLink> </li> </ul> </div> </> ); }; export default Navbar;
原单元测试代码
import { render, fireEvent } from "@testing-library/react"; import NavBar from './NavBar'; import * as router from 'react-router'; import { BrowserRouter as Router } from 'react-router-dom'; describe(NavBar, () => { const mockedNavigation = jest.fn(); const MockedNav = () => { return( <Router> <Navbar /> </Router> ) } beforeEach(() => { jest.spyOn(router, 'useNavigate').mockImplementation(() => mockedNavigation) }) it('should navigate to the about page', () => { const { getByText } = render(<MockedNav />); fireEvent.click(getByText(/About/i)); expect(mockedNavigation).toHaveBeenCalledWith("about"); }); })
问题解决
React Router v6中,navigate函数支持接收两个参数:第一个是目标路径,第二个是可选的配置对象(包含replace、state等属性)。NavLink点击时会自动传入默认配置对象,导致你的断言只匹配第一个参数时失败。
有两种修复方式:
忽略第二个参数,仅验证路径
使用expect.anything()匹配任意类型的第二个参数,无需关心默认配置的具体内容:expect(mockedNavigation).toHaveBeenCalledWith("about", expect.anything());精确匹配完整参数
如果需要严格验证配置对象,可以直接断言完整的参数组合:expect(mockedNavigation).toHaveBeenCalledWith( "about", { preventScrollReset: undefined, relative: undefined, replace: false, state: undefined, unstable_viewTransition: undefined } );
另外注意原测试代码中的小问题:组件导入的是NavBar,但渲染时写成了Navbar(大小写不一致),需要修正为<NavBar />才能正常运行。
修正后的测试代码示例:
import { render, fireEvent } from "@testing-library/react"; import NavBar from './NavBar'; import * as router from 'react-router'; import { BrowserRouter as Router } from 'react-router-dom'; describe('NavBar', () => { const mockedNavigation = jest.fn(); const MockedNav = () => { return( <Router> <NavBar /> {/* 修正组件名称大小写 */} </Router> ) } beforeEach(() => { jest.spyOn(router, 'useNavigate').mockImplementation(() => mockedNavigation) }) it('should navigate to the about page', () => { const { getByText } = render(<MockedNav />); fireEvent.click(getByText(/About/i)); expect(mockedNavigation).toHaveBeenCalledWith("about", expect.anything()); }); })
内容的提问来源于stack exchange,提问作者Scottish Smile
相关产品推荐
相关产品推荐

