在玩笑中模拟地图框点击处理程序回调

问题描述 投票:0回答:1

假设我有一张 Mapbox 地图。 Mapbox 地图有一个 onclick 处理程序,在 onclick 处理程序的回调中,调用了一个函数:

import { Map } from 'mapbox-gl'

const map = new Map({
  container: someContainer,
  center, 
  zoom
})

map.on('click', e => {
  const { lng, lat } = e.lngLat
  runSomeFunction(lat, lng).   // <---- i want to test this function
})

我想用玩笑来测试我的地图。围绕这样一个事实已经存在很多问题:mapbox-gl 在浏览器环境之外很难 失败。虽然有些人试图找到解决方法(修复

window.URL. createObjectURL
问题,使用已失效的mapbox-gl-js-mock存储库,克服开玩笑环境中缺乏GL的问题),但我一直在努力在那个兔子洞里呆了大约两天。是时候采取另一种方法了。

很多人都在谈论模拟地图框,就像这样:

jest.mock('mapbox-gl', () => ({
  Map: jest.fn(() => ({
    on: jest.fn(),
    otherMethods: jest.fn(),
  })),
}));

我可以使用这个方法并让我的测试通过。但我无法真正测试任何有趣的行为。如何模拟用户点击地图的行为,并测试我是否

expect(runSomeFunction).toHaveBeenCalledWith(whatever)

我真的不知道从哪里开始,因为我找不到实际测试地图行为或事件的笑话单元测试的单个示例。为了找到类似的东西,我还研究了如何在玩笑中测试传单地图事件,但我没有发现任何有用的东西。

javascript unit-testing jestjs mapbox mapbox-gl
1个回答
0
投票

我看到问题的两个部分:

  • 测试
    runSomeFunction()
  • 测试地图是否正确处理点击事件

对我来说,点击处理程序是匿名函数:

(e) => {
  const { lng, lat } = e.lngLat;
  runSomeFunction(lat, lng);
}

runSomeFunction()
可以通过单元测试单独进行测试。

点击处理程序可以通过单元测试单独进行测试 如果它被提取到命名函数。

还可以通过触发单击事件来测试单击处理程序 确认它调用了一个嘲笑的

runSomeFunction()
使用正确的参数,或确认单击的最终结果。我 会称这些为 集成测试而不是单元测试,因为它们不测试 隔离的单击处理程序。我喜欢 这种整合与 单元 测试

MapBox 拥有 关于真实自动化测试的资源 浏览器

开玩笑

这是一个基本的

Map
玩笑模拟,用于处理事件
mapbox-gl
3.1.2

测试环境是带有 babel 编译的 jsdom,根据 jest 文档设置。

// tests/__mocks__/mapbox-gl.js

import EventEmitter from 'events';
import { TextDecoder } from 'util';

// Add `TextDecoder` to globals.
globalThis.TextDecoder = TextDecoder;

const mapboxActual = jest.requireActual('mapbox-gl');

/**
 * Mock Map class.
 *
 * Extends the `EventEmitter` class and adds mock properties & methods.
 *
 * The real `Map` extends `Evented`, but `Evented.fire()` is now private
 * and may be deprecated in the future.
 *
 * @see https://nodejs.org/api/events.html#class-eventemitter
 * @see https://github.com/mapbox/mapbox-gl-js/blob/main/CHANGELOG.md#%EF%B8%8F-breaking-changes-5
 */
class MockMap extends EventEmitter {
  // ... Put mock properties & methods here.
}

mapboxActual.Map = MockMap;

export default mapboxActual;

使用它

这是一个测试

runSomeFunction()
的简单示例 跟踪间谍,只是因为我不知道更好的确认方法
console.log()
被正确调用。在真实的应用程序中,如果
runSomeFunction()
渲染一些东西,你可以测试它是否出现在 屏幕如预期。

// runSomeFunction.js

export default function runSomeFunction(lat, lng) {
  console.log(`Map clicked at ${lat}, ${lng}.`);
}
// map.js

import mapboxgl from 'mapbox-gl';
import runSomeFunction from "./runSomeFunction";

// If you pull in `mapbox-gl` with an html `script` tag instead of
// importing it, you'll need to add `mapboxgl` to the globals for the
// test environment so that it's available here.

mapboxgl.accessToken = 'pk.eyJ1Ijoia2VudHIiLCJhIjoiY2tva3YxOWFzMDdpcDJvcno5ZjBzM3JvNCJ9.ZdH2WahCpmtdiLsNLWZNFQ';

const map = new mapboxgl.Map({
  container: 'map', // container ID
  center: [ -74.5, 40 ], // starting position [lng, lat]
  zoom: 9, // starting zoom
});

map.on('click', (e) => {
  const { lng, lat } = e.lngLat;
  runSomeFunction(lat, lng);
});

export default map;
// map.test.js

import map from './map';

jest.spyOn(console, 'log');

it('logs click on map', () => {

  const testLatLng = {
    lat: 39,
    lng: -74,
  };

  // Confirm `console.log` not called before event is fired.
  expect(console.log)
    .not
    .toBeCalled();

  // Emit click event.
  map.emit(
    'click',
    {
      lngLat: testLatLng,
    }
  );

  // Check result.
  // May need delay for async event.
  expect(console.log)
    .toBeCalledTimes(1);

  expect(console.log)
    .toBeCalledWith(`Map clicked at ${testLatLng.lat}, ${testLatLng.lng}.`);
});

mapbox-gl
通过
script
标签

如果您通过 html

mapbox-gl
标签而不是拉入
script
将其导入到
map.js
,这是设置全局的示例 测试。

// jest.config.js

/** @type {import('jest').Config} */
const config = {
  setupFiles: [
    '<rootDir>/tests/setupTests.js'
  ],
  testEnvironment: "jsdom",
};

module.exports = config;
// tests/setupTests.js

import mapboxgl from "mapbox-gl";

globalThis.mapboxgl = mapboxgl;
© www.soinside.com 2019 - 2024. All rights reserved.