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

Jest中mock的useHistory.push函数未被调用问题求助

问题:Jest中mock useHistory.push未被触发

我不是Jest mocking专家,尝试mock useHistory的push方法,但点击按钮后mock函数没被触发,求解决办法。

组件代码

const ReviseAction = ({ plans, template, coveragePercentage, territoryName, existingTemplateId, }) => { 
  const history = useHistory(); 
  const handleRevise = () => { 
    history.push({ 
      pathname: "/xxx", 
      state: { 
        plans: plans, 
        template: template, 
        coveragePercentage: coveragePercentage, 
        territoryName: territoryName, 
        existingTemplateId: existingTemplateId, 
      }, 
    }); 
  }; 
  return ( 
    <button data-testid="revise-button" onClick={handleRevise} key="revise-button" > 
      Revise 
    </button> 
  ); 
};

测试代码

import React from "react"; 
import { render, screen, fireEvent } from "@testing-library/react"; 
import ReviseAction from "./ReviseAction"; 
import { HashRouter as Router } from "react-router-dom"; 

describe("ReviseAction", () => { 
  jest.mock("react-router-dom"); 
  const pushMock = jest.fn(); 
  //reactRouterDom.useHistory = jest.fn().mockReturnValue({push: pushMock}); 
  jest.mock("react-router-dom", () => ({ 
    ...jest.requireActual("react-router-dom"), 
    useHistory: () => ({ push: jest.fn() }) 
  })); 

  it("Renders component", async () => { 
    render( 
      <Router> 
        <ReviseAction plans={[]} template={{}} coveragePercentage="12" territoryName="Name" existingTemplateId="1234" /> 
      </Router> 
    ); 
    fireEvent.click(screen.queryByTestId("revise-button")); 
    expect(pushMock).toHaveBeenCalled(); 
  }); 
});

报错信息

Expected number of calls: >= 1
Received number of calls: 0


解决办法

问题根源

你定义的pushMock和mockuseHistory返回的push不是同一个函数:测试里写了两次jest.mock调用,第二个mock覆盖了第一个,且内部用了全新的jest.fn(),和你提前定义的pushMock完全无关。

修正后的测试代码

import React from "react"; 
import { render, screen, fireEvent } from "@testing-library/react"; 
import ReviseAction from "./ReviseAction"; 
import { HashRouter as Router, useHistory } from "react-router-dom"; 

// 提前mock react-router-dom,确保组件导入时就使用mock版本
jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useHistory: jest.fn()
}));

describe("ReviseAction", () => { 
  const pushMock = jest.fn(); 

  beforeEach(() => {
    // 每次测试前重置mock,避免测试用例间的调用记录污染
    pushMock.mockClear();
    // 将pushMock关联到useHistory的返回值
    useHistory.mockReturnValue({ push: pushMock });
  });

  it("点击按钮触发history.push", () => { 
    render( 
      <Router> 
        <ReviseAction plans={[]} template={{}} coveragePercentage="12" territoryName="Name" existingTemplateId="1234" /> 
      </Router> 
    ); 
    // 用getByTestId替代queryByTestId,找不到元素时直接报错,更容易定位问题
    fireEvent.click(screen.getByTestId("revise-button")); 
    // 可选:验证push的调用参数是否符合预期
    expect(pushMock).toHaveBeenCalledWith({
      pathname: "/xxx",
      state: {
        plans: [],
        template: {},
        coveragePercentage: "12",
        territoryName: "Name",
        existingTemplateId: "1234"
      }
    });
  }); 
});

额外优化说明

  • 使用getByTestId替代queryByTestId:前者找不到元素会直接抛出错误,避免因元素未渲染导致的无意义测试通过
  • 每次测试前重置mock:确保不同测试用例的调用记录互不干扰
  • 验证push的调用参数:让测试更严谨,确保跳转逻辑完全符合预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:50:49