@osimatic/helpers-js 1.5.20 → 1.5.21

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.
@@ -1,77 +1,186 @@
1
1
  /**
2
2
  * @jest-environment jsdom
3
3
  */
4
- const { OpenStreetMap } = require('../open_street_map');
4
+ const { OpenStreetMap, OsmMap } = require('../open_street_map');
5
5
  const L = require('leaflet');
6
6
 
7
+ function createMockMap(zoom = 6) {
8
+ return {
9
+ setView: jest.fn(),
10
+ getZoom: jest.fn(() => zoom),
11
+ setZoom: jest.fn(),
12
+ fitBounds: jest.fn(),
13
+ invalidateSize: jest.fn(),
14
+ off: jest.fn(),
15
+ remove: jest.fn(),
16
+ addLayer: jest.fn(),
17
+ removeLayer: jest.fn(),
18
+ eachLayer: jest.fn(),
19
+ addControl: jest.fn(),
20
+ on: jest.fn(),
21
+ };
22
+ }
23
+
24
+ function createMockMarker(lat = 48.8566, lng = 2.3522) {
25
+ return {
26
+ on: jest.fn(),
27
+ addTo: jest.fn().mockReturnThis(),
28
+ bindPopup: jest.fn(),
29
+ getLatLng: jest.fn(() => ({ lat, lng })),
30
+ };
31
+ }
32
+
7
33
  describe('OpenStreetMap', () => {
34
+ describe('createMap', () => {
35
+ let mockMap;
36
+ let mockTileLayer;
37
+ let domUtilGetSpy;
38
+ let mapSpy;
39
+ let tileLayerSpy;
40
+
41
+ beforeEach(() => {
42
+ mockMap = createMockMap();
43
+ mockTileLayer = { addTo: jest.fn() };
44
+ domUtilGetSpy = jest.spyOn(L.DomUtil, 'get').mockReturnValue(null);
45
+ mapSpy = jest.spyOn(L, 'map').mockReturnValue(mockMap);
46
+ tileLayerSpy = jest.spyOn(L, 'tileLayer').mockReturnValue(mockTileLayer);
47
+ jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: [] });
48
+ });
49
+
50
+ afterEach(() => jest.restoreAllMocks());
51
+
52
+ test('should return null when mapContainer is null', () => {
53
+ const result = OpenStreetMap.createMap(null);
54
+ expect(result).toBeNull();
55
+ expect(mapSpy).not.toHaveBeenCalled();
56
+ });
57
+
58
+ test('should return null when mapContainer is undefined', () => {
59
+ const result = OpenStreetMap.createMap(undefined);
60
+ expect(result).toBeNull();
61
+ expect(mapSpy).not.toHaveBeenCalled();
62
+ });
63
+
64
+ test('should create and return a Leaflet map for a valid DOM element', () => {
65
+ const div = document.createElement('div');
66
+ document.body.appendChild(div);
67
+
68
+ const result = OpenStreetMap.createMap(div);
69
+
70
+ expect(mapSpy).toHaveBeenCalledWith(div, {});
71
+ expect(tileLayerSpy).toHaveBeenCalled();
72
+ expect(mockTileLayer.addTo).toHaveBeenCalledWith(mockMap);
73
+ expect(result).toBe(mockMap);
74
+
75
+ document.body.removeChild(div);
76
+ });
77
+
78
+ test('should reset _leaflet_id when container already has one', () => {
79
+ const div = document.createElement('div');
80
+ document.body.appendChild(div);
81
+ const existingContainer = { _leaflet_id: 42 };
82
+ domUtilGetSpy.mockReturnValue(existingContainer);
83
+
84
+ OpenStreetMap.createMap(div);
85
+
86
+ expect(existingContainer._leaflet_id).toBeNull();
87
+ document.body.removeChild(div);
88
+ });
89
+
90
+ test('should pass options to L.map', () => {
91
+ const div = document.createElement('div');
92
+ document.body.appendChild(div);
93
+
94
+ OpenStreetMap.createMap(div, { zoomControl: false });
95
+
96
+ expect(mapSpy).toHaveBeenCalledWith(div, { zoomControl: false });
97
+ document.body.removeChild(div);
98
+ });
99
+
100
+ test('should center on France by default', () => {
101
+ const div = document.createElement('div');
102
+ document.body.appendChild(div);
103
+
104
+ OpenStreetMap.createMap(div);
105
+
106
+ expect(mockMap.fitBounds).toHaveBeenCalled();
107
+ document.body.removeChild(div);
108
+ });
109
+ });
110
+
8
111
  describe('getUrl', () => {
9
112
  test('should generate OpenStreetMap URL with latitude and longitude', () => {
10
113
  const url = OpenStreetMap.getUrl(48.8566, 2.3522);
11
-
12
114
  expect(url).toBe('https://www.openstreetmap.org/?mlat=48.8566&mlon=2.3522#map=17/48.8566/2.3522&layers=N');
13
115
  });
14
116
 
15
117
  test('should handle negative coordinates', () => {
16
118
  const url = OpenStreetMap.getUrl(-33.8688, 151.2093);
17
-
18
119
  expect(url).toContain('mlat=-33.8688');
19
120
  expect(url).toContain('mlon=151.2093');
20
121
  });
21
122
 
22
123
  test('should handle zero coordinates', () => {
23
124
  const url = OpenStreetMap.getUrl(0, 0);
24
-
25
125
  expect(url).toContain('mlat=0');
26
126
  expect(url).toContain('mlon=0');
27
127
  });
28
128
 
29
129
  test('should include zoom level 17', () => {
30
- const url = OpenStreetMap.getUrl(48.8566, 2.3522);
31
-
32
- expect(url).toContain('#map=17/');
130
+ expect(OpenStreetMap.getUrl(48.8566, 2.3522)).toContain('#map=17/');
33
131
  });
34
132
 
35
133
  test('should include layers=N parameter', () => {
36
- const url = OpenStreetMap.getUrl(48.8566, 2.3522);
37
-
38
- expect(url).toContain('&layers=N');
134
+ expect(OpenStreetMap.getUrl(48.8566, 2.3522)).toContain('&layers=N');
39
135
  });
40
136
  });
41
137
 
42
138
  describe('getUrlFromCoordinates', () => {
43
139
  test('should parse coordinate string and generate URL', () => {
44
140
  const url = OpenStreetMap.getUrlFromCoordinates('48.8566,2.3522');
45
-
46
141
  expect(url).toBe('https://www.openstreetmap.org/?mlat=48.8566&mlon=2.3522#map=17/48.8566/2.3522&layers=N');
47
142
  });
48
143
 
49
144
  test('should handle negative coordinates in string', () => {
50
145
  const url = OpenStreetMap.getUrlFromCoordinates('-33.8688,151.2093');
51
-
52
146
  expect(url).toContain('mlat=-33.8688');
53
147
  expect(url).toContain('mlon=151.2093');
54
148
  });
55
149
 
56
150
  test('should parse coordinates with spaces', () => {
57
151
  const url = OpenStreetMap.getUrlFromCoordinates('48.8566, 2.3522');
58
-
59
152
  expect(url).toContain('mlat=48.8566');
60
153
  expect(url).toContain('mlon=2.3522');
61
154
  });
62
155
 
63
156
  test('should handle decimal coordinates', () => {
64
157
  const url = OpenStreetMap.getUrlFromCoordinates('48.856614,2.352222');
65
-
66
158
  expect(url).toContain('mlat=48.856614');
67
159
  expect(url).toContain('mlon=2.352222');
68
160
  });
69
161
  });
70
162
 
163
+ describe('centerOnFrance', () => {
164
+ test('should call setView with France coordinates', () => {
165
+ const mockMap = createMockMap();
166
+ OpenStreetMap.centerOnFrance(mockMap);
167
+ expect(mockMap.setView).toHaveBeenCalledWith([46.52863469527167, 2.43896484375], 6);
168
+ });
169
+
170
+ test('should use zoom level 6', () => {
171
+ const mockMap = createMockMap();
172
+ OpenStreetMap.centerOnFrance(mockMap);
173
+ expect(mockMap.setView).toHaveBeenCalledWith(expect.any(Array), 6);
174
+ });
175
+
176
+ test('should not throw when map is null', () => {
177
+ expect(() => OpenStreetMap.centerOnFrance(null)).not.toThrow();
178
+ });
179
+ });
180
+
71
181
  describe('getCountryBoundingBoxes', () => {
72
182
  test('should return object with country codes', () => {
73
183
  const boxes = OpenStreetMap.getCountryBoundingBoxes();
74
-
75
184
  expect(typeof boxes).toBe('object');
76
185
  expect(boxes).toHaveProperty('fr');
77
186
  expect(boxes).toHaveProperty('de');
@@ -79,66 +188,41 @@ describe('OpenStreetMap', () => {
79
188
  });
80
189
 
81
190
  test('should have France bounding box', () => {
82
- const boxes = OpenStreetMap.getCountryBoundingBoxes();
83
-
84
- expect(boxes.fr).toEqual([[41.333, -5.142], [51.091, 9.559]]);
191
+ expect(OpenStreetMap.getCountryBoundingBoxes().fr).toEqual([[41.333, -5.142], [51.091, 9.559]]);
85
192
  });
86
193
 
87
194
  test('should have Germany bounding box', () => {
88
- const boxes = OpenStreetMap.getCountryBoundingBoxes();
89
-
90
- expect(boxes.de).toEqual([[47.270, 5.866], [55.058, 15.041]]);
195
+ expect(OpenStreetMap.getCountryBoundingBoxes().de).toEqual([[47.270, 5.866], [55.058, 15.041]]);
91
196
  });
92
197
 
93
198
  test('should have USA bounding box', () => {
94
- const boxes = OpenStreetMap.getCountryBoundingBoxes();
95
-
96
- expect(boxes.us).toEqual([[24.396, -124.848], [49.384, -66.885]]);
199
+ expect(OpenStreetMap.getCountryBoundingBoxes().us).toEqual([[24.396, -124.848], [49.384, -66.885]]);
97
200
  });
98
201
 
99
202
  test('should include European countries', () => {
100
203
  const boxes = OpenStreetMap.getCountryBoundingBoxes();
101
-
102
- expect(boxes).toHaveProperty('fr'); // France
103
- expect(boxes).toHaveProperty('de'); // Germany
104
- expect(boxes).toHaveProperty('es'); // Spain
105
- expect(boxes).toHaveProperty('it'); // Italy
106
- expect(boxes).toHaveProperty('gb'); // UK
204
+ ['fr', 'de', 'es', 'it', 'gb'].forEach(c => expect(boxes).toHaveProperty(c));
107
205
  });
108
206
 
109
207
  test('should include Asian countries', () => {
110
208
  const boxes = OpenStreetMap.getCountryBoundingBoxes();
111
-
112
- expect(boxes).toHaveProperty('cn'); // China
113
- expect(boxes).toHaveProperty('in'); // India
114
- expect(boxes).toHaveProperty('jp'); // Japan
209
+ ['cn', 'in', 'jp'].forEach(c => expect(boxes).toHaveProperty(c));
115
210
  });
116
211
 
117
212
  test('should include American countries', () => {
118
213
  const boxes = OpenStreetMap.getCountryBoundingBoxes();
119
-
120
- expect(boxes).toHaveProperty('us'); // USA
121
- expect(boxes).toHaveProperty('ca'); // Canada
122
- expect(boxes).toHaveProperty('br'); // Brazil
123
- expect(boxes).toHaveProperty('mx'); // Mexico
214
+ ['us', 'ca', 'br', 'mx'].forEach(c => expect(boxes).toHaveProperty(c));
124
215
  });
125
216
 
126
217
  test('should include African countries', () => {
127
218
  const boxes = OpenStreetMap.getCountryBoundingBoxes();
128
-
129
- expect(boxes).toHaveProperty('ma'); // Morocco
130
- expect(boxes).toHaveProperty('eg'); // Egypt
131
- expect(boxes).toHaveProperty('za'); // South Africa
219
+ ['ma', 'eg', 'za'].forEach(c => expect(boxes).toHaveProperty(c));
132
220
  });
133
221
 
134
222
  test('should have bounding box format [[S,W], [N,E]]', () => {
135
- const boxes = OpenStreetMap.getCountryBoundingBoxes();
136
- const frBox = boxes.fr;
137
-
223
+ const frBox = OpenStreetMap.getCountryBoundingBoxes().fr;
138
224
  expect(Array.isArray(frBox)).toBe(true);
139
225
  expect(frBox).toHaveLength(2);
140
- expect(Array.isArray(frBox[0])).toBe(true);
141
- expect(Array.isArray(frBox[1])).toBe(true);
142
226
  expect(frBox[0]).toHaveLength(2);
143
227
  expect(frBox[1]).toHaveLength(2);
144
228
  });
@@ -146,329 +230,586 @@ describe('OpenStreetMap', () => {
146
230
 
147
231
  describe('getCountryBoundingBox', () => {
148
232
  test('should return bounding box for France', () => {
149
- const box = OpenStreetMap.getCountryBoundingBox('FR');
150
-
151
- expect(box).toEqual([[41.333, -5.142], [51.091, 9.559]]);
233
+ expect(OpenStreetMap.getCountryBoundingBox('FR')).toEqual([[41.333, -5.142], [51.091, 9.559]]);
152
234
  });
153
235
 
154
236
  test('should be case insensitive', () => {
155
- const boxUpper = OpenStreetMap.getCountryBoundingBox('FR');
156
- const boxLower = OpenStreetMap.getCountryBoundingBox('fr');
157
- const boxMixed = OpenStreetMap.getCountryBoundingBox('Fr');
158
-
159
- expect(boxLower).toEqual(boxUpper);
160
- expect(boxMixed).toEqual(boxUpper);
237
+ const box = OpenStreetMap.getCountryBoundingBox('FR');
238
+ expect(OpenStreetMap.getCountryBoundingBox('fr')).toEqual(box);
239
+ expect(OpenStreetMap.getCountryBoundingBox('Fr')).toEqual(box);
161
240
  });
162
241
 
163
242
  test('should handle whitespace in country code', () => {
164
- const box = OpenStreetMap.getCountryBoundingBox(' FR ');
165
-
166
- expect(box).toEqual([[41.333, -5.142], [51.091, 9.559]]);
243
+ expect(OpenStreetMap.getCountryBoundingBox(' FR ')).toEqual([[41.333, -5.142], [51.091, 9.559]]);
167
244
  });
168
245
 
169
246
  test('should return null for unknown country code', () => {
170
- const box = OpenStreetMap.getCountryBoundingBox('XX');
171
-
172
- expect(box).toBeNull();
247
+ expect(OpenStreetMap.getCountryBoundingBox('XX')).toBeNull();
173
248
  });
174
249
 
175
250
  test('should return null for empty string', () => {
176
- const box = OpenStreetMap.getCountryBoundingBox('');
177
-
178
- expect(box).toBeNull();
251
+ expect(OpenStreetMap.getCountryBoundingBox('')).toBeNull();
179
252
  });
180
253
 
181
254
  test('should return null for null', () => {
182
- const box = OpenStreetMap.getCountryBoundingBox(null);
183
-
184
- expect(box).toBeNull();
255
+ expect(OpenStreetMap.getCountryBoundingBox(null)).toBeNull();
185
256
  });
186
257
 
187
258
  test('should return null for undefined', () => {
188
- const box = OpenStreetMap.getCountryBoundingBox(undefined);
189
-
190
- expect(box).toBeNull();
259
+ expect(OpenStreetMap.getCountryBoundingBox(undefined)).toBeNull();
191
260
  });
192
261
 
193
262
  test('should return bounding box for Germany', () => {
194
- const box = OpenStreetMap.getCountryBoundingBox('DE');
195
-
196
- expect(box).toEqual([[47.270, 5.866], [55.058, 15.041]]);
263
+ expect(OpenStreetMap.getCountryBoundingBox('DE')).toEqual([[47.270, 5.866], [55.058, 15.041]]);
197
264
  });
198
265
 
199
266
  test('should return bounding box for USA', () => {
200
- const box = OpenStreetMap.getCountryBoundingBox('US');
201
-
202
- expect(box).toEqual([[24.396, -124.848], [49.384, -66.885]]);
267
+ expect(OpenStreetMap.getCountryBoundingBox('US')).toEqual([[24.396, -124.848], [49.384, -66.885]]);
203
268
  });
204
269
 
205
270
  test('should return bounding box for Japan', () => {
206
- const box = OpenStreetMap.getCountryBoundingBox('JP');
207
-
208
- expect(box).toEqual([[24.249, 122.938], [45.557, 153.987]]);
271
+ expect(OpenStreetMap.getCountryBoundingBox('JP')).toEqual([[24.249, 122.938], [45.557, 153.987]]);
209
272
  });
210
273
 
211
274
  test('should return bounding box for Brazil', () => {
212
- const box = OpenStreetMap.getCountryBoundingBox('BR');
213
-
214
- expect(box).toEqual([[-33.751, -73.987], [5.271, -34.729]]);
275
+ expect(OpenStreetMap.getCountryBoundingBox('BR')).toEqual([[-33.751, -73.987], [5.271, -34.729]]);
215
276
  });
216
277
  });
217
278
 
218
- describe('createMap', () => {
279
+ describe('centerMapOnCountry', () => {
219
280
  let mockMap;
220
- let mockTileLayer;
221
- let domUtilGetSpy;
222
- let mapSpy;
223
- let tileLayerSpy;
224
281
 
225
282
  beforeEach(() => {
226
- mockMap = {
227
- setView: jest.fn(),
228
- getZoom: jest.fn(() => 6),
229
- setZoom: jest.fn(),
230
- fitBounds: jest.fn(),
231
- invalidateSize: jest.fn(),
232
- };
233
- mockTileLayer = { addTo: jest.fn() };
234
- domUtilGetSpy = jest.spyOn(L.DomUtil, 'get').mockReturnValue(null);
235
- mapSpy = jest.spyOn(L, 'map').mockReturnValue(mockMap);
236
- tileLayerSpy = jest.spyOn(L, 'tileLayer').mockReturnValue(mockTileLayer);
283
+ mockMap = createMockMap();
284
+ jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: [] });
237
285
  });
238
286
 
239
- afterEach(() => {
240
- domUtilGetSpy.mockRestore();
241
- mapSpy.mockRestore();
242
- tileLayerSpy.mockRestore();
287
+ afterEach(() => jest.restoreAllMocks());
288
+
289
+ test('should not throw when map is null', () => {
290
+ expect(() => OpenStreetMap.centerMapOnCountry(null, 'FR')).not.toThrow();
243
291
  });
244
292
 
245
- test('should return null when mapContainer is null', () => {
246
- const result = OpenStreetMap.createMap(null);
293
+ test('should not call fitBounds for unknown country', () => {
294
+ OpenStreetMap.centerMapOnCountry(mockMap, 'XX');
295
+ expect(mockMap.fitBounds).not.toHaveBeenCalled();
296
+ });
247
297
 
248
- expect(result).toBeNull();
249
- expect(mapSpy).not.toHaveBeenCalled();
298
+ test('should call fitBounds for known country', () => {
299
+ OpenStreetMap.centerMapOnCountry(mockMap, 'FR');
300
+ expect(mockMap.fitBounds).toHaveBeenCalled();
250
301
  });
251
302
 
252
- test('should return null when mapContainer is undefined', () => {
253
- const result = OpenStreetMap.createMap(undefined);
303
+ test('should be case insensitive', () => {
304
+ OpenStreetMap.centerMapOnCountry(mockMap, 'fr');
305
+ expect(mockMap.fitBounds).toHaveBeenCalled();
306
+ });
254
307
 
255
- expect(result).toBeNull();
256
- expect(mapSpy).not.toHaveBeenCalled();
308
+ test('should enforce minZoom when current zoom is too low', () => {
309
+ mockMap.getZoom.mockReturnValue(1);
310
+ OpenStreetMap.centerMapOnCountry(mockMap, 'FR');
311
+ expect(mockMap.setZoom).toHaveBeenCalledWith(3);
257
312
  });
258
313
 
259
- test('should create and return a Leaflet map for a valid DOM element', () => {
260
- const div = document.createElement('div');
261
- document.body.appendChild(div);
314
+ test('should not enforce minZoom when zoom is sufficient', () => {
315
+ mockMap.getZoom.mockReturnValue(6);
316
+ OpenStreetMap.centerMapOnCountry(mockMap, 'FR');
317
+ expect(mockMap.setZoom).not.toHaveBeenCalled();
318
+ });
319
+ });
262
320
 
263
- const result = OpenStreetMap.createMap(div);
321
+ describe('centerMapToLocations', () => {
322
+ let mockMap;
264
323
 
265
- expect(mapSpy).toHaveBeenCalledWith(div, {});
266
- expect(tileLayerSpy).toHaveBeenCalled();
267
- expect(mockTileLayer.addTo).toHaveBeenCalledWith(mockMap);
268
- expect(result).toBe(mockMap);
324
+ beforeEach(() => {
325
+ mockMap = createMockMap(12);
326
+ jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: [] });
327
+ });
269
328
 
270
- document.body.removeChild(div);
329
+ afterEach(() => jest.restoreAllMocks());
330
+
331
+ test('should call fitBounds with location bounds', () => {
332
+ const locations = [[48.8566, 2.3522], [48.8606, 2.3376]];
333
+ OpenStreetMap.centerMapToLocations(mockMap, locations);
334
+ expect(mockMap.invalidateSize).toHaveBeenCalledWith(false);
335
+ expect(mockMap.fitBounds).toHaveBeenCalled();
271
336
  });
272
337
 
273
- test('should reset _leaflet_id when container already has one', () => {
274
- const div = document.createElement('div');
275
- document.body.appendChild(div);
276
- const existingContainer = { _leaflet_id: 42 };
277
- domUtilGetSpy.mockReturnValue(existingContainer);
338
+ test('should not do anything when map is null', () => {
339
+ OpenStreetMap.centerMapToLocations(null, [[48.8566, 2.3522]]);
340
+ expect(mockMap.invalidateSize).not.toHaveBeenCalled();
341
+ });
278
342
 
279
- OpenStreetMap.createMap(div);
343
+ test('should not do anything when locations list is empty', () => {
344
+ OpenStreetMap.centerMapToLocations(mockMap, []);
345
+ expect(mockMap.invalidateSize).not.toHaveBeenCalled();
346
+ });
280
347
 
281
- expect(existingContainer._leaflet_id).toBeNull();
348
+ test('should set zoom to maxZoom if current zoom exceeds it', () => {
349
+ mockMap.getZoom.mockReturnValue(20);
350
+ OpenStreetMap.centerMapToLocations(mockMap, [[48.8566, 2.3522]], [20, 20], 18);
351
+ expect(mockMap.setZoom).toHaveBeenCalledWith(18);
352
+ });
282
353
 
283
- document.body.removeChild(div);
354
+ test('should use custom padding', () => {
355
+ OpenStreetMap.centerMapToLocations(mockMap, [[48.8566, 2.3522]], [50, 50]);
356
+ expect(mockMap.fitBounds).toHaveBeenCalledWith(expect.anything(), { padding: [50, 50] });
284
357
  });
358
+ });
285
359
 
286
- test('should pass options to L.map', () => {
287
- const div = document.createElement('div');
288
- document.body.appendChild(div);
289
- const options = { zoomControl: false };
360
+ describe('centerMapToGooglePlace', () => {
361
+ test('should call setView with place location', () => {
362
+ const mockMap = createMockMap(10);
363
+ const place = { geometry: { location: { lat: () => 48.8566, lng: () => 2.3522 } } };
364
+ OpenStreetMap.centerMapToGooglePlace(mockMap, place);
365
+ expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 15);
366
+ });
290
367
 
291
- OpenStreetMap.createMap(div, options);
368
+ test('should not throw when place is null', () => {
369
+ expect(() => OpenStreetMap.centerMapToGooglePlace(createMockMap(), null)).not.toThrow();
370
+ });
292
371
 
293
- expect(mapSpy).toHaveBeenCalledWith(div, options);
372
+ test('should not throw when place has no geometry', () => {
373
+ expect(() => OpenStreetMap.centerMapToGooglePlace(createMockMap(), {})).not.toThrow();
374
+ });
375
+ });
294
376
 
295
- document.body.removeChild(div);
377
+ describe('centerMapToCoordinates', () => {
378
+ test('should call setView with provided coordinates', () => {
379
+ const mockMap = createMockMap(10);
380
+ OpenStreetMap.centerMapToCoordinates(mockMap, 48.8566, 2.3522);
381
+ expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 15);
296
382
  });
297
383
 
298
- test('should center on France by default', () => {
299
- const div = document.createElement('div');
300
- document.body.appendChild(div);
301
- const fitBoundsSpy = jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: [] });
384
+ test('should use minimum zoom of 15 if current zoom is lower', () => {
385
+ const mockMap = createMockMap(10);
386
+ OpenStreetMap.centerMapToCoordinates(mockMap, 48.8566, 2.3522);
387
+ expect(mockMap.setView).toHaveBeenCalledWith(expect.any(Array), 15);
388
+ });
302
389
 
303
- OpenStreetMap.createMap(div);
390
+ test('should keep current zoom if higher than 15', () => {
391
+ const mockMap = createMockMap(18);
392
+ OpenStreetMap.centerMapToCoordinates(mockMap, 48.8566, 2.3522);
393
+ expect(mockMap.setView).toHaveBeenCalledWith(expect.any(Array), 18);
394
+ });
304
395
 
305
- expect(mockMap.fitBounds).toHaveBeenCalled();
396
+ test('should not call setView when map is null', () => {
397
+ const mockMap = createMockMap(10);
398
+ OpenStreetMap.centerMapToCoordinates(null, 48.8566, 2.3522);
399
+ expect(mockMap.setView).not.toHaveBeenCalled();
400
+ });
306
401
 
307
- fitBoundsSpy.mockRestore();
308
- document.body.removeChild(div);
402
+ test('should handle negative coordinates', () => {
403
+ const mockMap = createMockMap(10);
404
+ OpenStreetMap.centerMapToCoordinates(mockMap, -33.8688, 151.2093);
405
+ expect(mockMap.setView).toHaveBeenCalledWith([-33.8688, 151.2093], 15);
309
406
  });
310
407
  });
311
408
 
312
- describe('centerOnFrance', () => {
313
- test('should call setView with France coordinates', () => {
314
- const mockMap = {
315
- setView: jest.fn()
316
- };
409
+ describe('clearSelections', () => {
410
+ test('should call eachLayer on map', () => {
411
+ const mockMap = createMockMap();
412
+ mockMap.eachLayer = jest.fn();
413
+ OpenStreetMap.clearSelections(mockMap);
414
+ expect(mockMap.eachLayer).toHaveBeenCalled();
415
+ });
317
416
 
318
- OpenStreetMap.centerOnFrance(mockMap);
417
+ test('should remove L.Marker layers', () => {
418
+ const removeSpy = jest.spyOn(L.Marker.prototype, 'remove').mockImplementation(() => {});
419
+ const mockMap = createMockMap();
420
+ mockMap.eachLayer = jest.fn((cb) => { cb(new L.Marker([0, 0])); });
319
421
 
320
- expect(mockMap.setView).toHaveBeenCalledWith([46.52863469527167, 2.43896484375], 6);
422
+ OpenStreetMap.clearSelections(mockMap);
423
+
424
+ expect(removeSpy).toHaveBeenCalled();
425
+ removeSpy.mockRestore();
321
426
  });
322
427
 
323
- test('should use zoom level 6', () => {
324
- const mockMap = {
325
- setView: jest.fn()
326
- };
428
+ test('should not throw when map is null', () => {
429
+ expect(() => OpenStreetMap.clearSelections(null)).not.toThrow();
430
+ });
431
+ });
327
432
 
328
- OpenStreetMap.centerOnFrance(mockMap);
433
+ describe('addTempMarker', () => {
434
+ let mockMarker;
329
435
 
330
- expect(mockMap.setView).toHaveBeenCalledWith(expect.any(Array), 6);
436
+ beforeEach(() => {
437
+ mockMarker = { on: jest.fn() };
438
+ jest.spyOn(L, 'marker').mockReturnValue(mockMarker);
331
439
  });
332
- });
333
440
 
334
- describe('centerMapToCoordinates', () => {
335
- test('should call setView with provided coordinates', () => {
336
- const mockMap = {
337
- setView: jest.fn(),
338
- getZoom: jest.fn(() => 10)
339
- };
441
+ afterEach(() => jest.restoreAllMocks());
340
442
 
341
- OpenStreetMap.centerMapToCoordinates(mockMap, 48.8566, 2.3522);
443
+ test('should create a draggable marker and add it to the map', () => {
444
+ const mockMap = createMockMap();
445
+ const result = OpenStreetMap.addTempMarker(mockMap, 48.8566, 2.3522);
446
+ expect(L.marker).toHaveBeenCalledWith([48.8566, 2.3522], { draggable: true });
447
+ expect(mockMap.addLayer).toHaveBeenCalledWith(mockMarker);
448
+ expect(result).toBe(mockMarker);
449
+ });
342
450
 
343
- expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 15);
451
+ test('should register dragend when onDragEnd is provided', () => {
452
+ OpenStreetMap.addTempMarker(createMockMap(), 48.8566, 2.3522, jest.fn());
453
+ expect(mockMarker.on).toHaveBeenCalledWith('dragend', expect.any(Function));
344
454
  });
345
455
 
346
- test('should use minimum zoom of 15 if current zoom is lower', () => {
347
- const mockMap = {
348
- setView: jest.fn(),
349
- getZoom: jest.fn(() => 10)
350
- };
456
+ test('should not register dragend when onDragEnd is not provided', () => {
457
+ OpenStreetMap.addTempMarker(createMockMap(), 48.8566, 2.3522);
458
+ expect(mockMarker.on).not.toHaveBeenCalled();
459
+ });
351
460
 
352
- OpenStreetMap.centerMapToCoordinates(mockMap, 48.8566, 2.3522);
461
+ test('should call onDragEnd with the marker on dragend', () => {
462
+ const onDragEnd = jest.fn();
463
+ let dragEndHandler;
464
+ mockMarker.on = jest.fn((event, handler) => { dragEndHandler = handler; });
353
465
 
354
- expect(mockMap.setView).toHaveBeenCalledWith(expect.any(Array), 15);
466
+ OpenStreetMap.addTempMarker(createMockMap(), 48.8566, 2.3522, onDragEnd);
467
+ dragEndHandler({ target: mockMarker });
468
+
469
+ expect(onDragEnd).toHaveBeenCalledWith(mockMarker);
355
470
  });
471
+ });
356
472
 
357
- test('should keep current zoom if higher than 15', () => {
358
- const mockMap = {
359
- setView: jest.fn(),
360
- getZoom: jest.fn(() => 18)
361
- };
473
+ describe('resetTempSelection', () => {
474
+ test('should remove tempLayer from map', () => {
475
+ const mockMap = createMockMap();
476
+ OpenStreetMap.resetTempSelection(mockMap, {});
477
+ expect(mockMap.removeLayer).toHaveBeenCalled();
478
+ });
362
479
 
363
- OpenStreetMap.centerMapToCoordinates(mockMap, 48.8566, 2.3522);
480
+ test('should not call removeLayer when tempLayer is null', () => {
481
+ const mockMap = createMockMap();
482
+ OpenStreetMap.resetTempSelection(mockMap, null);
483
+ expect(mockMap.removeLayer).not.toHaveBeenCalled();
484
+ });
364
485
 
365
- expect(mockMap.setView).toHaveBeenCalledWith(expect.any(Array), 18);
486
+ test('should not throw when both are null', () => {
487
+ expect(() => OpenStreetMap.resetTempSelection(null, null)).not.toThrow();
366
488
  });
489
+ });
367
490
 
368
- test('should not call setView when map is null', () => {
369
- const mockMap = {
370
- setView: jest.fn(),
371
- getZoom: jest.fn(() => 10)
372
- };
491
+ describe('destroyMap', () => {
492
+ test('should call off and remove on map', () => {
493
+ const mockMap = createMockMap();
494
+ OpenStreetMap.destroyMap(mockMap);
495
+ expect(mockMap.off).toHaveBeenCalled();
496
+ expect(mockMap.remove).toHaveBeenCalled();
497
+ });
373
498
 
374
- OpenStreetMap.centerMapToCoordinates(null, 48.8566, 2.3522);
499
+ test('should not throw when map is null', () => {
500
+ expect(() => OpenStreetMap.destroyMap(null)).not.toThrow();
501
+ });
502
+ });
375
503
 
376
- expect(mockMap.setView).not.toHaveBeenCalled();
504
+ describe('setZoom', () => {
505
+ test('should call setZoom on map', () => {
506
+ const mockMap = createMockMap();
507
+ OpenStreetMap.setZoom(mockMap, 12);
508
+ expect(mockMap.setZoom).toHaveBeenCalledWith(12);
377
509
  });
378
510
 
379
- test('should handle negative coordinates', () => {
380
- const mockMap = {
381
- setView: jest.fn(),
382
- getZoom: jest.fn(() => 10)
383
- };
511
+ test('should not throw when map is null', () => {
512
+ expect(() => OpenStreetMap.setZoom(null, 12)).not.toThrow();
513
+ });
514
+ });
384
515
 
385
- OpenStreetMap.centerMapToCoordinates(mockMap, -33.8688, 151.2093);
516
+ describe('setView', () => {
517
+ test('should call setView on map', () => {
518
+ const mockMap = createMockMap();
519
+ OpenStreetMap.setView(mockMap, [48.8566, 2.3522], 12);
520
+ expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 12);
521
+ });
386
522
 
387
- expect(mockMap.setView).toHaveBeenCalledWith([-33.8688, 151.2093], 15);
523
+ test('should not throw when map is null', () => {
524
+ expect(() => OpenStreetMap.setView(null, [0, 0], 10)).not.toThrow();
388
525
  });
389
526
  });
390
527
 
391
- describe('centerMapToLocations', () => {
392
- test('should call fitBounds with location bounds', () => {
393
- const mockMap = {
394
- invalidateSize: jest.fn(),
395
- fitBounds: jest.fn(),
396
- getZoom: jest.fn(() => 12),
397
- setZoom: jest.fn()
398
- };
528
+ describe('addMarker', () => {
529
+ let mockMarker;
399
530
 
400
- const locations = [[48.8566, 2.3522], [48.8606, 2.3376]];
401
- const mockBounds = { _bounds: locations };
402
- const latLngBoundsSpy = jest.spyOn(L, 'latLngBounds').mockReturnValue(mockBounds);
531
+ beforeEach(() => {
532
+ mockMarker = createMockMarker();
533
+ jest.spyOn(L, 'marker').mockReturnValue(mockMarker);
534
+ jest.spyOn(L, 'icon').mockReturnValue({});
535
+ });
403
536
 
404
- OpenStreetMap.centerMapToLocations(mockMap, locations);
537
+ afterEach(() => jest.restoreAllMocks());
405
538
 
406
- expect(mockMap.invalidateSize).toHaveBeenCalledWith(false);
407
- expect(latLngBoundsSpy).toHaveBeenCalledWith(locations);
408
- expect(mockMap.fitBounds).toHaveBeenCalled();
539
+ test('should return null when map is null', () => {
540
+ expect(OpenStreetMap.addMarker(null, '48.8566,2.3522', {})).toBeNull();
541
+ });
409
542
 
410
- latLngBoundsSpy.mockRestore();
543
+ test('should create marker at parsed coordinates', () => {
544
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', {});
545
+ expect(L.marker).toHaveBeenCalledWith([48.8566, 2.3522], expect.any(Object));
411
546
  });
412
547
 
413
- test('should not do anything when map is null', () => {
414
- const mockMap = {
415
- invalidateSize: jest.fn(),
416
- fitBounds: jest.fn()
417
- };
548
+ test('should set icon when provided', () => {
549
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', { icon: '/img/marker.png' });
550
+ expect(L.icon).toHaveBeenCalledWith({ iconUrl: '/img/marker.png', iconSize: [22, 32] });
551
+ });
418
552
 
419
- OpenStreetMap.centerMapToLocations(null, [[48.8566, 2.3522]]);
553
+ test('should not set icon when not provided', () => {
554
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', {});
555
+ expect(L.icon).not.toHaveBeenCalled();
556
+ });
420
557
 
421
- expect(mockMap.invalidateSize).not.toHaveBeenCalled();
558
+ test('should set title when provided', () => {
559
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', { title: 'Test' });
560
+ expect(L.marker).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({ title: 'Test' }));
422
561
  });
423
562
 
424
- test('should not do anything when locations list is empty', () => {
425
- const mockMap = {
426
- invalidateSize: jest.fn(),
427
- fitBounds: jest.fn()
428
- };
563
+ test('should bind popup when provided', () => {
564
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', { popup: '<p>info</p>' });
565
+ expect(mockMarker.bindPopup).toHaveBeenCalledWith('<p>info</p>');
566
+ });
429
567
 
430
- OpenStreetMap.centerMapToLocations(mockMap, []);
568
+ test('should not bind popup when not provided', () => {
569
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', {});
570
+ expect(mockMarker.bindPopup).not.toHaveBeenCalled();
571
+ });
431
572
 
432
- expect(mockMap.invalidateSize).not.toHaveBeenCalled();
573
+ test('should add marker to map', () => {
574
+ const mockMap = createMockMap();
575
+ OpenStreetMap.addMarker(mockMap, '48.8566,2.3522', {});
576
+ expect(mockMarker.addTo).toHaveBeenCalledWith(mockMap);
433
577
  });
434
578
 
435
- test('should set zoom to maxZoom if current zoom exceeds it', () => {
436
- const mockMap = {
437
- invalidateSize: jest.fn(),
438
- fitBounds: jest.fn(),
439
- getZoom: jest.fn(() => 20),
440
- setZoom: jest.fn()
441
- };
579
+ test('should return the marker', () => {
580
+ expect(OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', {})).toBe(mockMarker);
581
+ });
442
582
 
443
- const locations = [[48.8566, 2.3522]];
444
- const latLngBoundsSpy = jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: locations });
583
+ test('should register popupopen when on_click is provided', () => {
584
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', { on_click: jest.fn() });
585
+ expect(mockMarker.on).toHaveBeenCalledWith('popupopen', expect.any(Function));
586
+ });
445
587
 
446
- OpenStreetMap.centerMapToLocations(mockMap, locations, [20, 20], 18);
588
+ test('should not register popupopen when no callbacks provided', () => {
589
+ OpenStreetMap.addMarker(createMockMap(), '48.8566,2.3522', {});
590
+ expect(mockMarker.on).not.toHaveBeenCalled();
591
+ });
592
+ });
447
593
 
448
- expect(mockMap.setZoom).toHaveBeenCalledWith(18);
594
+ describe('addMarkers', () => {
595
+ beforeEach(() => {
596
+ jest.spyOn(L, 'marker').mockReturnValue(createMockMarker());
597
+ jest.spyOn(L, 'icon').mockReturnValue({});
598
+ });
599
+
600
+ afterEach(() => jest.restoreAllMocks());
449
601
 
450
- latLngBoundsSpy.mockRestore();
602
+ test('should return empty array when map is null', () => {
603
+ expect(OpenStreetMap.addMarkers(null, ['48.8566,2.3522'], {})).toEqual([]);
451
604
  });
452
605
 
453
- test('should use custom padding', () => {
454
- const mockMap = {
455
- invalidateSize: jest.fn(),
456
- fitBounds: jest.fn(),
457
- getZoom: jest.fn(() => 12),
458
- setZoom: jest.fn()
459
- };
606
+ test('should return empty array when list is empty', () => {
607
+ expect(OpenStreetMap.addMarkers(createMockMap(), [], {})).toEqual([]);
608
+ });
609
+
610
+ test('should return one marker per location', () => {
611
+ const result = OpenStreetMap.addMarkers(createMockMap(), ['48.8566,2.3522', '48.86,2.35'], {});
612
+ expect(result).toHaveLength(2);
613
+ });
614
+ });
615
+
616
+ describe('connectMarkers', () => {
617
+ let mockPolyline;
618
+
619
+ beforeEach(() => {
620
+ mockPolyline = { addTo: jest.fn() };
621
+ jest.spyOn(L, 'polyline').mockReturnValue(mockPolyline);
622
+ });
460
623
 
461
- const locations = [[48.8566, 2.3522]];
462
- const latLngBoundsSpy = jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: locations });
624
+ afterEach(() => jest.restoreAllMocks());
463
625
 
464
- OpenStreetMap.centerMapToLocations(mockMap, locations, [50, 50]);
626
+ test('should not draw when locations is empty', () => {
627
+ OpenStreetMap.connectMarkers(createMockMap(), []);
628
+ expect(L.polyline).not.toHaveBeenCalled();
629
+ });
630
+
631
+ test('should not draw when map is null', () => {
632
+ OpenStreetMap.connectMarkers(null, [[0, 0], [1, 1]]);
633
+ expect(L.polyline).not.toHaveBeenCalled();
634
+ });
465
635
 
466
- expect(mockMap.fitBounds).toHaveBeenCalledWith(
467
- expect.anything(),
468
- { padding: [50, 50] }
469
- );
636
+ test('should not draw with only one location', () => {
637
+ OpenStreetMap.connectMarkers(createMockMap(), [[0, 0]]);
638
+ expect(L.polyline).not.toHaveBeenCalled();
639
+ });
470
640
 
471
- latLngBoundsSpy.mockRestore();
641
+ test('should draw n-1 polylines for n locations', () => {
642
+ OpenStreetMap.connectMarkers(createMockMap(), [[0, 0], [1, 1], [2, 2]]);
643
+ expect(L.polyline).toHaveBeenCalledTimes(2);
472
644
  });
473
645
  });
646
+ });
647
+
648
+ describe('OsmMap', () => {
649
+ let mockMap;
650
+
651
+ beforeEach(() => {
652
+ mockMap = createMockMap();
653
+ jest.spyOn(L.DomUtil, 'get').mockReturnValue(null);
654
+ jest.spyOn(L, 'map').mockReturnValue(mockMap);
655
+ jest.spyOn(L, 'tileLayer').mockReturnValue({ addTo: jest.fn() });
656
+ jest.spyOn(L, 'latLngBounds').mockReturnValue({ _bounds: [] });
657
+ });
658
+
659
+ afterEach(() => jest.restoreAllMocks());
660
+
661
+ function makeOsmMap() {
662
+ const div = document.createElement('div');
663
+ document.body.appendChild(div);
664
+ const osmMap = new OsmMap(div);
665
+ document.body.removeChild(div);
666
+ return osmMap;
667
+ }
668
+
669
+ test('constructor initializes markers, locations, tempSelection, tempLayer', () => {
670
+ const osmMap = makeOsmMap();
671
+ expect(osmMap.markers).toEqual([]);
672
+ expect(osmMap.locations).toEqual([]);
673
+ expect(osmMap.tempSelection).toBeNull();
674
+ expect(osmMap.tempLayer).toBeNull();
675
+ expect(osmMap.map).toBe(mockMap);
676
+ });
677
+
678
+ test('setZoom delegates to map', () => {
679
+ makeOsmMap().setZoom(12);
680
+ expect(mockMap.setZoom).toHaveBeenCalledWith(12);
681
+ });
682
+
683
+ test('deleteMarkers clears markers and locations', () => {
684
+ const osmMap = makeOsmMap();
685
+ osmMap.markers.push({});
686
+ osmMap.locations.push([0, 0]);
687
+ osmMap.deleteMarkers();
688
+ expect(osmMap.markers).toHaveLength(0);
689
+ expect(osmMap.locations).toHaveLength(0);
690
+ });
691
+
692
+ test('clearSelections calls eachLayer on map', () => {
693
+ mockMap.eachLayer = jest.fn();
694
+ makeOsmMap().clearSelections();
695
+ expect(mockMap.eachLayer).toHaveBeenCalled();
696
+ });
697
+
698
+ test('addTempMarker sets tempLayer', () => {
699
+ const mockTempMarker = { on: jest.fn() };
700
+ jest.spyOn(L, 'marker').mockReturnValue(mockTempMarker);
701
+
702
+ const osmMap = makeOsmMap();
703
+ osmMap.addTempMarker(48.8566, 2.3522);
704
+
705
+ expect(osmMap.tempLayer).toBe(mockTempMarker);
706
+ });
707
+
708
+ test('addTempMarker updates tempSelection on dragend', () => {
709
+ let dragEndHandler;
710
+ const mockTempMarker = {
711
+ on: jest.fn((e, h) => { dragEndHandler = h; }),
712
+ getLatLng: jest.fn(() => ({ lat: 48.86, lng: 2.35 })),
713
+ };
714
+ jest.spyOn(L, 'marker').mockReturnValue(mockTempMarker);
715
+
716
+ const osmMap = makeOsmMap();
717
+ osmMap.addTempMarker(48.8566, 2.3522);
718
+ dragEndHandler({ target: mockTempMarker });
719
+
720
+ expect(osmMap.tempSelection).toEqual({ type: 'point', lat: 48.86, long: 2.35 });
721
+ });
722
+
723
+ test('resetTempSelection removes tempLayer and resets state', () => {
724
+ const osmMap = makeOsmMap();
725
+ const mockLayer = {};
726
+ osmMap.tempLayer = mockLayer;
727
+ osmMap.tempSelection = { type: 'point', lat: 1, long: 2 };
728
+
729
+ osmMap.resetTempSelection();
730
+
731
+ expect(mockMap.removeLayer).toHaveBeenCalledWith(mockLayer);
732
+ expect(osmMap.tempLayer).toBeNull();
733
+ expect(osmMap.tempSelection).toBeNull();
734
+ });
735
+
736
+ test('addMarker pushes to markers and locations', () => {
737
+ const mockMarker = createMockMarker(48.8566, 2.3522);
738
+ jest.spyOn(L, 'marker').mockReturnValue(mockMarker);
739
+ jest.spyOn(L, 'icon').mockReturnValue({});
740
+
741
+ const osmMap = makeOsmMap();
742
+ osmMap.addMarker('48.8566,2.3522', {});
743
+
744
+ expect(osmMap.markers).toHaveLength(1);
745
+ expect(osmMap.locations).toEqual([[48.8566, 2.3522]]);
746
+ });
747
+
748
+ test('addMarker does nothing when map is null', () => {
749
+ const osmMap = makeOsmMap();
750
+ osmMap.map = null;
751
+ osmMap.addMarker('48.8566,2.3522', {});
752
+ expect(osmMap.markers).toHaveLength(0);
753
+ });
754
+
755
+ test('addMarkers pushes all markers to markers and locations', () => {
756
+ jest.spyOn(L, 'marker').mockReturnValue(createMockMarker());
757
+ jest.spyOn(L, 'icon').mockReturnValue({});
758
+
759
+ const osmMap = makeOsmMap();
760
+ osmMap.addMarkers(['48.8566,2.3522', '48.86,2.35'], {});
761
+
762
+ expect(osmMap.markers).toHaveLength(2);
763
+ expect(osmMap.locations).toHaveLength(2);
764
+ });
765
+
766
+ test('setView delegates to map', () => {
767
+ makeOsmMap().setView([48.8566, 2.3522], 10);
768
+ expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 10);
769
+ });
770
+
771
+ test('centerOnFrance calls setView with France coords', () => {
772
+ makeOsmMap().centerOnFrance();
773
+ expect(mockMap.setView).toHaveBeenCalledWith([46.52863469527167, 2.43896484375], 6);
774
+ });
775
+
776
+ test('centerOnCountry calls fitBounds for known country', () => {
777
+ makeOsmMap().centerOnCountry('FR');
778
+ expect(mockMap.fitBounds).toHaveBeenCalled();
779
+ });
780
+
781
+ test('centerOnMarkers calls fitBounds with locations', () => {
782
+ const osmMap = makeOsmMap();
783
+ osmMap.locations = [[48.8566, 2.3522]];
784
+ osmMap.centerOnMarkers([20, 20]);
785
+ expect(mockMap.invalidateSize).toHaveBeenCalled();
786
+ expect(mockMap.fitBounds).toHaveBeenCalled();
787
+ });
788
+
789
+ test('centerOnGooglePlace calls setView with place coords', () => {
790
+ const place = { geometry: { location: { lat: () => 48.8566, lng: () => 2.3522 } } };
791
+ makeOsmMap().centerOnGooglePlace(place);
792
+ expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 15);
793
+ });
794
+
795
+ test('centerOnCoordinates calls setView', () => {
796
+ makeOsmMap().centerOnCoordinates(48.8566, 2.3522);
797
+ expect(mockMap.setView).toHaveBeenCalledWith([48.8566, 2.3522], 15);
798
+ });
799
+
800
+ test('connectMarkers draws polylines between locations', () => {
801
+ jest.spyOn(L, 'polyline').mockReturnValue({ addTo: jest.fn() });
802
+
803
+ const osmMap = makeOsmMap();
804
+ osmMap.locations = [[0, 0], [1, 1], [2, 2]];
805
+ osmMap.connectMarkers();
806
+
807
+ expect(L.polyline).toHaveBeenCalledTimes(2);
808
+ });
809
+
810
+ test('destroyMap calls off and remove', () => {
811
+ makeOsmMap().destroyMap();
812
+ expect(mockMap.off).toHaveBeenCalled();
813
+ expect(mockMap.remove).toHaveBeenCalled();
814
+ });
474
815
  });