如何在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
相关产品推荐
相关产品推荐

