@trackunit/react-test-setup 1.8.60 → 1.8.62-alpha-c496ead6241.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +228 -0
- package/index.esm.js +226 -1
- package/package.json +5 -4
- package/preset.cjs.js +1 -1
- package/preset.esm.js +1 -1
- package/src/index.d.ts +1 -0
- package/src/setupAllMocks.d.ts +1 -0
- package/src/setupMapbox.d.ts +117 -0
package/index.cjs.js
CHANGED
|
@@ -125,8 +125,10 @@ const setupGoogleMaps = () => {
|
|
|
125
125
|
const InfoWindowMock = jest.fn(props => {
|
|
126
126
|
return jsxRuntime.jsx("div", { "data-testid": "google-info-window", children: props.children });
|
|
127
127
|
});
|
|
128
|
+
const APIProviderMock = jest.fn(props => jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.children }));
|
|
128
129
|
return {
|
|
129
130
|
...originalModule,
|
|
131
|
+
APIProvider: APIProviderMock,
|
|
130
132
|
useApiLoadingStatus: () => APILoadingStatus.LOADED,
|
|
131
133
|
useApiIsLoaded: () => true,
|
|
132
134
|
useMap: () => map,
|
|
@@ -219,6 +221,227 @@ class MockIntersectionObserver {
|
|
|
219
221
|
}
|
|
220
222
|
}
|
|
221
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Creates a new listener registry for tracking event subscriptions.
|
|
226
|
+
*/
|
|
227
|
+
const createListenerRegistry = () => ({
|
|
228
|
+
regular: new Map(),
|
|
229
|
+
once: new Map(),
|
|
230
|
+
});
|
|
231
|
+
/**
|
|
232
|
+
* Mock LngLat class matching Mapbox GL's interface.
|
|
233
|
+
* Returns actual objects with lng/lat properties rather than class instances.
|
|
234
|
+
*/
|
|
235
|
+
const createMockLngLat = (lng, lat) => ({
|
|
236
|
+
lng,
|
|
237
|
+
lat,
|
|
238
|
+
wrap: () => createMockLngLat(lng, lat),
|
|
239
|
+
toArray: () => [lng, lat],
|
|
240
|
+
distanceTo: () => 0,
|
|
241
|
+
toBounds: () => createMockLngLatBounds(lng - 1, lat - 1, lng + 1, lat + 1),
|
|
242
|
+
toString: () => `LngLat(${lng}, ${lat})`,
|
|
243
|
+
toEcef: () => [0, 0, 0],
|
|
244
|
+
});
|
|
245
|
+
/**
|
|
246
|
+
* Mock LngLatBounds matching Mapbox GL's interface.
|
|
247
|
+
*/
|
|
248
|
+
const createMockLngLatBounds = (west, south, east, north) => {
|
|
249
|
+
const sw = createMockLngLat(west, south);
|
|
250
|
+
const ne = createMockLngLat(east, north);
|
|
251
|
+
const bounds = {
|
|
252
|
+
_sw: sw,
|
|
253
|
+
_ne: ne,
|
|
254
|
+
getSouthWest: () => sw,
|
|
255
|
+
getNorthEast: () => ne,
|
|
256
|
+
getNorthWest: () => createMockLngLat(west, north),
|
|
257
|
+
getSouthEast: () => createMockLngLat(east, south),
|
|
258
|
+
getWest: () => west,
|
|
259
|
+
getSouth: () => south,
|
|
260
|
+
getEast: () => east,
|
|
261
|
+
getNorth: () => north,
|
|
262
|
+
getCenter: () => createMockLngLat((west + east) / 2, (south + north) / 2),
|
|
263
|
+
toArray: () => [
|
|
264
|
+
[west, south],
|
|
265
|
+
[east, north],
|
|
266
|
+
],
|
|
267
|
+
toString: () => `LngLatBounds(${sw.toString()}, ${ne.toString()})`,
|
|
268
|
+
isEmpty: () => false,
|
|
269
|
+
contains: () => true,
|
|
270
|
+
extend: () => bounds,
|
|
271
|
+
setNorthEast: () => bounds,
|
|
272
|
+
setSouthWest: () => bounds,
|
|
273
|
+
};
|
|
274
|
+
return bounds;
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* Creates a mock Mapbox map instance for unit testing adapter instances directly.
|
|
278
|
+
*
|
|
279
|
+
* Use this when you need fine-grained control over mock behavior, such as:
|
|
280
|
+
* - Testing adapter instance methods (connect, setCenter, etc.)
|
|
281
|
+
* - Simulating map events (idle, click, movestart)
|
|
282
|
+
* - Verifying method calls on the map
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```typescript
|
|
286
|
+
* import { createMockMapboxMap } from "@trackunit/react-test-setup";
|
|
287
|
+
*
|
|
288
|
+
* it("should connect to map", () => {
|
|
289
|
+
* const { map, triggerEvent } = createMockMapboxMap();
|
|
290
|
+
* const adapter = new MapboxAdapterInstance(config);
|
|
291
|
+
*
|
|
292
|
+
* adapter.connect(map as unknown as mapboxgl.Map);
|
|
293
|
+
* triggerEvent("idle");
|
|
294
|
+
*
|
|
295
|
+
* expect(adapter.getState().isReady).toBe(true);
|
|
296
|
+
* });
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
const createMockMapboxMap = () => {
|
|
300
|
+
const registry = createListenerRegistry();
|
|
301
|
+
const addListener = (store, event, handler) => {
|
|
302
|
+
const handlers = store.get(event);
|
|
303
|
+
if (handlers === undefined) {
|
|
304
|
+
store.set(event, new Set([handler]));
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
handlers.add(handler);
|
|
308
|
+
}
|
|
309
|
+
return map;
|
|
310
|
+
};
|
|
311
|
+
const map = {
|
|
312
|
+
on: jest.fn((event, handler) => addListener(registry.regular, event, handler)),
|
|
313
|
+
once: jest.fn((event, handler) => addListener(registry.once, event, handler)),
|
|
314
|
+
off: jest.fn((event, handler) => {
|
|
315
|
+
registry.regular.get(event)?.delete(handler);
|
|
316
|
+
return map;
|
|
317
|
+
}),
|
|
318
|
+
remove: jest.fn(),
|
|
319
|
+
getCenter: jest.fn(() => createMockLngLat(0, 0)),
|
|
320
|
+
getZoom: jest.fn(() => 10),
|
|
321
|
+
getBounds: jest.fn(() => createMockLngLatBounds(-1, -1, 1, 1)),
|
|
322
|
+
setCenter: jest.fn((_center) => map),
|
|
323
|
+
setZoom: jest.fn((_zoom) => map),
|
|
324
|
+
panTo: jest.fn((_lngLat) => map),
|
|
325
|
+
panBy: jest.fn((_offset) => map),
|
|
326
|
+
fitBounds: jest.fn((_bounds, _options) => map),
|
|
327
|
+
setStyle: jest.fn((_style) => map),
|
|
328
|
+
isStyleLoaded: jest.fn(() => true),
|
|
329
|
+
isMoving: jest.fn(() => false),
|
|
330
|
+
addSource: jest.fn(),
|
|
331
|
+
removeSource: jest.fn(),
|
|
332
|
+
getSource: jest.fn(() => undefined),
|
|
333
|
+
addLayer: jest.fn(),
|
|
334
|
+
removeLayer: jest.fn(),
|
|
335
|
+
getLayer: jest.fn(() => undefined),
|
|
336
|
+
hasImage: jest.fn(() => false),
|
|
337
|
+
addImage: jest.fn(),
|
|
338
|
+
getCanvas: jest.fn(() => ({ style: {} })),
|
|
339
|
+
};
|
|
340
|
+
const triggerEvent = (eventName, event) => {
|
|
341
|
+
// Fire regular listeners
|
|
342
|
+
const regularHandlers = registry.regular.get(eventName);
|
|
343
|
+
if (regularHandlers !== undefined) {
|
|
344
|
+
regularHandlers.forEach((handler) => handler(event));
|
|
345
|
+
}
|
|
346
|
+
// Fire and clear once listeners
|
|
347
|
+
const onceHandlers = registry.once.get(eventName);
|
|
348
|
+
if (onceHandlers !== undefined) {
|
|
349
|
+
onceHandlers.forEach((handler) => handler(event));
|
|
350
|
+
registry.once.delete(eventName);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
return { map, triggerEvent };
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* Mock click event matching Mapbox GL's MapMouseEvent shape.
|
|
357
|
+
* Use with triggerEvent("click", createMockClickEvent(...))
|
|
358
|
+
*
|
|
359
|
+
* Note: The `point` property is intentionally omitted because:
|
|
360
|
+
* 1. It requires the full Point class from @mapbox/point-geometry with 30+ methods
|
|
361
|
+
* 2. No tests currently use the point property
|
|
362
|
+
* 3. Since this returns Partial<MapMouseEvent>, point is optional
|
|
363
|
+
*/
|
|
364
|
+
const createMockClickEvent = (lng, lat) => ({
|
|
365
|
+
lngLat: createMockLngLat(lng, lat),
|
|
366
|
+
originalEvent: new MouseEvent("click"),
|
|
367
|
+
type: "click",
|
|
368
|
+
});
|
|
369
|
+
/**
|
|
370
|
+
* Sets up mocks for Mapbox GL JS in testing environments.
|
|
371
|
+
*
|
|
372
|
+
* This function mocks the mapbox-gl module with functional mock implementations,
|
|
373
|
+
* allowing tests of map-dependent components to run without WebGL or actual
|
|
374
|
+
* network requests.
|
|
375
|
+
*
|
|
376
|
+
* Key features:
|
|
377
|
+
* - Mocks mapboxgl.Map constructor to return a trackable mock instance
|
|
378
|
+
* - Auto-fires the "load" event after map construction (for renderer tests)
|
|
379
|
+
* - Provides mock implementations for all common map methods
|
|
380
|
+
* - Resets mock state between tests via beforeEach
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```typescript
|
|
384
|
+
* // In your test file
|
|
385
|
+
* import { setupMapbox } from "@trackunit/react-test-setup";
|
|
386
|
+
*
|
|
387
|
+
* setupMapbox();
|
|
388
|
+
*
|
|
389
|
+
* describe("MapboxRenderer", () => {
|
|
390
|
+
* it("renders map when loaded", async () => {
|
|
391
|
+
* // The mock will auto-fire "load" event
|
|
392
|
+
* render(<MapboxRenderer adapterInstance={instance} />);
|
|
393
|
+
* await waitFor(() => expect(screen.getByRole("application")).toBeInTheDocument());
|
|
394
|
+
* });
|
|
395
|
+
* });
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
const setupMapbox = () => {
|
|
399
|
+
jest.mock("mapbox-gl", () => {
|
|
400
|
+
const createMockMapWithAutoLoad = () => {
|
|
401
|
+
const result = createMockMapboxMap();
|
|
402
|
+
// Override "on" to auto-fire "load" event for renderer compatibility
|
|
403
|
+
const originalOn = result.map.on;
|
|
404
|
+
result.map.on = jest.fn((event, handler) => {
|
|
405
|
+
originalOn(event, handler);
|
|
406
|
+
// Auto-fire load event asynchronously to simulate real Mapbox behavior
|
|
407
|
+
if (event === "load") {
|
|
408
|
+
setTimeout(() => handler(undefined), 0);
|
|
409
|
+
}
|
|
410
|
+
return result.map;
|
|
411
|
+
});
|
|
412
|
+
return result.map;
|
|
413
|
+
};
|
|
414
|
+
const createMockMarker = () => {
|
|
415
|
+
const el = document.createElement("div");
|
|
416
|
+
const marker = {
|
|
417
|
+
setLngLat: jest.fn(() => marker),
|
|
418
|
+
addTo: jest.fn(() => marker),
|
|
419
|
+
remove: jest.fn(),
|
|
420
|
+
getElement: jest.fn(() => el),
|
|
421
|
+
setOffset: jest.fn(() => marker),
|
|
422
|
+
getLngLat: jest.fn(() => createMockLngLat(0, 0)),
|
|
423
|
+
setPopup: jest.fn(() => marker),
|
|
424
|
+
getPopup: jest.fn(() => null),
|
|
425
|
+
togglePopup: jest.fn(() => marker),
|
|
426
|
+
setDraggable: jest.fn(() => marker),
|
|
427
|
+
isDraggable: jest.fn(() => false),
|
|
428
|
+
};
|
|
429
|
+
return marker;
|
|
430
|
+
};
|
|
431
|
+
return {
|
|
432
|
+
__esModule: true,
|
|
433
|
+
default: {
|
|
434
|
+
Map: jest.fn(createMockMapWithAutoLoad),
|
|
435
|
+
Marker: jest.fn(createMockMarker),
|
|
436
|
+
accessToken: "",
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
});
|
|
440
|
+
beforeEach(() => {
|
|
441
|
+
jest.clearAllMocks();
|
|
442
|
+
});
|
|
443
|
+
};
|
|
444
|
+
|
|
222
445
|
/**
|
|
223
446
|
* Mocks the window.matchMedia API for testing environments.
|
|
224
447
|
*
|
|
@@ -737,6 +960,7 @@ const setupWebStreams = () => {
|
|
|
737
960
|
* - Canvas API mocks
|
|
738
961
|
* - Console error reporting to fail tests (includes automatic CSS parser error suppression)
|
|
739
962
|
* - Google Maps API and components mocks
|
|
963
|
+
* - Mapbox GL JS mocks
|
|
740
964
|
* - React Helmet mocks
|
|
741
965
|
* - IntersectionObserver mocks
|
|
742
966
|
* - MatchMedia API mocks
|
|
@@ -767,6 +991,7 @@ const setupAllMocks = (options = {}) => {
|
|
|
767
991
|
setupCanvasMock();
|
|
768
992
|
setupFailOnConsole(options.failOnConsoleOptions);
|
|
769
993
|
setupGoogleMaps();
|
|
994
|
+
setupMapbox();
|
|
770
995
|
setupHelmetMock();
|
|
771
996
|
setupIntersectionObserver();
|
|
772
997
|
setupMatchMediaMock();
|
|
@@ -898,6 +1123,8 @@ const setupTanstackReactRouter = () => {
|
|
|
898
1123
|
}));
|
|
899
1124
|
};
|
|
900
1125
|
|
|
1126
|
+
exports.createMockClickEvent = createMockClickEvent;
|
|
1127
|
+
exports.createMockMapboxMap = createMockMapboxMap;
|
|
901
1128
|
exports.setupAllMocks = setupAllMocks;
|
|
902
1129
|
exports.setupBasicMocks = setupBasicMocks;
|
|
903
1130
|
exports.setupCanvasMock = setupCanvasMock;
|
|
@@ -906,6 +1133,7 @@ exports.setupFailOnConsole = setupFailOnConsole;
|
|
|
906
1133
|
exports.setupGoogleMaps = setupGoogleMaps;
|
|
907
1134
|
exports.setupHelmetMock = setupHelmetMock;
|
|
908
1135
|
exports.setupIntersectionObserver = setupIntersectionObserver;
|
|
1136
|
+
exports.setupMapbox = setupMapbox;
|
|
909
1137
|
exports.setupMatchMediaMock = setupMatchMediaMock;
|
|
910
1138
|
exports.setupReactTestingLibrary = setupReactTestingLibrary;
|
|
911
1139
|
exports.setupReactVirtualizedAutoSizer = setupReactVirtualizedAutoSizer;
|
package/index.esm.js
CHANGED
|
@@ -104,8 +104,10 @@ const setupGoogleMaps = () => {
|
|
|
104
104
|
const InfoWindowMock = jest.fn(props => {
|
|
105
105
|
return jsx("div", { "data-testid": "google-info-window", children: props.children });
|
|
106
106
|
});
|
|
107
|
+
const APIProviderMock = jest.fn(props => jsx(Fragment, { children: props.children }));
|
|
107
108
|
return {
|
|
108
109
|
...originalModule,
|
|
110
|
+
APIProvider: APIProviderMock,
|
|
109
111
|
useApiLoadingStatus: () => APILoadingStatus.LOADED,
|
|
110
112
|
useApiIsLoaded: () => true,
|
|
111
113
|
useMap: () => map,
|
|
@@ -198,6 +200,227 @@ class MockIntersectionObserver {
|
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Creates a new listener registry for tracking event subscriptions.
|
|
205
|
+
*/
|
|
206
|
+
const createListenerRegistry = () => ({
|
|
207
|
+
regular: new Map(),
|
|
208
|
+
once: new Map(),
|
|
209
|
+
});
|
|
210
|
+
/**
|
|
211
|
+
* Mock LngLat class matching Mapbox GL's interface.
|
|
212
|
+
* Returns actual objects with lng/lat properties rather than class instances.
|
|
213
|
+
*/
|
|
214
|
+
const createMockLngLat = (lng, lat) => ({
|
|
215
|
+
lng,
|
|
216
|
+
lat,
|
|
217
|
+
wrap: () => createMockLngLat(lng, lat),
|
|
218
|
+
toArray: () => [lng, lat],
|
|
219
|
+
distanceTo: () => 0,
|
|
220
|
+
toBounds: () => createMockLngLatBounds(lng - 1, lat - 1, lng + 1, lat + 1),
|
|
221
|
+
toString: () => `LngLat(${lng}, ${lat})`,
|
|
222
|
+
toEcef: () => [0, 0, 0],
|
|
223
|
+
});
|
|
224
|
+
/**
|
|
225
|
+
* Mock LngLatBounds matching Mapbox GL's interface.
|
|
226
|
+
*/
|
|
227
|
+
const createMockLngLatBounds = (west, south, east, north) => {
|
|
228
|
+
const sw = createMockLngLat(west, south);
|
|
229
|
+
const ne = createMockLngLat(east, north);
|
|
230
|
+
const bounds = {
|
|
231
|
+
_sw: sw,
|
|
232
|
+
_ne: ne,
|
|
233
|
+
getSouthWest: () => sw,
|
|
234
|
+
getNorthEast: () => ne,
|
|
235
|
+
getNorthWest: () => createMockLngLat(west, north),
|
|
236
|
+
getSouthEast: () => createMockLngLat(east, south),
|
|
237
|
+
getWest: () => west,
|
|
238
|
+
getSouth: () => south,
|
|
239
|
+
getEast: () => east,
|
|
240
|
+
getNorth: () => north,
|
|
241
|
+
getCenter: () => createMockLngLat((west + east) / 2, (south + north) / 2),
|
|
242
|
+
toArray: () => [
|
|
243
|
+
[west, south],
|
|
244
|
+
[east, north],
|
|
245
|
+
],
|
|
246
|
+
toString: () => `LngLatBounds(${sw.toString()}, ${ne.toString()})`,
|
|
247
|
+
isEmpty: () => false,
|
|
248
|
+
contains: () => true,
|
|
249
|
+
extend: () => bounds,
|
|
250
|
+
setNorthEast: () => bounds,
|
|
251
|
+
setSouthWest: () => bounds,
|
|
252
|
+
};
|
|
253
|
+
return bounds;
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Creates a mock Mapbox map instance for unit testing adapter instances directly.
|
|
257
|
+
*
|
|
258
|
+
* Use this when you need fine-grained control over mock behavior, such as:
|
|
259
|
+
* - Testing adapter instance methods (connect, setCenter, etc.)
|
|
260
|
+
* - Simulating map events (idle, click, movestart)
|
|
261
|
+
* - Verifying method calls on the map
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* import { createMockMapboxMap } from "@trackunit/react-test-setup";
|
|
266
|
+
*
|
|
267
|
+
* it("should connect to map", () => {
|
|
268
|
+
* const { map, triggerEvent } = createMockMapboxMap();
|
|
269
|
+
* const adapter = new MapboxAdapterInstance(config);
|
|
270
|
+
*
|
|
271
|
+
* adapter.connect(map as unknown as mapboxgl.Map);
|
|
272
|
+
* triggerEvent("idle");
|
|
273
|
+
*
|
|
274
|
+
* expect(adapter.getState().isReady).toBe(true);
|
|
275
|
+
* });
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
const createMockMapboxMap = () => {
|
|
279
|
+
const registry = createListenerRegistry();
|
|
280
|
+
const addListener = (store, event, handler) => {
|
|
281
|
+
const handlers = store.get(event);
|
|
282
|
+
if (handlers === undefined) {
|
|
283
|
+
store.set(event, new Set([handler]));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
handlers.add(handler);
|
|
287
|
+
}
|
|
288
|
+
return map;
|
|
289
|
+
};
|
|
290
|
+
const map = {
|
|
291
|
+
on: jest.fn((event, handler) => addListener(registry.regular, event, handler)),
|
|
292
|
+
once: jest.fn((event, handler) => addListener(registry.once, event, handler)),
|
|
293
|
+
off: jest.fn((event, handler) => {
|
|
294
|
+
registry.regular.get(event)?.delete(handler);
|
|
295
|
+
return map;
|
|
296
|
+
}),
|
|
297
|
+
remove: jest.fn(),
|
|
298
|
+
getCenter: jest.fn(() => createMockLngLat(0, 0)),
|
|
299
|
+
getZoom: jest.fn(() => 10),
|
|
300
|
+
getBounds: jest.fn(() => createMockLngLatBounds(-1, -1, 1, 1)),
|
|
301
|
+
setCenter: jest.fn((_center) => map),
|
|
302
|
+
setZoom: jest.fn((_zoom) => map),
|
|
303
|
+
panTo: jest.fn((_lngLat) => map),
|
|
304
|
+
panBy: jest.fn((_offset) => map),
|
|
305
|
+
fitBounds: jest.fn((_bounds, _options) => map),
|
|
306
|
+
setStyle: jest.fn((_style) => map),
|
|
307
|
+
isStyleLoaded: jest.fn(() => true),
|
|
308
|
+
isMoving: jest.fn(() => false),
|
|
309
|
+
addSource: jest.fn(),
|
|
310
|
+
removeSource: jest.fn(),
|
|
311
|
+
getSource: jest.fn(() => undefined),
|
|
312
|
+
addLayer: jest.fn(),
|
|
313
|
+
removeLayer: jest.fn(),
|
|
314
|
+
getLayer: jest.fn(() => undefined),
|
|
315
|
+
hasImage: jest.fn(() => false),
|
|
316
|
+
addImage: jest.fn(),
|
|
317
|
+
getCanvas: jest.fn(() => ({ style: {} })),
|
|
318
|
+
};
|
|
319
|
+
const triggerEvent = (eventName, event) => {
|
|
320
|
+
// Fire regular listeners
|
|
321
|
+
const regularHandlers = registry.regular.get(eventName);
|
|
322
|
+
if (regularHandlers !== undefined) {
|
|
323
|
+
regularHandlers.forEach((handler) => handler(event));
|
|
324
|
+
}
|
|
325
|
+
// Fire and clear once listeners
|
|
326
|
+
const onceHandlers = registry.once.get(eventName);
|
|
327
|
+
if (onceHandlers !== undefined) {
|
|
328
|
+
onceHandlers.forEach((handler) => handler(event));
|
|
329
|
+
registry.once.delete(eventName);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
return { map, triggerEvent };
|
|
333
|
+
};
|
|
334
|
+
/**
|
|
335
|
+
* Mock click event matching Mapbox GL's MapMouseEvent shape.
|
|
336
|
+
* Use with triggerEvent("click", createMockClickEvent(...))
|
|
337
|
+
*
|
|
338
|
+
* Note: The `point` property is intentionally omitted because:
|
|
339
|
+
* 1. It requires the full Point class from @mapbox/point-geometry with 30+ methods
|
|
340
|
+
* 2. No tests currently use the point property
|
|
341
|
+
* 3. Since this returns Partial<MapMouseEvent>, point is optional
|
|
342
|
+
*/
|
|
343
|
+
const createMockClickEvent = (lng, lat) => ({
|
|
344
|
+
lngLat: createMockLngLat(lng, lat),
|
|
345
|
+
originalEvent: new MouseEvent("click"),
|
|
346
|
+
type: "click",
|
|
347
|
+
});
|
|
348
|
+
/**
|
|
349
|
+
* Sets up mocks for Mapbox GL JS in testing environments.
|
|
350
|
+
*
|
|
351
|
+
* This function mocks the mapbox-gl module with functional mock implementations,
|
|
352
|
+
* allowing tests of map-dependent components to run without WebGL or actual
|
|
353
|
+
* network requests.
|
|
354
|
+
*
|
|
355
|
+
* Key features:
|
|
356
|
+
* - Mocks mapboxgl.Map constructor to return a trackable mock instance
|
|
357
|
+
* - Auto-fires the "load" event after map construction (for renderer tests)
|
|
358
|
+
* - Provides mock implementations for all common map methods
|
|
359
|
+
* - Resets mock state between tests via beforeEach
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```typescript
|
|
363
|
+
* // In your test file
|
|
364
|
+
* import { setupMapbox } from "@trackunit/react-test-setup";
|
|
365
|
+
*
|
|
366
|
+
* setupMapbox();
|
|
367
|
+
*
|
|
368
|
+
* describe("MapboxRenderer", () => {
|
|
369
|
+
* it("renders map when loaded", async () => {
|
|
370
|
+
* // The mock will auto-fire "load" event
|
|
371
|
+
* render(<MapboxRenderer adapterInstance={instance} />);
|
|
372
|
+
* await waitFor(() => expect(screen.getByRole("application")).toBeInTheDocument());
|
|
373
|
+
* });
|
|
374
|
+
* });
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
const setupMapbox = () => {
|
|
378
|
+
jest.mock("mapbox-gl", () => {
|
|
379
|
+
const createMockMapWithAutoLoad = () => {
|
|
380
|
+
const result = createMockMapboxMap();
|
|
381
|
+
// Override "on" to auto-fire "load" event for renderer compatibility
|
|
382
|
+
const originalOn = result.map.on;
|
|
383
|
+
result.map.on = jest.fn((event, handler) => {
|
|
384
|
+
originalOn(event, handler);
|
|
385
|
+
// Auto-fire load event asynchronously to simulate real Mapbox behavior
|
|
386
|
+
if (event === "load") {
|
|
387
|
+
setTimeout(() => handler(undefined), 0);
|
|
388
|
+
}
|
|
389
|
+
return result.map;
|
|
390
|
+
});
|
|
391
|
+
return result.map;
|
|
392
|
+
};
|
|
393
|
+
const createMockMarker = () => {
|
|
394
|
+
const el = document.createElement("div");
|
|
395
|
+
const marker = {
|
|
396
|
+
setLngLat: jest.fn(() => marker),
|
|
397
|
+
addTo: jest.fn(() => marker),
|
|
398
|
+
remove: jest.fn(),
|
|
399
|
+
getElement: jest.fn(() => el),
|
|
400
|
+
setOffset: jest.fn(() => marker),
|
|
401
|
+
getLngLat: jest.fn(() => createMockLngLat(0, 0)),
|
|
402
|
+
setPopup: jest.fn(() => marker),
|
|
403
|
+
getPopup: jest.fn(() => null),
|
|
404
|
+
togglePopup: jest.fn(() => marker),
|
|
405
|
+
setDraggable: jest.fn(() => marker),
|
|
406
|
+
isDraggable: jest.fn(() => false),
|
|
407
|
+
};
|
|
408
|
+
return marker;
|
|
409
|
+
};
|
|
410
|
+
return {
|
|
411
|
+
__esModule: true,
|
|
412
|
+
default: {
|
|
413
|
+
Map: jest.fn(createMockMapWithAutoLoad),
|
|
414
|
+
Marker: jest.fn(createMockMarker),
|
|
415
|
+
accessToken: "",
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
});
|
|
419
|
+
beforeEach(() => {
|
|
420
|
+
jest.clearAllMocks();
|
|
421
|
+
});
|
|
422
|
+
};
|
|
423
|
+
|
|
201
424
|
/**
|
|
202
425
|
* Mocks the window.matchMedia API for testing environments.
|
|
203
426
|
*
|
|
@@ -716,6 +939,7 @@ const setupWebStreams = () => {
|
|
|
716
939
|
* - Canvas API mocks
|
|
717
940
|
* - Console error reporting to fail tests (includes automatic CSS parser error suppression)
|
|
718
941
|
* - Google Maps API and components mocks
|
|
942
|
+
* - Mapbox GL JS mocks
|
|
719
943
|
* - React Helmet mocks
|
|
720
944
|
* - IntersectionObserver mocks
|
|
721
945
|
* - MatchMedia API mocks
|
|
@@ -746,6 +970,7 @@ const setupAllMocks = (options = {}) => {
|
|
|
746
970
|
setupCanvasMock();
|
|
747
971
|
setupFailOnConsole(options.failOnConsoleOptions);
|
|
748
972
|
setupGoogleMaps();
|
|
973
|
+
setupMapbox();
|
|
749
974
|
setupHelmetMock();
|
|
750
975
|
setupIntersectionObserver();
|
|
751
976
|
setupMatchMediaMock();
|
|
@@ -877,4 +1102,4 @@ const setupTanstackReactRouter = () => {
|
|
|
877
1102
|
}));
|
|
878
1103
|
};
|
|
879
1104
|
|
|
880
|
-
export { setupAllMocks, setupBasicMocks, setupCanvasMock, setupDefaultMocks, setupFailOnConsole, setupGoogleMaps, setupHelmetMock, setupIntersectionObserver, setupMatchMediaMock, setupReactTestingLibrary, setupReactVirtualizedAutoSizer, setupResizeObserver, setupTanstackReactRouter, setupTanstackReactVirtual, setupTimeAndLanguage, setupTimeZone, setupTranslations, setupWebStreams };
|
|
1105
|
+
export { createMockClickEvent, createMockMapboxMap, setupAllMocks, setupBasicMocks, setupCanvasMock, setupDefaultMocks, setupFailOnConsole, setupGoogleMaps, setupHelmetMock, setupIntersectionObserver, setupMapbox, setupMatchMediaMock, setupReactTestingLibrary, setupReactVirtualizedAutoSizer, setupResizeObserver, setupTanstackReactRouter, setupTanstackReactVirtual, setupTimeAndLanguage, setupTimeZone, setupTranslations, setupWebStreams };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-test-setup",
|
|
3
3
|
"description": "Test setup utilities for React applications",
|
|
4
|
-
"version": "1.8.
|
|
4
|
+
"version": "1.8.62-alpha-c496ead6241.0",
|
|
5
5
|
"repository": "https://github.com/Trackunit/manager",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
7
7
|
"engines": {
|
|
@@ -21,18 +21,19 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@googlemaps/jest-mocks": "2.22.6",
|
|
24
|
+
"@js-temporal/polyfill": "^0.5.1",
|
|
24
25
|
"@react-spring/web": "9.7.5",
|
|
25
26
|
"@testing-library/jest-dom": "^6.9.1",
|
|
26
27
|
"@testing-library/react": "16.2.0",
|
|
27
28
|
"@vis.gl/react-google-maps": "^1.7.1",
|
|
29
|
+
"mapbox-gl": "^3.18.1",
|
|
30
|
+
"jest": "30.0.5",
|
|
28
31
|
"jest-canvas-mock": "^2.5.2",
|
|
29
32
|
"jest-fail-on-console": "^3.1.2",
|
|
30
33
|
"react": "19.0.0",
|
|
31
34
|
"react-i18next": "^15.5.1",
|
|
32
35
|
"react-virtualized-auto-sizer": "^1.0.20",
|
|
33
|
-
"web-streams-polyfill": "^4.2.0"
|
|
34
|
-
"jest": "30.0.5",
|
|
35
|
-
"@js-temporal/polyfill": "^0.5.1"
|
|
36
|
+
"web-streams-polyfill": "^4.2.0"
|
|
36
37
|
},
|
|
37
38
|
"module": "./index.esm.js",
|
|
38
39
|
"main": "./index.cjs.js",
|
package/preset.cjs.js
CHANGED
|
@@ -19,7 +19,7 @@ const irisPreset = {
|
|
|
19
19
|
"@trackunit/ui-icons/icons-sprite-micro.svg": "jest-transform-stub",
|
|
20
20
|
},
|
|
21
21
|
transformIgnorePatterns: [
|
|
22
|
-
"/node_modules/(?!.*react-dnd.*|@tanstack[/-].*|.*dnd-core.*|.*react-calendar.*|.*get-user-locale.*|.*memoize.*|.*mimic-function.*|.*@wojtekmaj[/-]date-utils.*)",
|
|
22
|
+
"/node_modules/(?!.*react-dnd.*|@tanstack[/-].*|.*dnd-core.*|.*react-calendar.*|.*get-user-locale.*|.*memoize.*|.*mimic-function.*|.*@wojtekmaj[/-]date-utils.*|.*supercluster.*|.*kdbush.*)",
|
|
23
23
|
],
|
|
24
24
|
};
|
|
25
25
|
|
package/preset.esm.js
CHANGED
|
@@ -15,7 +15,7 @@ const irisPreset = {
|
|
|
15
15
|
"@trackunit/ui-icons/icons-sprite-micro.svg": "jest-transform-stub",
|
|
16
16
|
},
|
|
17
17
|
transformIgnorePatterns: [
|
|
18
|
-
"/node_modules/(?!.*react-dnd.*|@tanstack[/-].*|.*dnd-core.*|.*react-calendar.*|.*get-user-locale.*|.*memoize.*|.*mimic-function.*|.*@wojtekmaj[/-]date-utils.*)",
|
|
18
|
+
"/node_modules/(?!.*react-dnd.*|@tanstack[/-].*|.*dnd-core.*|.*react-calendar.*|.*get-user-locale.*|.*memoize.*|.*mimic-function.*|.*@wojtekmaj[/-]date-utils.*|.*supercluster.*|.*kdbush.*)",
|
|
19
19
|
],
|
|
20
20
|
};
|
|
21
21
|
|
package/src/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./setupFailOnConsole";
|
|
|
6
6
|
export * from "./setupGoogleMaps";
|
|
7
7
|
export * from "./setupHelmetMock";
|
|
8
8
|
export * from "./setupIntersectionObserver";
|
|
9
|
+
export * from "./setupMapbox";
|
|
9
10
|
export * from "./setupMatchMediaMock";
|
|
10
11
|
export * from "./setupReactTestingLibrary";
|
|
11
12
|
export * from "./setupReactVirtualizedAutoSizer";
|
package/src/setupAllMocks.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface SetupAllMocksOptions {
|
|
|
9
9
|
* - Canvas API mocks
|
|
10
10
|
* - Console error reporting to fail tests (includes automatic CSS parser error suppression)
|
|
11
11
|
* - Google Maps API and components mocks
|
|
12
|
+
* - Mapbox GL JS mocks
|
|
12
13
|
* - React Helmet mocks
|
|
13
14
|
* - IntersectionObserver mocks
|
|
14
15
|
* - MatchMedia API mocks
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { LngLat, LngLatBounds, LngLatLike, MapMouseEvent } from "mapbox-gl";
|
|
2
|
+
/**
|
|
3
|
+
* Type for event handlers stored in our mock map's listener registry.
|
|
4
|
+
* Using a generic to avoid `as` assertions when retrieving handlers.
|
|
5
|
+
*/
|
|
6
|
+
type MapEventHandler<TEvent = unknown> = (event: TEvent) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Shape of the mock map returned by createMockMapboxMap.
|
|
9
|
+
* Extends the necessary parts of mapboxgl.Map for adapter testing.
|
|
10
|
+
*/
|
|
11
|
+
type MockMapboxMap = {
|
|
12
|
+
on: jest.Mock<MockMapboxMap, [string, MapEventHandler]>;
|
|
13
|
+
once: jest.Mock<MockMapboxMap, [string, MapEventHandler]>;
|
|
14
|
+
off: jest.Mock<MockMapboxMap, [string, MapEventHandler]>;
|
|
15
|
+
remove: jest.Mock<void, []>;
|
|
16
|
+
getCenter: jest.Mock<LngLat, []>;
|
|
17
|
+
getZoom: jest.Mock<number, []>;
|
|
18
|
+
getBounds: jest.Mock<LngLatBounds, []>;
|
|
19
|
+
setCenter: jest.Mock<MockMapboxMap, [LngLatLike]>;
|
|
20
|
+
setZoom: jest.Mock<MockMapboxMap, [number]>;
|
|
21
|
+
panTo: jest.Mock<MockMapboxMap, [LngLatLike]>;
|
|
22
|
+
panBy: jest.Mock<MockMapboxMap, [[number, number]]>;
|
|
23
|
+
fitBounds: jest.Mock<MockMapboxMap, [LngLatBounds, unknown]>;
|
|
24
|
+
setStyle: jest.Mock<MockMapboxMap, [string]>;
|
|
25
|
+
isStyleLoaded: jest.Mock<boolean, []>;
|
|
26
|
+
isMoving: jest.Mock<boolean, []>;
|
|
27
|
+
addSource: jest.Mock;
|
|
28
|
+
removeSource: jest.Mock;
|
|
29
|
+
getSource: jest.Mock;
|
|
30
|
+
addLayer: jest.Mock;
|
|
31
|
+
removeLayer: jest.Mock;
|
|
32
|
+
getLayer: jest.Mock;
|
|
33
|
+
hasImage: jest.Mock<boolean, []>;
|
|
34
|
+
addImage: jest.Mock;
|
|
35
|
+
getCanvas: jest.Mock;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Return type of createMockMapboxMap - provides both the mock map
|
|
39
|
+
* and a triggerEvent helper for simulating Mapbox events in tests.
|
|
40
|
+
*/
|
|
41
|
+
type MockMapboxMapResult = {
|
|
42
|
+
/**
|
|
43
|
+
* The mock map instance. Cast to mapboxgl.Map when passing to adapter.connect().
|
|
44
|
+
* We return MockMapboxMap to preserve access to jest mock methods in tests.
|
|
45
|
+
*/
|
|
46
|
+
readonly map: MockMapboxMap;
|
|
47
|
+
/**
|
|
48
|
+
* Triggers an event on the mock map, calling all registered handlers.
|
|
49
|
+
* Handles both regular (on) and one-time (once) listeners.
|
|
50
|
+
*/
|
|
51
|
+
readonly triggerEvent: <TEvent = unknown>(eventName: string, event?: TEvent) => void;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a mock Mapbox map instance for unit testing adapter instances directly.
|
|
55
|
+
*
|
|
56
|
+
* Use this when you need fine-grained control over mock behavior, such as:
|
|
57
|
+
* - Testing adapter instance methods (connect, setCenter, etc.)
|
|
58
|
+
* - Simulating map events (idle, click, movestart)
|
|
59
|
+
* - Verifying method calls on the map
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { createMockMapboxMap } from "@trackunit/react-test-setup";
|
|
64
|
+
*
|
|
65
|
+
* it("should connect to map", () => {
|
|
66
|
+
* const { map, triggerEvent } = createMockMapboxMap();
|
|
67
|
+
* const adapter = new MapboxAdapterInstance(config);
|
|
68
|
+
*
|
|
69
|
+
* adapter.connect(map as unknown as mapboxgl.Map);
|
|
70
|
+
* triggerEvent("idle");
|
|
71
|
+
*
|
|
72
|
+
* expect(adapter.getState().isReady).toBe(true);
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare const createMockMapboxMap: () => MockMapboxMapResult;
|
|
77
|
+
/**
|
|
78
|
+
* Mock click event matching Mapbox GL's MapMouseEvent shape.
|
|
79
|
+
* Use with triggerEvent("click", createMockClickEvent(...))
|
|
80
|
+
*
|
|
81
|
+
* Note: The `point` property is intentionally omitted because:
|
|
82
|
+
* 1. It requires the full Point class from @mapbox/point-geometry with 30+ methods
|
|
83
|
+
* 2. No tests currently use the point property
|
|
84
|
+
* 3. Since this returns Partial<MapMouseEvent>, point is optional
|
|
85
|
+
*/
|
|
86
|
+
export declare const createMockClickEvent: (lng: number, lat: number) => Partial<MapMouseEvent>;
|
|
87
|
+
/**
|
|
88
|
+
* Sets up mocks for Mapbox GL JS in testing environments.
|
|
89
|
+
*
|
|
90
|
+
* This function mocks the mapbox-gl module with functional mock implementations,
|
|
91
|
+
* allowing tests of map-dependent components to run without WebGL or actual
|
|
92
|
+
* network requests.
|
|
93
|
+
*
|
|
94
|
+
* Key features:
|
|
95
|
+
* - Mocks mapboxgl.Map constructor to return a trackable mock instance
|
|
96
|
+
* - Auto-fires the "load" event after map construction (for renderer tests)
|
|
97
|
+
* - Provides mock implementations for all common map methods
|
|
98
|
+
* - Resets mock state between tests via beforeEach
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* // In your test file
|
|
103
|
+
* import { setupMapbox } from "@trackunit/react-test-setup";
|
|
104
|
+
*
|
|
105
|
+
* setupMapbox();
|
|
106
|
+
*
|
|
107
|
+
* describe("MapboxRenderer", () => {
|
|
108
|
+
* it("renders map when loaded", async () => {
|
|
109
|
+
* // The mock will auto-fire "load" event
|
|
110
|
+
* render(<MapboxRenderer adapterInstance={instance} />);
|
|
111
|
+
* await waitFor(() => expect(screen.getByRole("application")).toBeInTheDocument());
|
|
112
|
+
* });
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare const setupMapbox: () => void;
|
|
117
|
+
export {};
|