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

React单元测试中如何监视useNavigate?遇重定义错误求解决

问题原因

react-router-dom 导出的 useNavigate 是一个不可配置的属性(内部用 Object.defineProperty 定义时设置了 configurable: false),而 jest.spyOn 的工作原理是尝试重新定义这个属性来替换成 mock 函数,由于属性不可配置,所以会抛出 Cannot redefine property 的错误。

解决方案

不要用 jest.spyOn,直接通过 jest.mock 来模拟 useNavigate,同时保留 react-router-dom 的其他原有功能:

import { useNavigate } from 'react-router-dom';
// 模拟react-router-dom,只替换useNavigate为mock函数
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'), // 继承原模块的其他导出
  useNavigate: jest.fn(),
}));
完整测试示例

假设你要测试的组件包含一个点击后跳转的按钮,测试代码可以这样写:

import { render, screen, fireEvent } from '@testing-library/react';
import { useNavigate } from 'react-router-dom';
import TargetComponent from './TargetComponent';

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useNavigate: jest.fn(),
}));

test('点击按钮后正确调用useNavigate并传入目标路径', () => {
  // 渲染组件
  render(<TargetComponent />);
  
  // 触发按钮点击
  fireEvent.click(screen.getByRole('button', { name: '跳转' }));
  
  // 验证调用次数和参数
  expect(useNavigate).toHaveBeenCalledTimes(1);
  expect(useNavigate).toHaveBeenCalledWith('/expected-path');
});
注意事项
  • 必须使用 ...jest.requireActual('react-router-dom'),否则其他如 useParams、Link 等 react-router-dom 的功能会被完全模拟,导致测试时无法正常使用。
  • 如果你的测试不需要其他 react-router-dom 的功能,也可以直接模拟整个模块而不继承原有导出,但这种场景较少。

内容的提问来源于stack exchange,提问作者ptjr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:31:36