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

如何在Jest中模拟React Leaflet地图事件完成测试覆盖

Jest覆盖Leaflet定位点击逻辑方案

原代码问题修正

你贴的代码存在几处语法/API笔误,先修正为可运行版本,否则无法正常执行也无法通过单测覆盖:

const map = useMap();

const locationClick = (): void => {
  map.locate().on("locationfound", function (e) {
    setP(e.latlng);
    map.flyTo(e.latlng, 10.3);
    const radius = e.accuracy;
    map.setZoom(14.3);
    const circle = L.circle(e.latlng, radius);
    circle.addTo(map);
  });
};

修正点:补全缺失的赋值等号、修正Leaflet API驼峰命名(setzoom→setZoom)、修正坐标属性名笔误(lating→latlng)、修正Leaflet原生定位成功事件名(带空格的location found→无空格locationfound,如果你用的是自定义事件可保留原命名)。

单测实现思路

这类依赖第三方地图实例的逻辑,不需要真实加载Leaflet地图,通过mock所有依赖的实例方法,手动触发事件回调即可覆盖所有分支:

  • mock react-leaflet的useMap钩子,返回带所有mock方法的模拟map实例
  • mock Leaflet根对象的circle方法,返回带addTomock方法的模拟圆形实例
  • 触发组件上绑定locationClick的交互后,手动取出绑定的定位成功事件回调,传入模拟定位参数执行
  • 断言所有内部方法都按预期被调用,即可完成100%覆盖率

完整测试代码示例

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TargetComponent from './TargetComponent'; // 替换为你的组件实际路径
import { useMap } from 'react-leaflet';
import L from 'leaflet';

// 声明依赖mock
jest.mock('react-leaflet');
jest.mock('leaflet');

describe('定位点击逻辑测试', () => {
  // 提前定义所有mock方法
  const mockMapOn = jest.fn();
  const mockMapLocate = jest.fn(() => ({ on: mockMapOn }));
  const mockMapFlyTo = jest.fn();
  const mockMapSetZoom = jest.fn();
  const mockCircleAddTo = jest.fn();
  const mockMapInstance = {
    locate: mockMapLocate,
    flyTo: mockMapFlyTo,
    setZoom: mockMapSetZoom
  };

  beforeEach(() => {
    // 每个用例执行前重置mock状态
    jest.clearAllMocks();
    (useMap as jest.Mock).mockReturnValue(mockMapInstance);
    (L.circle as jest.Mock).mockReturnValue({ addTo: mockCircleAddTo });
  });

  it('定位成功后所有逻辑正常执行', async () => {
    const user = userEvent.setup();
    // 渲染待测组件,假设组件内绑定locationClick的是文本为「定位」的按钮
    render(<TargetComponent />);
    // 触发点击,执行locationClick逻辑
    await user.click(screen.getByRole('button', { name: '定位' }));

    // 校验定位方法、事件绑定逻辑执行
    expect(mockMapLocate).toHaveBeenCalledTimes(1);
    expect(mockMapOn).toHaveBeenCalledWith('locationfound', expect.any(Function));

    // 手动触发定位成功回调,模拟定位返回数据
    const locationSuccessCb = mockMapOn.mock.calls[0][1];
    const mockLocationEvent = {
      latlng: { lat: 30.27, lng: 120.15 },
      accuracy: 80
    };
    locationSuccessCb(mockLocationEvent);

    // 校验回调内所有逻辑执行
    expect(mockMapFlyTo).toHaveBeenCalledWith(mockLocationEvent.latlng, 10.3);
    expect(mockMapSetZoom).toHaveBeenCalledWith(14.3);
    expect(L.circle).toHaveBeenCalledWith(mockLocationEvent.latlng, mockLocationEvent.accuracy);
    expect(mockCircleAddTo).toHaveBeenCalledWith(mockMapInstance);
  });
});

适配说明

  • 如果你保留了原代码里带空格的location found事件名、lating/setzoom等自定义命名,把测试代码里对应的字段替换为和你业务代码一致的值即可
  • 如果setP是组件内部useState返回的状态更新方法,不需要额外mock,事件回调执行时会自动调用,覆盖率会自动统计;如果是外部传入的props方法,在mock组件props时传入jest mock函数,再加一行调用断言即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:03:11