mapicgc-gl-js 1.0.2 → 1.0.4

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.
Files changed (44) hide show
  1. package/README.md +35 -1
  2. package/dist/chunk-efA98nb6-Dfm7IivL.mjs +13 -0
  3. package/dist/html2canvas-DhrjCa5K-zEqRDH-g.mjs +4024 -0
  4. package/dist/index.es-D_FsJY9H-CO3QIBGM.mjs +5741 -0
  5. package/dist/mapicgc-gl-js.css +2 -0
  6. package/dist/mapicgc-gl.css +1948 -1
  7. package/dist/mapicgc-gl.js +224 -440
  8. package/dist/mapicgc-gl.mjs +88138 -5
  9. package/dist/purify.es-DVGU85zV-CJOZ7ABI.mjs +549 -0
  10. package/dist/typeof-CTd55yxz-BxqQpTq1.mjs +11 -0
  11. package/dist/webgl-device-CDzrheIu.mjs +2 -0
  12. package/dist/webgl-device-DPB4IspV.mjs +5573 -0
  13. package/package.json +19 -20
  14. package/src/map/Map.js +65 -6
  15. package/test/exemples/addBasemap.html +1 -1
  16. package/test/exemples/addCompare.html +1 -1
  17. package/test/exemples/addControl.html +1 -1
  18. package/test/exemples/addFeatureQuery.html +1 -1
  19. package/test/exemples/addGeocoderICGC.html +1 -1
  20. package/test/exemples/addICGCTerrain.html +1 -1
  21. package/test/exemples/addICGCTerrainCustomStyle.html +1 -1
  22. package/test/exemples/addImageLayerICGC.html +1 -1
  23. package/test/exemples/addLayerGeojson.html +1 -1
  24. package/test/exemples/addLayerTree.html +1 -1
  25. package/test/exemples/addLogo.html +1 -1
  26. package/test/exemples/addMapStyle.html +8 -6
  27. package/test/exemples/addMarker.html +1 -1
  28. package/test/exemples/addMouseCoordinateControl.html +1 -1
  29. package/test/exemples/addReliefStyle.html +1 -1
  30. package/test/exemples/addVectorLayerICGC.html +1 -1
  31. package/test/exemples/advancedExemple.html +1 -1
  32. package/test/exemples/fetchData.html +1 -1
  33. package/test/exemples/fetchDataAndMenu.html +1 -1
  34. package/test/exemples/styleOrto3D.html +1 -1
  35. package/test/vitest/Config.test.js +145 -0
  36. package/test/vitest/MapFunctions.test.js +971 -0
  37. package/vite.config.mjs +7 -2
  38. package/dist/html2canvas.esm-Dmi1NfiH-AQaq32X6.mjs +0 -4534
  39. package/dist/index-DdkbNQVU.mjs +0 -83555
  40. package/dist/index.es-CDV9zB2B-CB-dpJjG.mjs +0 -6731
  41. package/dist/mapicgc-gl.umd.js +0 -4064
  42. package/dist/purify.es-DHbHSKL1-2rarU4M1.mjs +0 -480
  43. package/test/vitest/Map.test.js +0 -215
  44. package/test/vitest/MapStyle.test.js +0 -129
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "mapicgc-gl-js",
3
3
  "homepage": "https://openicgc.github.io/mapicgc-doc/",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
5
5
  "description": "mapicgc-gl-js library",
6
6
  "author": "Institut Cartogràfic i Geològic de Catalunya",
7
7
  "license": "BSD-3-Clause",
8
8
  "type": "commonjs",
9
-
10
9
  "keywords": [
11
10
  "map",
12
11
  "js",
@@ -43,34 +42,34 @@
43
42
  "test": "vitest"
44
43
  },
45
44
  "devDependencies": {
46
- "@babel/core": "^7.28.5",
47
- "@babel/preset-env": "^7.28.5",
48
- "@rollup/plugin-babel": "^6.1.0",
49
- "axios": "^1.13.1",
50
- "dotenv": "^17.2.3",
51
- "jest": "30.2.0",
45
+ "@babel/core": "^7.29.0",
46
+ "@babel/preset-env": "^7.29.2",
47
+ "@rollup/plugin-babel": "^7.0.0",
48
+ "axios": "^1.14.0",
49
+ "dotenv": "^17.3.1",
50
+ "jest": "30.3.0",
52
51
  "jsdoc": "^4.0.5",
53
- "jsdom": "^27.0.1",
52
+ "jsdom": "^29.0.1",
54
53
  "npm-run-all": "^4.1.5",
55
54
  "package-json-versionify": "^1.0.4",
56
55
  "path": "^0.12.7",
57
56
  "rollup-plugin-polyfill": "^4.2.0",
58
- "ssh2-sftp-client": "^12.0.1",
59
- "vite": "^7.1.12",
60
- "vite-plugin-node-polyfills": "^0.24.0",
61
- "vitest": "^4.0.5",
57
+ "ssh2-sftp-client": "^12.1.1",
58
+ "vite": "^8.0.3",
59
+ "vite-plugin-node-polyfills": "^0.26.0",
60
+ "vitest": "^4.1.2",
62
61
  "xml2js": "^0.6.2"
63
62
  },
64
63
  "dependencies": {
65
- "@deck.gl/core": "^9.2.2",
66
- "@deck.gl/geo-layers": "^9.2.2",
67
- "@deck.gl/mapbox": "^9.2.2",
64
+ "@deck.gl/core": "^9.2.11",
65
+ "@deck.gl/geo-layers": "^9.2.11",
66
+ "@deck.gl/mapbox": "^9.2.11",
68
67
  "@loaders.gl/3d-tiles": "~4.3.4",
69
68
  "@maplibre/maplibre-gl-compare": "^0.5.0",
70
- "@maplibre/maplibre-gl-geocoder": "^1.9.1",
71
- "@watergis/maplibre-gl-export": "^4.1.0",
72
- "flatgeobuf": "^4.3.1",
73
- "maplibre-gl": "^5.10.0",
69
+ "@maplibre/maplibre-gl-geocoder": "^1.9.4",
70
+ "@watergis/maplibre-gl-export": "^4.1.2",
71
+ "flatgeobuf": "^4.4.0",
72
+ "maplibre-gl": "^5.21.1",
74
73
  "utm-latlng": "^1.0.8"
75
74
  }
76
75
  }
package/src/map/Map.js CHANGED
@@ -178,6 +178,13 @@ export default class Map {
178
178
  }
179
179
 
180
180
  this.map.on("load", () => {
181
+ this.addAttributionControl()
182
+ setTimeout(() => {
183
+ const attribBtn = document.querySelector('.maplibregl-ctrl-attrib-button');
184
+ if (attribBtn) {
185
+ attribBtn.click();
186
+ }
187
+ }, 1000);
181
188
  if (!isRaster && !isRelief) {
182
189
  const nameStyle = this.map.getStyle().name;
183
190
  const urlName = options.style;
@@ -2846,14 +2853,61 @@ export default class Map {
2846
2853
  }
2847
2854
  }
2848
2855
  /**
2849
- * Adds an attribution control to the map with the provided options.
2856
+ * Adds an attribution control to the map. Always includes "Fet amb MapICGC" attribution by default.
2857
+ * If additional custom attributions are provided, they will be combined with the default one.
2850
2858
  * @function addAttributionControl
2851
- * @param {Object} options - Options for the attribution control.
2859
+ * @param {Object} [options] - Options for the attribution control.
2860
+ * @param {boolean} [options.compact=true] - If true, the attribution control will be compact.
2861
+ * @param {string|string[]} [options.customAttribution] - Additional custom attribution(s) to display alongside "Fet amb MapICGC".
2862
+ * @param {number} [options.autoCollapseDelay] - If set, the attribution will auto-collapse after this many milliseconds. E.g., 3000 for 3 seconds.
2852
2863
  * @param {string} [position='bottom-right'] - Position to add the control on the map.
2864
+ * @example
2865
+ * // Default usage: shows "Fet amb MapICGC" with compact mode
2866
+ * map.addAttributionControl();
2867
+ *
2868
+ * // With additional custom attribution
2869
+ * map.addAttributionControl({ customAttribution: '© El meu projecte' });
2870
+ *
2871
+ * // With multiple custom attributions
2872
+ * map.addAttributionControl({ customAttribution: ['© Projecte A', '© Projecte B'] });
2873
+ *
2874
+ * // With auto-collapse after 3 seconds
2875
+ * map.addAttributionControl({ autoCollapseDelay: 3000 });
2853
2876
  */
2854
2877
  addAttributionControl(options, position) {
2855
2878
  try {
2856
- this.map.addControl(new maplibregl.AttributionControl(options), position);
2879
+ const mapicgcAttribution = '<a style="font-weight: bold; color: #D97634;" href="https://www.icgc.cat/Eines-i-visors/Recursos-desenvolupadors/Biblioteca-MapICGC-GL-JS/" target="_blank">Fet amb MapICGC</a>';
2880
+ const mergedOptions = Object.assign({}, { compact: true }, options);
2881
+ const autoCollapseDelay = mergedOptions.autoCollapseDelay;
2882
+
2883
+ // Remove autoCollapseDelay from options before passing to AttributionControl
2884
+ delete mergedOptions.autoCollapseDelay;
2885
+
2886
+ if (mergedOptions.customAttribution) {
2887
+ if (Array.isArray(mergedOptions.customAttribution)) {
2888
+ if (!mergedOptions.customAttribution.includes(mapicgcAttribution)) {
2889
+ mergedOptions.customAttribution = [mapicgcAttribution, ...mergedOptions.customAttribution];
2890
+ }
2891
+ } else {
2892
+ if (mergedOptions.customAttribution !== mapicgcAttribution) {
2893
+ mergedOptions.customAttribution = [mapicgcAttribution, mergedOptions.customAttribution];
2894
+ }
2895
+ }
2896
+ } else {
2897
+ mergedOptions.customAttribution = mapicgcAttribution;
2898
+ }
2899
+
2900
+ this.map.addControl(new maplibregl.AttributionControl(mergedOptions), position);
2901
+
2902
+ // Auto-collapse after specified delay if autoCollapseDelay is set
2903
+ if (autoCollapseDelay && typeof autoCollapseDelay === 'number' && autoCollapseDelay > 0) {
2904
+ setTimeout(() => {
2905
+ const attributionButton = document.querySelector('.maplibregl-ctrl-attrib-button');
2906
+ if (attributionButton && attributionButton.getAttribute('aria-pressed') === 'true') {
2907
+ attributionButton.click();
2908
+ }
2909
+ }, autoCollapseDelay);
2910
+ }
2857
2911
  } catch (error) {
2858
2912
  console.error(`Error adding attribution control: ${error.message}`);
2859
2913
  }
@@ -3318,14 +3372,19 @@ export default class Map {
3318
3372
  const ambientLight = new AmbientLight({
3319
3373
  intensity: 4,
3320
3374
  });
3321
- const lightingEffect = new LightingEffect({
3322
- ambientLight,
3323
- });
3375
+
3376
+ if (this.map.getTerrain()) this.map.setTerrain(null);
3324
3377
  this.map.setTerrain({
3325
3378
  source: defaultOptions.map3dOptions.terrainSource,
3326
3379
  exaggeration: defaultOptions.map3dOptions.exaggeration,
3327
3380
  });
3328
3381
 
3382
+ const lightingEffect = new LightingEffect({
3383
+ ambientLight,
3384
+ });
3385
+
3386
+
3387
+
3329
3388
  citiesMapboxLayer = new MapboxOverlay({
3330
3389
  interleaved: true,
3331
3390
  layers: [this._createCitiesMapboxLayer(false)], // Inicialment invisible
@@ -5,7 +5,7 @@
5
5
  <title>Exemple mapicgc-gl-js: Afegir mapa base ICGC</title>
6
6
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
7
7
 
8
- <script src="../../dist/mapicgc-gl.umd.js"></script>
8
+ <script src="../../dist/mapicgc-gl.js"></script>
9
9
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
10
10
 
11
11
  <style>
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <title>Exemple mapicgc-gl-js: Afegir comparador</title>
6
6
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
 
10
10
  <style>
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>test mapicgc-gl-js</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
 
10
10
  <style>
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>test mapicgc-gl-js</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
 
10
10
  <style>
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>addGeocoderICGC.html</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>addICGCTerrain.html</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>addICGCTerrain.html</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>test mapicgc-gl-js</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>addLayerGeojson.html</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>addLayerTree</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>addLogo</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>addMapStyle</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -39,13 +39,15 @@
39
39
 
40
40
  map.on("load", () => {
41
41
  map.flyTo({
42
- center: [2.812786, 41.98559],
43
- zoom: 14,
42
+ center: [2.812786, 41.98559],
43
+ zoom: 14,
44
+ });
44
45
 
45
- });
46
-
47
- });
46
+
47
+ });
48
48
  }
49
+
50
+
49
51
  initMap();
50
52
  </script>
51
53
  </body>
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>addMarker</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>addMouseCoordinateControl</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>addICGCTerrain.html</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>addVectorLayerICGC</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>advancedExemple</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>fetchData</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -3,7 +3,7 @@
3
3
  <meta charset='utf-8' />
4
4
  <title>test mapicgc-gl-js</title>
5
5
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
6
- <script src="../../dist/mapicgc-gl.umd.js"></script>
6
+ <script src="../../dist/mapicgc-gl.js"></script>
7
7
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
8
8
  <style>
9
9
  body {
@@ -4,7 +4,7 @@
4
4
  <meta charset='utf-8' />
5
5
  <title>styleOrto3D</title>
6
6
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
7
- <script src="../../dist/mapicgc-gl.umd.js"></script>
7
+ <script src="../../dist/mapicgc-gl.js"></script>
8
8
  <link href="../../dist/mapicgc-gl.css" rel="stylesheet" />
9
9
  <style>
10
10
  body {
@@ -0,0 +1,145 @@
1
+ import { describe, expect, test, vi, beforeEach } from 'vitest';
2
+
3
+ // Mock axios before importing Config
4
+ vi.mock('axios', () => ({
5
+ default: {
6
+ get: vi.fn(),
7
+ },
8
+ }));
9
+
10
+ import axios from 'axios';
11
+ import mapicgcConfig from '../../src/mapicgc-config.json';
12
+
13
+ // Import Config after mocking axios
14
+ import Config from '../../src/constants/ConfigICGC.js';
15
+
16
+ describe('ConfigICGC', () => {
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+
21
+ test('should export a Config class with getConfigICGC static method', () => {
22
+ expect(Config).toBeDefined();
23
+ expect(typeof Config.getConfigICGC).toBe('function');
24
+ });
25
+
26
+ test('should return remote config data when API responds successfully', async () => {
27
+ const mockRemoteConfig = {
28
+ Styles: { TOPO: 'https://example.com/topo.json' },
29
+ Layers: { WMS: {} },
30
+ Terrains: {},
31
+ defaultOptions: { mapOptions: {} },
32
+ };
33
+
34
+ axios.get.mockResolvedValueOnce({ data: mockRemoteConfig });
35
+
36
+ const result = await Config.getConfigICGC();
37
+
38
+ expect(axios.get).toHaveBeenCalledTimes(1);
39
+ expect(axios.get).toHaveBeenCalledWith(
40
+ 'https://eines.icgc.cat/recursos/mapicgc-gl-js/mapicgc-config.json',
41
+ { timeout: 5000 }
42
+ );
43
+ expect(result).toEqual(mockRemoteConfig);
44
+ });
45
+
46
+ test('should return local mapicgc-config.json when API returns empty data', async () => {
47
+ axios.get.mockResolvedValueOnce({ data: null });
48
+
49
+ const result = await Config.getConfigICGC();
50
+
51
+ expect(result).toEqual(mapicgcConfig);
52
+ });
53
+
54
+ test('should return local mapicgc-config.json when API call fails with network error', async () => {
55
+ axios.get.mockRejectedValueOnce(new Error('Network Error'));
56
+
57
+ const result = await Config.getConfigICGC();
58
+
59
+ expect(result).toEqual(mapicgcConfig);
60
+ });
61
+
62
+ test('should return local mapicgc-config.json when API returns HTTP error', async () => {
63
+ const httpError = new Error('Request failed');
64
+ httpError.response = { data: 'Not Found', status: 404 };
65
+ axios.get.mockRejectedValueOnce(httpError);
66
+
67
+ const result = await Config.getConfigICGC();
68
+
69
+ expect(result).toEqual(mapicgcConfig);
70
+ });
71
+
72
+ test('should return local mapicgc-config.json when server does not respond (timeout)', async () => {
73
+ const timeoutError = new Error('Timeout');
74
+ timeoutError.request = {};
75
+ axios.get.mockRejectedValueOnce(timeoutError);
76
+
77
+ const result = await Config.getConfigICGC();
78
+
79
+ expect(result).toEqual(mapicgcConfig);
80
+ });
81
+ });
82
+
83
+ describe('mapicgc-config.json structure', () => {
84
+ test('should have defaultOptions with mapOptions', () => {
85
+ expect(mapicgcConfig.defaultOptions).toBeDefined();
86
+ expect(mapicgcConfig.defaultOptions.mapOptions).toBeDefined();
87
+ });
88
+
89
+ test('should have mapOptions with required fields', () => {
90
+ const mapOpts = mapicgcConfig.defaultOptions.mapOptions;
91
+ expect(mapOpts.container).toBeDefined();
92
+ expect(mapOpts.center).toBeDefined();
93
+ expect(mapOpts.zoom).toBeDefined();
94
+ expect(mapOpts.style).toBeDefined();
95
+ expect(mapOpts.maxZoom).toBeDefined();
96
+ });
97
+
98
+ test('should have center coordinates for Catalonia', () => {
99
+ const center = mapicgcConfig.defaultOptions.mapOptions.center;
100
+ // Catalonia approx: lon 0.15-3.33, lat 40.5-42.9
101
+ const lon = center['0'] || center[0];
102
+ const lat = center['1'] || center[1];
103
+ expect(lon).toBeGreaterThan(0);
104
+ expect(lon).toBeLessThan(4);
105
+ expect(lat).toBeGreaterThan(40);
106
+ expect(lat).toBeLessThan(43);
107
+ });
108
+
109
+ test('should have Styles configuration', () => {
110
+ expect(mapicgcConfig.Styles).toBeDefined();
111
+ expect(Array.isArray(mapicgcConfig.Styles) || typeof mapicgcConfig.Styles === 'object').toBe(true);
112
+ });
113
+
114
+ test('should have Layers configuration with WMS, Orto, Vector', () => {
115
+ expect(mapicgcConfig.Layers).toBeDefined();
116
+ expect(mapicgcConfig.Layers.WMS).toBeDefined();
117
+ expect(mapicgcConfig.Layers.Orto).toBeDefined();
118
+ expect(mapicgcConfig.Layers.Vector).toBeDefined();
119
+ });
120
+
121
+ test('should have Terrains configuration', () => {
122
+ expect(mapicgcConfig.Terrains).toBeDefined();
123
+ });
124
+
125
+ test('should have geocoder config with pelias URLs', () => {
126
+ const geocoder = mapicgcConfig.defaultOptions.geocoder;
127
+ expect(geocoder).toBeDefined();
128
+ expect(geocoder.peliasUrl1).toBeDefined();
129
+ expect(geocoder.peliasUrl1).toContain('icgc.cat');
130
+ });
131
+
132
+ test('should have logo ICGC options', () => {
133
+ const logo = mapicgcConfig.defaultOptions.logoIcgcOptions;
134
+ expect(logo).toBeDefined();
135
+ expect(logo.logoUrlColor).toBeDefined();
136
+ expect(logo.logoLink).toContain('icgc.cat');
137
+ });
138
+
139
+ test('should have map3d options', () => {
140
+ const opts3d = mapicgcConfig.defaultOptions.map3dOptions;
141
+ expect(opts3d).toBeDefined();
142
+ expect(opts3d.exaggeration).toBeDefined();
143
+ expect(opts3d.terrainSource).toBeDefined();
144
+ });
145
+ });