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

如何用Jest测试React组件内部定义的onClick事件?

如何测试React组件内部定义的onClick事件?

我找到了很多在Jest中模拟监视传递给组件的回调函数的方法,但找不到测试组件内部定义的简单onClick事件的方案。

示例页面代码

const ExamplePage: NextPage = () => {
    const router = useRouter();
    const onClick = (): Promise<void> => {
        axios.post(`/api/track`, {
            eventName: Event.TRACK_CLICK,
        });
        router.push("/new-route");
        return Promise.resolve();
    };

    return (
        <Container data-testid="container">
            <Title>Example Title</Title>
            <CreateButton data-testid="create-button" onClick={onClick}>
                Create Partner
            </CreateButton>
        </Container>
    );
};

export default ExamplePage;

我尝试的测试代码(失败)

import { fireEvent, render } from "../../../../test/customRenderer";
import ExamplePage from "../../../pages/example-page";

describe("Example page", () => {
    it("has a button to create", () => {
        const { getByTestId } = render(<ExamplePage />);

        const createButton = getByTestId("create-button");

        expect(createButton).toBeInTheDocument();
    });

    it(" the button's OnClick function should be executed when clicked", () => {
        const { getByTestId } = render(<ExamplePage />);
        // find the button
        const createButton = getByTestId("create-button");
        // check the button has onClick
        expect(createButton).toHaveAttribute("onClick");
        // get the onClick function
        const onClick = createButton.getAttribute("onClick");
        fireEvent.click(createButton);
        // check if the button's onClick function has been executed
        expect(onClick).toHaveBeenCalled();
    });
});

上面的测试失败了,因为通过getAttribute获取到的onClick属性值是null。我的思路是获取按钮上的函数并检查它是否被调用,但这个方法行不通。


解决方案

核心思路:测试函数的副作用,而非函数本身

React不会将组件内部定义的函数暴露为DOM元素的属性,所以你没法通过DOM节点直接拿到onClick函数并断言它是否被调用。正确的做法是测试点击按钮后产生的实际业务效果——也就是onClick函数执行时触发的副作用,比如API请求、路由跳转、状态变更等。

具体实现:模拟依赖并验证调用

我们需要把组件依赖的axios和useRouter模拟掉,通过验证这些依赖是否被正确调用,来间接证明onClick函数执行了预期逻辑。

修改后的测试代码如下:

import { fireEvent, render } from "../../../../test/customRenderer";
import ExamplePage from "../../../pages/example-page";
import axios from "axios";
import { useRouter } from "next/router";
import { Event } from "./path-to-event-constants"; // 导入你的Event常量

// 全局模拟axios和next/router
jest.mock("axios");
jest.mock("next/router", () => ({
  useRouter: jest.fn(),
}));

describe("Example page", () => {
  beforeEach(() => {
    // 每次测试前重置模拟函数,避免测试间的污染
    (axios.post as jest.Mock).mockClear();
    
    // 模拟router.push方法
    const mockPush = jest.fn();
    (useRouter as jest.Mock).mockReturnValue({
      push: mockPush,
    });
  });

  it("点击按钮后会发送追踪请求并跳转到指定路由", () => {
    const { getByTestId } = render(<ExamplePage />);
    const createButton = getByTestId("create-button");

    // 触发按钮点击
    fireEvent.click(createButton);

    // 验证axios是否发送了正确的POST请求
    expect(axios.post).toHaveBeenCalledWith("/api/track", {
      eventName: Event.TRACK_CLICK,
    });

    // 验证路由跳转是否被触发
    const router = useRouter() as ReturnType<typeof useRouter>;
    expect(router.push).toHaveBeenCalledWith("/new-route");
  });
});

补充说明

  • 如果你的onClick函数包含状态更新逻辑(比如修改组件内的useState值),可以通过查询组件渲染后的UI变化来验证(比如检查某个元素是否显示、文本是否更新等)。
  • 这种测试方式更贴近用户实际使用场景,我们不需要关心函数内部的实现细节,只需要确保功能符合预期即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:45:49