You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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时除了路由路径还传递了一个配置对象,导致断言不匹配。

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点击时会自动传入默认配置对象,导致你的断言只匹配第一个参数时失败。

有两种修复方式:

  1. 忽略第二个参数,仅验证路径
    使用expect.anything()匹配任意类型的第二个参数,无需关心默认配置的具体内容:

    expect(mockedNavigation).toHaveBeenCalledWith("about", expect.anything());
    
  2. 精确匹配完整参数
    如果需要严格验证配置对象,可以直接断言完整的参数组合:

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 06:26:36