@masterportal/masterportalapi 2.63.0 → 2.64.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.
@@ -0,0 +1,257 @@
1
+ import Feature from "ol/Feature.js";
2
+ import {Point, LineString, Polygon} from "ol/geom.js";
3
+ import {KML} from "ol/format.js";
4
+ import proj4 from "proj4";
5
+ import {register} from "ol/proj/proj4.js";
6
+ import kmlExport from "../../src/shared/kmlExport";
7
+
8
+ // Register projection used in tests
9
+ proj4.defs("EPSG:25832", "+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");
10
+ register(proj4);
11
+
12
+ describe("src/shared/kmlExport.js", () => {
13
+ describe("transformCoordinates", () => {
14
+ it("transforms a Point geometry", () => {
15
+ const geometry = new Point([565874, 5934140]),
16
+ result = kmlExport.transformCoordinates(geometry, "EPSG:25832");
17
+
18
+ expect(result).toHaveLength(2);
19
+ expect(typeof result[0]).toBe("number");
20
+ expect(typeof result[1]).toBe("number");
21
+ });
22
+
23
+ it("transforms a LineString geometry", () => {
24
+ const geometry = new LineString([[565874, 5934140], [566000, 5934200]]),
25
+ result = kmlExport.transformCoordinates(geometry, "EPSG:25832");
26
+
27
+ expect(result).toHaveLength(2);
28
+ result.forEach(point => {
29
+ expect(point).toHaveLength(2);
30
+ expect(typeof point[0]).toBe("number");
31
+ expect(typeof point[1]).toBe("number");
32
+ });
33
+ });
34
+
35
+ it("transforms a Polygon geometry", () => {
36
+ const geometry = new Polygon([[[565874, 5934140], [566000, 5934200], [566100, 5934100], [565874, 5934140]]]),
37
+ result = kmlExport.transformCoordinates(geometry, "EPSG:25832");
38
+
39
+ expect(Array.isArray(result)).toBe(true);
40
+ expect(result).toHaveLength(1);
41
+ expect(result[0].length).toBeGreaterThanOrEqual(4);
42
+ });
43
+
44
+ it("returns coordinates unchanged for MultiPolygon", () => {
45
+ const coords = [[[[0, 0], [1, 0], [1, 1], [0, 0]]]],
46
+ geometry = {
47
+ getCoordinates: () => coords,
48
+ getType: () => "MultiPolygon"
49
+ },
50
+ result = kmlExport.transformCoordinates(geometry);
51
+
52
+ expect(result).toEqual(coords);
53
+ });
54
+
55
+ it("returns an empty array for unsupported geometry types", () => {
56
+ const geometry = {
57
+ getCoordinates: () => [],
58
+ getType: () => "GeometryCollection"
59
+ };
60
+
61
+ expect(kmlExport.transformCoordinates(geometry)).toEqual([]);
62
+ });
63
+ });
64
+
65
+ describe("convertFeatures", () => {
66
+ it("converts Point features to a KML string", () => {
67
+ const feature = new Feature({geometry: new Point([565874, 5934140])}),
68
+ format = new KML({extractStyles: true}),
69
+ result = kmlExport.convertFeatures([feature], format, "EPSG:25832");
70
+
71
+ expect(typeof result).toBe("string");
72
+ expect(result).toContain("Point");
73
+ expect(result).toContain("coordinates");
74
+ });
75
+
76
+ it("converts LineString features to a KML string", () => {
77
+ const feature = new Feature({geometry: new LineString([[565874, 5934140], [566000, 5934200]])}),
78
+ format = new KML({extractStyles: true}),
79
+ result = kmlExport.convertFeatures([feature], format, "EPSG:25832");
80
+
81
+ expect(typeof result).toBe("string");
82
+ expect(result).toContain("LineString");
83
+ });
84
+
85
+ it("converts multiple features to KML", () => {
86
+ const features = [
87
+ new Feature({geometry: new Point([565874, 5934140])}),
88
+ new Feature({geometry: new LineString([[565874, 5934140], [566000, 5934200]])})
89
+ ],
90
+ format = new KML({extractStyles: true}),
91
+ result = kmlExport.convertFeatures(features, format, "EPSG:25832");
92
+
93
+ expect(result).toContain("Point");
94
+ expect(result).toContain("LineString");
95
+ });
96
+
97
+ it("removes trailing zero from 3D point coordinates", () => {
98
+ const feature = new Feature({geometry: new Point([565874, 5934140, 0])}),
99
+ format = new KML({extractStyles: true}),
100
+ result = kmlExport.convertFeatures([feature], format, "EPSG:25832"),
101
+ // KML coordinates are lon,lat,alt - check it doesn't contain a trailing ,0
102
+ coordMatch = result.match(/<coordinates>([\s\S]*?)<\/coordinates>/);
103
+
104
+ expect(coordMatch).not.toBeNull();
105
+ // The coordinate should have been transformed and not have trailing 0
106
+ const coordParts = coordMatch[1].trim().split(",");
107
+
108
+ expect(coordParts).toHaveLength(2);
109
+ });
110
+ });
111
+
112
+ describe("getKMLWithCustomAttributes", () => {
113
+ it("returns null if features is not an array", () => {
114
+ const format = new KML({extractStyles: true});
115
+
116
+ expect(kmlExport.getKMLWithCustomAttributes(undefined, format)).toBeNull();
117
+ expect(kmlExport.getKMLWithCustomAttributes(null, format)).toBeNull();
118
+ expect(kmlExport.getKMLWithCustomAttributes("string", format)).toBeNull();
119
+ });
120
+
121
+ it("returns null if format is not an object", () => {
122
+ const features = [new Feature({geometry: new Point([10, 53])})];
123
+
124
+ expect(kmlExport.getKMLWithCustomAttributes(features, null)).toBeNull();
125
+ expect(kmlExport.getKMLWithCustomAttributes(features, undefined)).toBeNull();
126
+ });
127
+
128
+ it("returns null if no features have attributes", () => {
129
+ const feature = new Feature({geometry: new Point([10, 53])}),
130
+ format = new KML({extractStyles: true});
131
+
132
+ expect(kmlExport.getKMLWithCustomAttributes([feature], format)).toBeNull();
133
+ });
134
+
135
+ it("returns a KML document when features have attributes", () => {
136
+ const feature = new Feature({geometry: new Point([10, 53]), category: "test"});
137
+
138
+ feature.set("attributes", {category: "test"});
139
+ const format = new KML({extractStyles: true}),
140
+ result = kmlExport.getKMLWithCustomAttributes([feature], format);
141
+
142
+ expect(result).not.toBeNull();
143
+ expect(result.getElementsByTagName("Placemark").length).toBe(1);
144
+ });
145
+ });
146
+
147
+ describe("setKmlAttributes", () => {
148
+ it("returns false if features is not an array", () => {
149
+ expect(kmlExport.setKmlAttributes(undefined)).toBe(false);
150
+ expect(kmlExport.setKmlAttributes(null)).toBe(false);
151
+ expect(kmlExport.setKmlAttributes("string")).toBe(false);
152
+ expect(kmlExport.setKmlAttributes({})).toBe(false);
153
+ expect(kmlExport.setKmlAttributes(123)).toBe(false);
154
+ });
155
+
156
+ it("sets attributes property on features that don't already have it", () => {
157
+ const feature = new Feature({
158
+ geometry: new Point([565874, 5934140]),
159
+ name: "testFeature",
160
+ category: "example"
161
+ });
162
+
163
+ kmlExport.setKmlAttributes([feature]);
164
+
165
+ expect(feature.get("attributes")).toBeDefined();
166
+ expect(feature.get("attributes").name).toBe("testFeature");
167
+ expect(feature.get("attributes").category).toBe("example");
168
+ });
169
+
170
+ it("does not overwrite existing attributes property", () => {
171
+ const feature = new Feature({geometry: new Point([565874, 5934140])});
172
+
173
+ feature.set("attributes", {existing: "value"});
174
+ kmlExport.setKmlAttributes([feature]);
175
+
176
+ expect(feature.get("attributes").existing).toBe("value");
177
+ });
178
+
179
+ it("does not include reserved properties in attributes", () => {
180
+ const feature = new Feature({geometry: new Point([565874, 5934140])});
181
+
182
+ feature.set("masterportal_attributes", {mpKey: "mpValue"});
183
+ kmlExport.setKmlAttributes([feature]);
184
+
185
+ expect(feature.get("attributes").masterportal_attributes).toBeUndefined();
186
+ expect(feature.get("attributes").geometry).toBeUndefined();
187
+ });
188
+
189
+ it("promotes masterportal_attributes keys to feature-level properties", () => {
190
+ const feature = new Feature({geometry: new Point([565874, 5934140])});
191
+
192
+ feature.set("masterportal_attributes", {isGeoCircle: true, geoCircleRadius: 50});
193
+ kmlExport.setKmlAttributes([feature]);
194
+
195
+ expect(feature.get("isGeoCircle")).toBe(true);
196
+ expect(feature.get("geoCircleRadius")).toBe(50);
197
+ });
198
+
199
+ it("serializes drawState when promoting masterportal_attributes", () => {
200
+ const drawState = {
201
+ drawType: {id: "drawPolygon", geometry: "Polygon"},
202
+ strokeWidth: 4,
203
+ color: [12, 34, 56, 0.7]
204
+ },
205
+ feature = new Feature({geometry: new Point([565874, 5934140])});
206
+
207
+ feature.set("masterportal_attributes", {drawState});
208
+ kmlExport.setKmlAttributes([feature]);
209
+
210
+ expect(feature.get("drawState")).toBe(JSON.stringify(drawState));
211
+ });
212
+
213
+ it("returns the features array on success", () => {
214
+ const features = [new Feature({geometry: new Point([565874, 5934140])})],
215
+ result = kmlExport.setKmlAttributes(features);
216
+
217
+ expect(result).toBe(features);
218
+ });
219
+
220
+ it("skips non-Feature items in the array", () => {
221
+ const feature = new Feature({geometry: new Point([565874, 5934140]), name: "valid"}),
222
+ result = kmlExport.setKmlAttributes([feature, "not a feature", null]);
223
+
224
+ expect(result).toHaveLength(3);
225
+ expect(feature.get("attributes").name).toBe("valid");
226
+ });
227
+ });
228
+
229
+ describe("convertFeaturesToKml", () => {
230
+ it("returns a KML string for LineString features", () => {
231
+ const feature = new Feature({geometry: new LineString([[565874, 5934140], [566000, 5934200]])});
232
+
233
+ return kmlExport.convertFeaturesToKml([feature], "EPSG:25832").then(result => {
234
+ expect(typeof result).toBe("string");
235
+ expect(result).toContain("LineString");
236
+ });
237
+ });
238
+
239
+ it("returns a KML string for Polygon features", () => {
240
+ const feature = new Feature({geometry: new Polygon([[[565874, 5934140], [566000, 5934200], [566100, 5934100], [565874, 5934140]]])});
241
+
242
+ return kmlExport.convertFeaturesToKml([feature], "EPSG:25832").then(result => {
243
+ expect(typeof result).toBe("string");
244
+ expect(result).toContain("Polygon");
245
+ });
246
+ });
247
+
248
+ it("handles features without style functions gracefully", () => {
249
+ const feature = new Feature({geometry: new LineString([[565874, 5934140], [566000, 5934200]])});
250
+
251
+ return kmlExport.convertFeaturesToKml([feature], "EPSG:25832").then(result => {
252
+ expect(typeof result).toBe("string");
253
+ expect(result).toContain("kml");
254
+ });
255
+ });
256
+ });
257
+ });
@@ -0,0 +1,35 @@
1
+ import {isObject, getProjections, transformPoint} from "../../src/shared/utils";
2
+
3
+ describe("src/shared/utils.js", () => {
4
+ describe("isObject", () => {
5
+ it("returns true only for plain objects", () => {
6
+ expect(isObject({a: 1})).toBe(true);
7
+ expect(isObject([])).toBe(false);
8
+ expect(isObject(null)).toBe(false);
9
+ expect(isObject("text")).toBe(false);
10
+ });
11
+ });
12
+
13
+ describe("getProjections", () => {
14
+ it("returns source and destination projections", () => {
15
+ const result = getProjections("EPSG:25832", "EPSG:4326", "32");
16
+
17
+ expect(result).toHaveProperty("sourceProj");
18
+ expect(result).toHaveProperty("destProj");
19
+ });
20
+ });
21
+
22
+ describe("transformPoint", () => {
23
+ it("returns a transformed lon-lat coordinate pair", () => {
24
+ const sourcePoint = [565826.38, 5934174.4],
25
+ transformed = transformPoint("EPSG:25832", sourcePoint);
26
+
27
+ expect(Array.isArray(transformed)).toBe(true);
28
+ expect(transformed).toHaveLength(2);
29
+ expect(Number.isFinite(transformed[0])).toBe(true);
30
+ expect(Number.isFinite(transformed[1])).toBe(true);
31
+ expect(transformed[0]).not.toBe(sourcePoint[0]);
32
+ expect(transformed[1]).not.toBe(sourcePoint[1]);
33
+ });
34
+ });
35
+ });