@geospatial-sdk/core 0.0.5-alpha.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.
Files changed (43) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +11 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +3 -0
  6. package/dist/model/index.d.ts +3 -0
  7. package/dist/model/index.d.ts.map +1 -0
  8. package/dist/model/index.js +2 -0
  9. package/dist/model/map-context-diff.d.ts +35 -0
  10. package/dist/model/map-context-diff.d.ts.map +1 -0
  11. package/dist/model/map-context-diff.js +1 -0
  12. package/dist/model/map-context.d.ts +82 -0
  13. package/dist/model/map-context.d.ts.map +1 -0
  14. package/dist/model/map-context.js +1 -0
  15. package/dist/utils/freeze.d.ts +2 -0
  16. package/dist/utils/freeze.d.ts.map +1 -0
  17. package/dist/utils/freeze.js +15 -0
  18. package/dist/utils/index.d.ts +5 -0
  19. package/dist/utils/index.d.ts.map +1 -0
  20. package/dist/utils/index.js +4 -0
  21. package/dist/utils/map-context-diff.d.ts +22 -0
  22. package/dist/utils/map-context-diff.d.ts.map +1 -0
  23. package/dist/utils/map-context-diff.js +79 -0
  24. package/dist/utils/map-context.d.ts +6 -0
  25. package/dist/utils/map-context.d.ts.map +1 -0
  26. package/dist/utils/map-context.js +36 -0
  27. package/dist/utils/url.d.ts +7 -0
  28. package/dist/utils/url.d.ts.map +1 -0
  29. package/dist/utils/url.js +17 -0
  30. package/lib/index.ts +3 -0
  31. package/lib/model/index.ts +2 -0
  32. package/lib/model/map-context-diff.ts +37 -0
  33. package/lib/model/map-context.ts +100 -0
  34. package/lib/utils/freeze.test.ts +52 -0
  35. package/lib/utils/freeze.ts +14 -0
  36. package/lib/utils/index.ts +4 -0
  37. package/lib/utils/map-context-diff.test.ts +275 -0
  38. package/lib/utils/map-context-diff.ts +102 -0
  39. package/lib/utils/map-context.test.ts +303 -0
  40. package/lib/utils/map-context.ts +51 -0
  41. package/lib/utils/url.test.ts +14 -0
  42. package/lib/utils/url.ts +20 -0
  43. package/package.json +26 -0
@@ -0,0 +1,275 @@
1
+ import { MapContext, MapContextDiff, MapContextLayer } from "../model";
2
+ import { computeMapContextDiff } from "./map-context-diff";
3
+ import {
4
+ SAMPLE_CONTEXT,
5
+ SAMPLE_LAYER1,
6
+ SAMPLE_LAYER2,
7
+ SAMPLE_LAYER3,
8
+ SAMPLE_LAYER4,
9
+ SAMPLE_LAYER5,
10
+ } from "../../fixtures/map-context.fixtures";
11
+
12
+ describe("Context diff utils", () => {
13
+ describe("computeMapContextDiff", () => {
14
+ let contextOld: MapContext;
15
+ let contextNew: MapContext;
16
+ let diff: MapContextDiff;
17
+
18
+ describe("no change", () => {
19
+ beforeEach(() => {
20
+ contextOld = {
21
+ ...SAMPLE_CONTEXT,
22
+ layers: [SAMPLE_LAYER2, SAMPLE_LAYER1],
23
+ };
24
+ contextNew = {
25
+ ...SAMPLE_CONTEXT,
26
+ layers: [SAMPLE_LAYER2, SAMPLE_LAYER1],
27
+ };
28
+ });
29
+ it("outputs the correct diff", () => {
30
+ diff = computeMapContextDiff(contextNew, contextOld);
31
+ expect(diff).toEqual({
32
+ layersAdded: [],
33
+ layersChanged: [],
34
+ layersRemoved: [],
35
+ layersReordered: [],
36
+ viewChanges: {},
37
+ });
38
+ });
39
+ });
40
+
41
+ describe("layers added", () => {
42
+ beforeEach(() => {
43
+ contextOld = {
44
+ ...SAMPLE_CONTEXT,
45
+ layers: [SAMPLE_LAYER1],
46
+ };
47
+ contextNew = {
48
+ ...SAMPLE_CONTEXT,
49
+ layers: [SAMPLE_LAYER2, SAMPLE_LAYER1, SAMPLE_LAYER4],
50
+ };
51
+ });
52
+ it("outputs the correct diff", () => {
53
+ diff = computeMapContextDiff(contextNew, contextOld);
54
+ expect(diff).toEqual({
55
+ layersAdded: [
56
+ {
57
+ layer: SAMPLE_LAYER2,
58
+ position: 0,
59
+ },
60
+ {
61
+ layer: SAMPLE_LAYER4,
62
+ position: 2,
63
+ },
64
+ ],
65
+ layersChanged: [],
66
+ layersRemoved: [],
67
+ layersReordered: [],
68
+ viewChanges: {},
69
+ });
70
+ });
71
+ });
72
+
73
+ describe("layers removed", () => {
74
+ beforeEach(() => {
75
+ contextOld = {
76
+ ...SAMPLE_CONTEXT,
77
+ layers: [SAMPLE_LAYER2, SAMPLE_LAYER1, SAMPLE_LAYER4],
78
+ };
79
+ contextNew = {
80
+ ...SAMPLE_CONTEXT,
81
+ layers: [SAMPLE_LAYER4],
82
+ };
83
+ });
84
+ it("outputs the correct diff", () => {
85
+ diff = computeMapContextDiff(contextNew, contextOld);
86
+ expect(diff).toEqual({
87
+ layersAdded: [],
88
+ layersChanged: [],
89
+ layersRemoved: [
90
+ {
91
+ layer: SAMPLE_LAYER2,
92
+ position: 0,
93
+ },
94
+ {
95
+ layer: SAMPLE_LAYER1,
96
+ position: 1,
97
+ },
98
+ ],
99
+ layersReordered: [],
100
+ viewChanges: {},
101
+ });
102
+ });
103
+ });
104
+
105
+ describe("layers changed", () => {
106
+ beforeEach(() => {
107
+ contextOld = {
108
+ ...SAMPLE_CONTEXT,
109
+ layers: [SAMPLE_LAYER2, { ...SAMPLE_LAYER1, id: 123, version: 3 }],
110
+ };
111
+ contextNew = {
112
+ ...SAMPLE_CONTEXT,
113
+ layers: [
114
+ { ...SAMPLE_LAYER2, extras: { prop: true } },
115
+ { ...SAMPLE_LAYER1, id: 123, version: 10 },
116
+ ],
117
+ };
118
+ });
119
+ it("outputs the correct diff", () => {
120
+ diff = computeMapContextDiff(contextNew, contextOld);
121
+ expect(diff).toEqual({
122
+ layersAdded: [],
123
+ layersChanged: [
124
+ {
125
+ layer: contextNew.layers[0],
126
+ position: 0,
127
+ },
128
+ {
129
+ layer: contextNew.layers[1],
130
+ position: 1,
131
+ },
132
+ ],
133
+ layersRemoved: [],
134
+ layersReordered: [],
135
+ viewChanges: {},
136
+ });
137
+ });
138
+ });
139
+
140
+ describe("reordering", () => {
141
+ describe("three layers reordered", () => {
142
+ beforeEach(() => {
143
+ contextOld = {
144
+ ...SAMPLE_CONTEXT,
145
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2, SAMPLE_LAYER3],
146
+ };
147
+ contextNew = {
148
+ ...SAMPLE_CONTEXT,
149
+ layers: [SAMPLE_LAYER2, SAMPLE_LAYER1, SAMPLE_LAYER3],
150
+ };
151
+ });
152
+ it("outputs the correct diff", () => {
153
+ diff = computeMapContextDiff(contextNew, contextOld);
154
+ expect(diff).toEqual({
155
+ layersAdded: [],
156
+ layersChanged: [],
157
+ layersRemoved: [],
158
+ layersReordered: [
159
+ {
160
+ layer: SAMPLE_LAYER2,
161
+ newPosition: 0,
162
+ previousPosition: 1,
163
+ },
164
+ {
165
+ layer: SAMPLE_LAYER1,
166
+ newPosition: 1,
167
+ previousPosition: 0,
168
+ },
169
+ ],
170
+ viewChanges: {},
171
+ });
172
+ });
173
+ });
174
+
175
+ describe("four layers reordered", () => {
176
+ beforeEach(() => {
177
+ contextOld = {
178
+ ...SAMPLE_CONTEXT,
179
+ layers: [
180
+ SAMPLE_LAYER1,
181
+ SAMPLE_LAYER3,
182
+ SAMPLE_LAYER4,
183
+ SAMPLE_LAYER2,
184
+ ],
185
+ };
186
+ contextNew = {
187
+ ...SAMPLE_CONTEXT,
188
+ layers: [
189
+ SAMPLE_LAYER4,
190
+ SAMPLE_LAYER3,
191
+ SAMPLE_LAYER1,
192
+ SAMPLE_LAYER2,
193
+ ],
194
+ };
195
+ });
196
+ it("outputs the correct diff", () => {
197
+ diff = computeMapContextDiff(contextNew, contextOld);
198
+ expect(diff).toEqual({
199
+ layersAdded: [],
200
+ layersChanged: [],
201
+ layersRemoved: [],
202
+ layersReordered: [
203
+ {
204
+ layer: SAMPLE_LAYER4,
205
+ newPosition: 0,
206
+ previousPosition: 2,
207
+ },
208
+ {
209
+ layer: SAMPLE_LAYER1,
210
+ newPosition: 2,
211
+ previousPosition: 0,
212
+ },
213
+ ],
214
+ viewChanges: {},
215
+ });
216
+ });
217
+ });
218
+ });
219
+
220
+ describe("combined changes", () => {
221
+ let changedLayer: MapContextLayer;
222
+ beforeEach(() => {
223
+ changedLayer = { ...SAMPLE_LAYER3, extras: { prop: true } };
224
+ contextOld = {
225
+ ...SAMPLE_CONTEXT,
226
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER5, SAMPLE_LAYER3, SAMPLE_LAYER4],
227
+ };
228
+ contextNew = {
229
+ ...SAMPLE_CONTEXT,
230
+ layers: [SAMPLE_LAYER2, changedLayer, SAMPLE_LAYER5],
231
+ };
232
+ });
233
+ it("outputs the correct diff", () => {
234
+ diff = computeMapContextDiff(contextNew, contextOld);
235
+ expect(diff).toEqual({
236
+ layersAdded: [
237
+ {
238
+ layer: SAMPLE_LAYER2,
239
+ position: 0,
240
+ },
241
+ ],
242
+ layersChanged: [
243
+ {
244
+ layer: changedLayer,
245
+ position: 1,
246
+ },
247
+ ],
248
+ layersRemoved: [
249
+ {
250
+ layer: SAMPLE_LAYER1,
251
+ position: 0,
252
+ },
253
+ {
254
+ layer: SAMPLE_LAYER4,
255
+ position: 3,
256
+ },
257
+ ],
258
+ layersReordered: [
259
+ {
260
+ layer: changedLayer,
261
+ newPosition: 1,
262
+ previousPosition: 2,
263
+ },
264
+ {
265
+ layer: SAMPLE_LAYER5,
266
+ newPosition: 2,
267
+ previousPosition: 1,
268
+ },
269
+ ],
270
+ viewChanges: {},
271
+ });
272
+ });
273
+ });
274
+ });
275
+ });
@@ -0,0 +1,102 @@
1
+ import {
2
+ MapContext,
3
+ MapContextDiff,
4
+ MapContextLayer,
5
+ MapContextLayerPositioned,
6
+ MapContextLayerReordered,
7
+ MapContextView,
8
+ } from "../model";
9
+ import { isLayerSame, isLayerSameAndUnchanged } from "./map-context";
10
+
11
+ /**
12
+ * The following logic is produced by identifying layers in both context
13
+ * and determining whether they have been added, removed, changed or reordered.
14
+ *
15
+ * Identifying layers to determine if they have been added/removed/reordered is done like so:
16
+ * 1. For layers with an `id` property, use non-strict equality on it (e.g. '2' and 2 are equivalent);
17
+ * 2. For layers without `id`, compute a hash of their base properties _excluding the `extras` property_
18
+ *
19
+ * Determining whether layers have changed is done like so:
20
+ * 1. For layers with an `id` property, the value of the `version` field is compared;
21
+ * if values are different (using non-strict equality), then the layer is considered to have changed; otherwise
22
+ * it is considered to have remained the same
23
+ * 2. For layers without `id`, a full hash is computed _including the `extras` property_;
24
+ * this means that a layer which only had changes in its `extras` object will not be considered added/removed,
25
+ * but only changed
26
+ *
27
+ * @param nextContext
28
+ * @param previousContext
29
+ */
30
+ export function computeMapContextDiff(
31
+ nextContext: MapContext,
32
+ previousContext: MapContext,
33
+ ): MapContextDiff {
34
+ function getLayerPosition(
35
+ layer: MapContextLayer,
36
+ layers: MapContextLayer[],
37
+ ): number {
38
+ for (let i = 0; i < layers.length; i++) {
39
+ if (isLayerSame(layers[i], layer)) {
40
+ return i;
41
+ }
42
+ }
43
+ return -1;
44
+ }
45
+
46
+ const layersChanged: MapContextLayerPositioned[] = [];
47
+ const layersReordered: MapContextLayerReordered[] = [];
48
+ const layersRemoved: MapContextLayerPositioned[] = [];
49
+ const layersAdded: MapContextLayerPositioned[] = [];
50
+ const viewChanges: MapContextView = {};
51
+
52
+ // loop on prev context layers (for removed layers)
53
+ for (let i = 0; i < previousContext.layers.length; i++) {
54
+ const layer = previousContext.layers[i];
55
+ const nextPosition = getLayerPosition(layer, nextContext.layers);
56
+ const prevPosition = getLayerPosition(layer, previousContext.layers);
57
+ if (nextPosition === -1) {
58
+ layersRemoved.push({ layer, position: prevPosition });
59
+ }
60
+ }
61
+
62
+ // loop on next context layers (for added & updated)
63
+ for (let i = 0; i < nextContext.layers.length; i++) {
64
+ const layer = nextContext.layers[i];
65
+ const prevPosition = getLayerPosition(layer, previousContext.layers);
66
+ if (prevPosition === -1) {
67
+ layersAdded.push({ layer, position: i });
68
+ } else {
69
+ const prevLayer = previousContext.layers[prevPosition];
70
+ if (!isLayerSameAndUnchanged(layer, prevLayer)) {
71
+ layersChanged.push({ layer, position: i });
72
+ }
73
+ }
74
+ }
75
+
76
+ // look for moved layers
77
+ const prevLayersFiltered = previousContext.layers.filter(
78
+ (l) => !layersRemoved.find(({ layer }) => l === layer),
79
+ );
80
+ const nextLayersFiltered = nextContext.layers.filter(
81
+ (l) => !layersAdded.find(({ layer }) => l === layer),
82
+ );
83
+ for (let i = 0; i < nextLayersFiltered.length; i++) {
84
+ const layer = nextLayersFiltered[i];
85
+ const prevPosition = getLayerPosition(layer, prevLayersFiltered);
86
+ if (i !== prevPosition) {
87
+ layersReordered.push({
88
+ layer,
89
+ newPosition: getLayerPosition(layer, nextContext.layers),
90
+ previousPosition: getLayerPosition(layer, previousContext.layers),
91
+ });
92
+ }
93
+ }
94
+
95
+ return {
96
+ layersAdded,
97
+ layersChanged,
98
+ layersRemoved,
99
+ layersReordered,
100
+ viewChanges,
101
+ };
102
+ }
@@ -0,0 +1,303 @@
1
+ import { describe } from "vitest";
2
+ import {
3
+ getLayerHash,
4
+ getLayerPosition,
5
+ isLayerSame,
6
+ isLayerSameAndUnchanged,
7
+ } from "./map-context";
8
+ import { MapContext } from "../model";
9
+ import {
10
+ SAMPLE_CONTEXT,
11
+ SAMPLE_LAYER1,
12
+ SAMPLE_LAYER2,
13
+ } from "../../fixtures/map-context.fixtures";
14
+
15
+ describe("Map context utils", () => {
16
+ describe("isLayerSame", () => {
17
+ describe("layers with id", () => {
18
+ it("compares non-strictly by id", () => {
19
+ expect(
20
+ isLayerSame(
21
+ { ...SAMPLE_LAYER1, id: "a" },
22
+ { ...SAMPLE_LAYER1, id: "b" },
23
+ ),
24
+ ).toBe(false);
25
+ expect(
26
+ isLayerSame(
27
+ { ...SAMPLE_LAYER1, id: "ab" },
28
+ { ...SAMPLE_LAYER2, id: "ab" },
29
+ ),
30
+ ).toBe(true);
31
+ expect(
32
+ isLayerSame(
33
+ { ...SAMPLE_LAYER1, id: 1 },
34
+ { ...SAMPLE_LAYER2, id: "01" },
35
+ ),
36
+ ).toBe(true);
37
+ expect(
38
+ isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER2, id: 1 }),
39
+ ).toBe(true);
40
+ expect(
41
+ isLayerSame({ ...SAMPLE_LAYER1, id: 1 }, { ...SAMPLE_LAYER1, id: 2 }),
42
+ ).toBe(false);
43
+ });
44
+ });
45
+ describe("layers without id", () => {
46
+ it("compares by properties", () => {
47
+ expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(true);
48
+ expect(
49
+ isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, name: "abc" }),
50
+ ).toBe(false);
51
+ expect(
52
+ isLayerSame(
53
+ {
54
+ ...SAMPLE_LAYER1,
55
+ url: "http://abc.org",
56
+ name: SAMPLE_LAYER1.name,
57
+ },
58
+ { ...SAMPLE_LAYER1, url: "http://abc.org" },
59
+ ),
60
+ ).toBe(true);
61
+ expect(isLayerSame(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(false);
62
+ });
63
+ it("ignores extras prop", () => {
64
+ expect(
65
+ isLayerSame(SAMPLE_LAYER1, {
66
+ ...SAMPLE_LAYER1,
67
+ extras: { otherProp: "abc" },
68
+ }),
69
+ ).toBe(true);
70
+ expect(
71
+ isLayerSame(SAMPLE_LAYER1, {
72
+ ...SAMPLE_LAYER1,
73
+ extras: undefined,
74
+ }),
75
+ ).toBe(true);
76
+ const { extras, ...layer } = SAMPLE_LAYER1;
77
+ expect(isLayerSame(SAMPLE_LAYER1, layer)).toBe(true);
78
+ });
79
+ });
80
+ describe("layers with and without id", () => {
81
+ it("compares by properties", () => {
82
+ expect(
83
+ isLayerSame(SAMPLE_LAYER1, { ...SAMPLE_LAYER1, id: "123" }),
84
+ ).toBe(false);
85
+ expect(
86
+ isLayerSame(
87
+ { ...SAMPLE_LAYER1, id: "123" },
88
+ { id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
89
+ ),
90
+ ).toBe(true);
91
+ });
92
+ });
93
+ });
94
+
95
+ describe("isLayerSameAndUnchanged", () => {
96
+ describe("layers with id", () => {
97
+ it("compares non-strictly by id and version field", () => {
98
+ expect(
99
+ isLayerSameAndUnchanged(
100
+ { ...SAMPLE_LAYER1, id: "a" },
101
+ { ...SAMPLE_LAYER1, id: "b" },
102
+ ),
103
+ ).toBe(false);
104
+ expect(
105
+ isLayerSameAndUnchanged(
106
+ { ...SAMPLE_LAYER1, id: "a" },
107
+ { ...SAMPLE_LAYER2, id: "a" },
108
+ ),
109
+ ).toBe(true);
110
+ expect(
111
+ isLayerSameAndUnchanged(
112
+ { ...SAMPLE_LAYER1, id: "ab", version: 2 },
113
+ { ...SAMPLE_LAYER2, id: "ab", version: 2 },
114
+ ),
115
+ ).toBe(true);
116
+ expect(
117
+ isLayerSameAndUnchanged(
118
+ { ...SAMPLE_LAYER1, id: "ab", version: 2 },
119
+ { ...SAMPLE_LAYER1, id: "ab", version: 1 },
120
+ ),
121
+ ).toBe(false);
122
+ expect(
123
+ isLayerSameAndUnchanged(
124
+ { ...SAMPLE_LAYER1, id: 1 },
125
+ { ...SAMPLE_LAYER1, id: "01", version: 3 },
126
+ ),
127
+ ).toBe(false);
128
+ });
129
+ });
130
+ describe("layers without id", () => {
131
+ it("compares by properties, including extras", () => {
132
+ expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER1)).toBe(
133
+ true,
134
+ );
135
+ expect(
136
+ isLayerSameAndUnchanged(SAMPLE_LAYER1, {
137
+ ...SAMPLE_LAYER1,
138
+ name: "abc",
139
+ }),
140
+ ).toBe(false);
141
+ expect(
142
+ isLayerSameAndUnchanged(
143
+ {
144
+ ...SAMPLE_LAYER1,
145
+ url: "http://abc.org",
146
+ name: SAMPLE_LAYER1.name,
147
+ },
148
+ { ...SAMPLE_LAYER1, url: "http://abc.org" },
149
+ ),
150
+ ).toBe(true);
151
+ expect(
152
+ isLayerSameAndUnchanged(
153
+ {
154
+ ...SAMPLE_LAYER1,
155
+ opacity: 1,
156
+ },
157
+ SAMPLE_LAYER1,
158
+ ),
159
+ ).toBe(false);
160
+ expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, SAMPLE_LAYER2)).toBe(
161
+ false,
162
+ );
163
+ });
164
+ it("takes into account extras prop", () => {
165
+ expect(
166
+ isLayerSameAndUnchanged(SAMPLE_LAYER1, {
167
+ ...SAMPLE_LAYER1,
168
+ extras: { otherProp: "abc" },
169
+ }),
170
+ ).toBe(false);
171
+ expect(
172
+ isLayerSameAndUnchanged(SAMPLE_LAYER1, {
173
+ ...SAMPLE_LAYER1,
174
+ extras: undefined,
175
+ }),
176
+ ).toBe(false);
177
+ const { extras, ...layer } = SAMPLE_LAYER1;
178
+ expect(isLayerSameAndUnchanged(SAMPLE_LAYER1, layer)).toBe(false);
179
+ });
180
+ });
181
+ describe("layers with and without id", () => {
182
+ it("compares by properties", () => {
183
+ expect(
184
+ isLayerSameAndUnchanged(SAMPLE_LAYER1, {
185
+ ...SAMPLE_LAYER1,
186
+ id: "123",
187
+ }),
188
+ ).toBe(false);
189
+ expect(
190
+ isLayerSameAndUnchanged(
191
+ { ...SAMPLE_LAYER1, id: "123" },
192
+ { id: "123", ...SAMPLE_LAYER1, name: SAMPLE_LAYER1.name },
193
+ ),
194
+ ).toBe(true);
195
+ });
196
+ });
197
+ });
198
+
199
+ describe("getLayerHash", () => {
200
+ it("works with serializable entities", () => {
201
+ expect(
202
+ getLayerHash({
203
+ ...SAMPLE_LAYER1,
204
+ extras: {
205
+ array: [11, 22, null, undefined],
206
+ object: {},
207
+ undef: undefined,
208
+ },
209
+ }),
210
+ ).toBeTypeOf("string");
211
+ });
212
+ it("ignores extra property by default", () => {
213
+ expect(
214
+ getLayerHash({
215
+ ...SAMPLE_LAYER1,
216
+ extras: {
217
+ array: [11, 22, null, undefined],
218
+ object: {},
219
+ },
220
+ }),
221
+ ).toEqual(
222
+ getLayerHash({
223
+ ...SAMPLE_LAYER1,
224
+ extras: { hello: "world" },
225
+ }),
226
+ );
227
+ });
228
+ it("works with non-serializable entities (but they are ignored)", () => {
229
+ const hash = getLayerHash(
230
+ {
231
+ ...SAMPLE_LAYER1,
232
+ extras: {
233
+ func: () => 123,
234
+ canvas: document.createElement("canvas"),
235
+ },
236
+ },
237
+ true,
238
+ );
239
+ expect(hash).toBeTypeOf("string");
240
+ expect(hash).toEqual(
241
+ getLayerHash(
242
+ {
243
+ ...SAMPLE_LAYER1,
244
+ extras: {
245
+ func: () => 456,
246
+ canvas: document.createElement("div"),
247
+ },
248
+ },
249
+ true,
250
+ ),
251
+ );
252
+ expect(hash).not.toEqual(
253
+ getLayerHash(
254
+ {
255
+ ...SAMPLE_LAYER1,
256
+ extras: {},
257
+ },
258
+ true,
259
+ ),
260
+ );
261
+ });
262
+ it("does not take into account properties order", () => {
263
+ expect(
264
+ getLayerHash(
265
+ {
266
+ type: "wms",
267
+ url: "http://abc.org/wms",
268
+ name: "myLayer",
269
+ extras: {
270
+ array: [1, 2, 3],
271
+ object: {},
272
+ },
273
+ },
274
+ true,
275
+ ),
276
+ ).toEqual(
277
+ getLayerHash(
278
+ {
279
+ extras: {
280
+ array: [1, 2, 3],
281
+ object: {},
282
+ },
283
+ url: "http://abc.org/wms",
284
+ type: "wms",
285
+ name: "myLayer",
286
+ },
287
+ true,
288
+ ),
289
+ );
290
+ });
291
+ });
292
+
293
+ describe("getLayerPosition", () => {
294
+ it("returns the index of the layer in the context", () => {
295
+ const context: MapContext = {
296
+ ...SAMPLE_CONTEXT,
297
+ layers: [SAMPLE_LAYER1, SAMPLE_LAYER2],
298
+ };
299
+ expect(getLayerPosition(context, SAMPLE_LAYER1)).toBe(0);
300
+ expect(getLayerPosition(context, SAMPLE_LAYER2)).toBe(1);
301
+ });
302
+ });
303
+ });