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

React Testing Library中点击NavLink时fireEvent.click()未触发history.push()

解决React NavLink点击测试中history.push未触发的问题

核心问题分析

  1. React Router v6+ API变更:MemoryRouter不再支持传入自定义history实例,直接传入会被忽略,导致你mock的history.push永远不会被调用。
  2. 错误的handleClick mock方式:直接给DOM元素赋值card.handleClick = jest.fn()无效,React组件的点击处理函数是内部绑定的,并非DOM元素的属性。
  3. 事件触发的合理性:仅添加bubbles: true不足以模拟真实用户交互,且路由跳转可能存在异步逻辑,需要等待断言。

修复后的测试代码

import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { Router } from "react-router-dom"; // 替换为Router组件
import { createMemoryHistory } from 'history';
import Card from "./Card";
// 推荐用userEvent模拟真实用户行为
import userEvent from '@testing-library/user-event';

test('点击卡片跳转到newgame/gameName路由', async () => {
    const history = createMemoryHistory();
    // 对history.push进行mock
    const mockPush = jest.spyOn(history, 'push').mockImplementation(() => {});

    // 使用Router组件传入自定义history实例
    render(
        <Router location={history.location} navigator={history}>
            <Card element={{name: "3ts", title: "3Ts", description: "Tic Tac Toe"}}/>
        </Router>
    );

    const cardLink = await screen.findByTestId('card-link');
    expect(cardLink).toHaveAttribute('href', '/newGame/3ts');

    // 模拟真实用户点击
    await userEvent.click(cardLink);

    // 等待异步路由跳转完成后断言
    await waitFor(() => {
        expect(mockPush).toHaveBeenCalledWith('/newGame/3ts');
    });
});

额外说明

  • 如果Card组件有自定义handleClick逻辑:
    • 若handleClick是组件props,渲染时直接传入mock函数:const mockHandleClick = jest.fn(); render(<Card handleClick={mockHandleClick} ... />)
    • 若为组件私有函数,应通过断言其产生的副作用(如状态变化、API调用)来测试,而非直接mock私有函数。
  • userEvent比fireEvent更贴近真实用户交互,会触发mouseDown、mouseUp、click等一系列完整事件链,测试稳定性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:05:56