From acd0f4c76a5b783ed4d5a28ec602726abcd3d0a2 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 09:28:59 +0100 Subject: [PATCH 1/7] IM-394 added a remove dataset api --- demo/js/esri-datasets.js | 2 ++ .../src/adapters/esri/esriLayerAdapter.js | 26 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/demo/js/esri-datasets.js b/demo/js/esri-datasets.js index 670728c7..1c7a3fd5 100644 --- a/demo/js/esri-datasets.js +++ b/demo/js/esri-datasets.js @@ -146,4 +146,6 @@ const testGlobalVisibility = () => { interactiveMap.on('datasets:ready', function () { // testGlobalVisibility() + setTimeout(() => datasetsPlugin.removeDataset('flood-zones-cc'), 1000) + setTimeout(() => datasetsPlugin.removeDataset('flood-zones'), 3000) }) \ No newline at end of file diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js index f9303757..58e4ee2c 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js @@ -76,8 +76,30 @@ export default class EsriLayerAdapter extends LayerAdapter { return vectorTileLayer.when() } - async removeDataset (...args) { - console.log('TODO: removeDataset', args) + async removeDataset (datasetId) { + const registryDataset = datasetRegistry.getDataset(datasetId) + if (!registryDataset) { + return + } + const { esriGroupId } = registryDataset + const vectorTileLayer = this._vectorTileLayers[datasetId] + // If the dataset is part of a group layer, we need to remove it from the group layer + const groupLayer = esriGroupId ? this._groupLayers[esriGroupId] : null + const vectorTileParent = groupLayer || this._map + + if (vectorTileLayer) { + // Remove the vectorTileLayer from the map or group layer + vectorTileParent.remove(vectorTileLayer) + // And remove the vectorTileLayer from the adapter's internal state + delete this._vectorTileLayers[datasetId] + delete this._vectorTileOpacityLayers[datasetId] + } + + // If the group layer has no more sublayers, we need to also remove the group layer from the map + if (groupLayer && groupLayer.layers.length === 0) { + this._map.remove(groupLayer) + delete this._groupLayers[esriGroupId] + } } async setData (...args) { From c65f3b8dc848f8e0943e00413d4906293bd60531 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 09:52:17 +0100 Subject: [PATCH 2/7] IM-394 added tests to cover removeDataset --- .../adapters/esri/esriLayerAdapter.test.js | 69 +++++++++++++++++-- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js index bb43d16c..ac186f25 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js @@ -14,13 +14,21 @@ jest.mock('@arcgis/core/layers/VectorTileLayer.js', () => })) ) jest.mock('@arcgis/core/layers/GroupLayer.js', () => - jest.fn().mockImplementation((opts = {}) => ({ - ...opts, - add: jest.fn() - })) + jest.fn().mockImplementation((opts = {}) => { + const layers = [] + return { + ...opts, + layers, + add: jest.fn(layer => layers.push(layer)), + remove: jest.fn(layer => { + const idx = layers.indexOf(layer) + if (idx !== -1) layers.splice(idx, 1) + }) + } + }) ) -// Uncovered: 80-88,124,145-149 +// Uncovered: 124,145-149 const MAP_STYLE = { id: 'outdoor' } const makeMap = () => { @@ -30,7 +38,8 @@ const makeMap = () => { // Ensure that the same layer is never added twice expect(_added[id]).toBeUndefined() _added[id] = true - }) + }), + remove: jest.fn() } } const makeMapProvider = (map) => ({ map }) @@ -55,6 +64,54 @@ describe('esriLayerAdapter', () => { }) }) + // ─── removeDataset ──────────────────────────────────────────────────────────── + + describe('removeDataset', () => { + it('does nothing when dataset is not in the registry', async () => { + await expect(adapter.removeDataset('unknown')).resolves.toBeUndefined() + expect(map.remove).not.toHaveBeenCalled() + }) + + it('does nothing when the dataset has not been added to the adapter', async () => { + await adapter.removeDataset('esri-standalone') + expect(map.remove).not.toHaveBeenCalled() + }) + + it('removes a standalone vectorTileLayer from the map and clears internal state', async () => { + await adapter._addLayers(datasetRegistry.getDataset('esri-standalone')) + const vtl = adapter._vectorTileLayers['esri-standalone'] + await adapter.removeDataset('esri-standalone') + expect(map.remove).toHaveBeenCalledWith(vtl) + expect(adapter._vectorTileLayers['esri-standalone']).toBeUndefined() + expect(adapter._vectorTileOpacityLayers['esri-standalone']).toBeUndefined() + }) + + it('removes the vectorTileLayer from its group layer but keeps the group when other layers remain', async () => { + await adapter._addLayers(datasetRegistry.getDataset('flood-zones-cc')) + await adapter._addLayers(datasetRegistry.getDataset('flood-zones')) + const vtl = adapter._vectorTileLayers['flood-zones-cc'] + const groupLayer = adapter._groupLayers['flood-zones-group'] + await adapter.removeDataset('flood-zones-cc') + expect(groupLayer.remove).toHaveBeenCalledWith(vtl) + expect(map.remove).not.toHaveBeenCalledWith(groupLayer) + expect(adapter._groupLayers['flood-zones-group']).toBeDefined() + expect(adapter._vectorTileLayers['flood-zones-cc']).toBeUndefined() + expect(adapter._vectorTileOpacityLayers['flood-zones-cc']).toBeUndefined() + }) + + it('removes the group layer from the map when its last vectorTileLayer is removed', async () => { + await adapter._addLayers(datasetRegistry.getDataset('esri-grouped')) + const vtl = adapter._vectorTileLayers['esri-grouped'] + const groupLayer = adapter._groupLayers['my-group'] + await adapter.removeDataset('esri-grouped') + expect(groupLayer.remove).toHaveBeenCalledWith(vtl) + expect(map.remove).toHaveBeenCalledWith(groupLayer) + expect(adapter._groupLayers['my-group']).toBeUndefined() + expect(adapter._vectorTileLayers['esri-grouped']).toBeUndefined() + expect(adapter._vectorTileOpacityLayers['esri-grouped']).toBeUndefined() + }) + }) + // ─── applyDatasetVisibility ────────────────────────────────────────────────── describe('applyDatasetVisibility', () => { From 19d480a08f496c46fa8fb493b6e2b92443f110c5 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 10:37:14 +0100 Subject: [PATCH 3/7] IM-394 removed un-needed params in esriLayerAdapter.test.js --- .../adapters/esri/esriLayerAdapter.test.js | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js index ac186f25..0c711b18 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js @@ -117,7 +117,9 @@ describe('esriLayerAdapter', () => { describe('applyDatasetVisibility', () => { beforeEach(async () => { const standAlone = datasetRegistry.getDataset('esri-standalone') - await adapter._addLayers(standAlone, MAP_STYLE) + await adapter._addLayers(standAlone) + const fz3 = datasetRegistry.getDataset('flood-zones-flood-zone-3') + await adapter._addLayers(fz3) }) it('applies visibility for a known dataset', async () => { @@ -134,7 +136,7 @@ describe('esriLayerAdapter', () => { describe('applyDatasetOpacity', () => { it('sets opacity on the opacity layer for a known dataset', async () => { - await adapter._addLayers(datasetRegistry.getDataset('esri-standalone'), MAP_STYLE) + await adapter._addLayers(datasetRegistry.getDataset('esri-standalone')) await adapter.applyDatasetOpacity('esri-standalone') expect(adapter._vectorTileOpacityLayers['esri-standalone'].opacity) .toBe(datasetRegistry.getDataset('esri-standalone').opacity) @@ -145,7 +147,7 @@ describe('esriLayerAdapter', () => { }) it('does nothing for an unknown dataset', async () => { - await adapter._addLayers(datasetRegistry.getDataset('esri-standalone'), MAP_STYLE) + await adapter._addLayers(datasetRegistry.getDataset('esri-standalone')) await expect(adapter.applyDatasetOpacity('unknown')).resolves.not.toThrow() }) }) @@ -154,7 +156,7 @@ describe('esriLayerAdapter', () => { describe('applyGlobalOpacity', () => { it('sets opacity on all opacity layers', async () => { - await adapter._addLayers(datasetRegistry.getDataset('esri-standalone'), MAP_STYLE) + await adapter._addLayers(datasetRegistry.getDataset('esri-standalone')) await adapter.applyGlobalOpacity() expect(adapter._vectorTileOpacityLayers['esri-standalone'].opacity) .toBe(datasetRegistry.getDataset('esri-standalone').opacity) @@ -171,33 +173,26 @@ describe('esriLayerAdapter', () => { describe('onMapStyleChange', () => { beforeEach(async () => { - await adapter._addLayers(datasetRegistry.getDataset('esri-standalone'), MAP_STYLE) - await adapter._addLayers(datasetRegistry.getDataset('esri-server'), MAP_STYLE) + await adapter._addLayers(datasetRegistry.getDataset('esri-standalone')) + await adapter._addLayers(datasetRegistry.getDataset('esri-server')) }) it('calls setStyleLayerVisibility for datasets with esriStyleLayerId', async () => { - await adapter.onMapStyleChange(MAP_STYLE, null) + await adapter.onMapStyleChange() expect(adapter._vectorTileLayers['esri-standalone'].setStyleLayerVisibility) .toHaveBeenCalledWith('standalone-style', expect.any(String)) }) it('calls setPaintProperties for datasets not using server style', async () => { - await adapter.onMapStyleChange(MAP_STYLE, null) + await adapter.onMapStyleChange() expect(adapter._vectorTileLayers['esri-standalone'].setPaintProperties) .toHaveBeenCalledWith('standalone-style', expect.any(Object)) }) it('does not call setPaintProperties when useServerStyle is true', async () => { - await adapter.onMapStyleChange(MAP_STYLE, null) + await adapter.onMapStyleChange() expect(adapter._vectorTileLayers['esri-server'].setPaintProperties).not.toHaveBeenCalled() }) - - // it('does not call setPaintProperties when getPaintProperties returns null', async () => { - // const vtl = adapter._vectorTileLayers['esri-standalone'] - // vtl.getPaintProperties.mockReturnValueOnce(null) - // await adapter.onMapStyleChange(MAP_STYLE, null) - // expect(vtl.setPaintProperties).not.toHaveBeenCalled() - // }) }) // ─── init ──────────────────────────────────────────────────────────────────── From cbfd63e5b0b79c247e68f4c0870150ee3bee27c9 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 10:46:58 +0100 Subject: [PATCH 4/7] IM-394 covered missing line in esriLayerAdapter --- .../src/adapters/esri/esriLayerAdapter.test.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js index 0c711b18..46bc287b 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js @@ -118,8 +118,6 @@ describe('esriLayerAdapter', () => { beforeEach(async () => { const standAlone = datasetRegistry.getDataset('esri-standalone') await adapter._addLayers(standAlone) - const fz3 = datasetRegistry.getDataset('flood-zones-flood-zone-3') - await adapter._addLayers(fz3) }) it('applies visibility for a known dataset', async () => { @@ -130,6 +128,13 @@ describe('esriLayerAdapter', () => { it('does nothing for an unknown dataset', async () => { await expect(adapter.applyDatasetVisibility('unknown')).resolves.not.toThrow() }) + + it('calls setStyleLayerVisibility for datasets with esriStyleLayerId', async () => { + const applyStyleLayerVisibilitySpy = jest.spyOn(adapter, '_applyStyleLayerVisibility') + await adapter._addLayers(datasetRegistry.getDataset('flood-zones')) + await adapter.applyDatasetVisibility('flood-zones-flood-zone-3') + expect(applyStyleLayerVisibilitySpy.mock.calls).toHaveLength(1) + }) }) // ─── applyDatasetOpacity ───────────────────────────────────────────────────── @@ -218,7 +223,7 @@ describe('esriLayerAdapter', () => { }) it('calls map.add for each top-level dataset', async () => { - expect(map.add.mock.calls.length).toEqual(5) // 3 top-level datasets + 2 group layers + expect(map.add.mock.calls).toHaveLength(5) // 3 top-level datasets + 2 group layers }) }) From 2029c6c51407407f92c9d2f13095474c1a1cfad7 Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 12:48:46 +0100 Subject: [PATCH 5/7] IM-394 added an addDataset method --- demo/js/esri-datasets.js | 12 ++- .../src/adapters/esri/esriLayerAdapter.js | 81 +++++++++++-------- .../adapters/esri/esriLayerAdapter.test.js | 12 +++ 3 files changed, 66 insertions(+), 39 deletions(-) diff --git a/demo/js/esri-datasets.js b/demo/js/esri-datasets.js index 1c7a3fd5..c3c90202 100644 --- a/demo/js/esri-datasets.js +++ b/demo/js/esri-datasets.js @@ -7,8 +7,7 @@ import createDatasetsPlugin from '/plugins/beta/datasets/src/index.js' import { vtsMapStyles27700 } from './mapStyles.js' import { transformGeocodeRequest, transformVtsRequest3857, setupEsriConfig } from './auth.js' -const datasets = [ - { +const datasetFloodZonesCC = { id: 'flood-zones-cc', label: 'Flood Zones Climate Change', groupLabel: 'Datasets', @@ -67,8 +66,9 @@ const datasets = [ showInMenu: false, } ] - }, - { + } + + const datasetFloodZones = { id: 'flood-zones', label: 'Flood Zones', groupLabel: 'Datasets', @@ -100,6 +100,9 @@ const datasets = [ } ] } + +const datasets = [ + datasetFloodZonesCC, datasetFloodZones ] const datasetsPlugin = createDatasetsPlugin({ @@ -148,4 +151,5 @@ interactiveMap.on('datasets:ready', function () { // testGlobalVisibility() setTimeout(() => datasetsPlugin.removeDataset('flood-zones-cc'), 1000) setTimeout(() => datasetsPlugin.removeDataset('flood-zones'), 3000) + setTimeout(() => datasetsPlugin.addDataset(datasetFloodZones), 5000) }) \ No newline at end of file diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js index 58e4ee2c..0f9e6738 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js @@ -76,6 +76,20 @@ export default class EsriLayerAdapter extends LayerAdapter { return vectorTileLayer.when() } + async addDataset (datasetId) { + const registryDataset = datasetRegistry.getDataset(datasetId) + if (!registryDataset) { + console.warn(`addDataset called, but Dataset with id ${datasetId} not found in registry`) + return + } + await this._addLayers(registryDataset) + const { parentId } = registryDataset + const vectorTileLayer = this._vectorTileLayers[parentId || datasetId] + this.applyDatasetOpacity(datasetId) + this._applyStyleLayerPaintProperties(registryDataset, vectorTileLayer) + this.applyDatasetVisibility(datasetId) + } + async removeDataset (datasetId) { const registryDataset = datasetRegistry.getDataset(datasetId) if (!registryDataset) { @@ -102,22 +116,6 @@ export default class EsriLayerAdapter extends LayerAdapter { } } - async setData (...args) { - console.log('TODO: setData', args) - } - - async applyStyle (...args) { - console.log('TODO: applyStyle', args) - } - - _applyStyleLayerVisibility (sublayer, vectorTileLayer) { - const { esriStyleLayerId } = sublayer - if (!esriStyleLayerId) { - return - } - vectorTileLayer.setStyleLayerVisibility(esriStyleLayerId, sublayer.visibility) - } - _applyRegistryDatasetVisibility (registryDataset) { // if this is a sublayer, we need to apply the visibility to the vectorTileLayers style sheet // if this is a top level dataset, we need to apply the visibility to the vectorTileLayer/ groupLayer itself @@ -163,36 +161,49 @@ export default class EsriLayerAdapter extends LayerAdapter { }) } - async addDataset (...args) { - console.log('TODO: addDataset', args) + _applyStyleLayerVisibility (registryDataset, vectorTileLayer) { + const { esriStyleLayerId } = registryDataset + if (!esriStyleLayerId || !vectorTileLayer) { + return + } + vectorTileLayer.setStyleLayerVisibility(esriStyleLayerId, registryDataset.visibility) } - async applyFeatureFilter (...args) { - console.log('TODO: applyFeatureFilter', args) + _applyStyleLayerPaintProperties (registryDataset, vectorTileLayer) { + const { esriStyleLayerId, useServerStyle } = registryDataset + if (useServerStyle || !esriStyleLayerId || !vectorTileLayer) { + return + } + const layerPaintProperties = vectorTileLayer.getPaintProperties(esriStyleLayerId) + if (layerPaintProperties) { + registryDataset.applyLayerPaintProperties(layerPaintProperties) + vectorTileLayer.setPaintProperties(esriStyleLayerId, registryDataset.applyLayerPaintProperties(layerPaintProperties)) + } } async onMapStyleChange () { datasetRegistry.forEach(registryDataset => { - const { id, isSublayer, esriStyleLayerId, parent } = registryDataset + const { id, isSublayer, parent } = registryDataset const vectorTileLayer = this._vectorTileLayers[isSublayer ? parent.id : id] - if (vectorTileLayer && esriStyleLayerId) { - // Show hide the style layer based on the dataset's mapStyle visibility - vectorTileLayer.setStyleLayerVisibility(esriStyleLayerId, registryDataset.visibility) - if (registryDataset.useServerStyle) { - // If the dataset is using the server style, we don't need to apply any paint properties - return - } - // Update the paint properties of the style layer based on the dataset's mapStyle style - const layerPaintProperties = vectorTileLayer.getPaintProperties(esriStyleLayerId) - if (layerPaintProperties) { - registryDataset.applyLayerPaintProperties(layerPaintProperties) - vectorTileLayer.setPaintProperties(esriStyleLayerId, registryDataset.applyLayerPaintProperties(layerPaintProperties)) - } - } + this._applyStyleLayerVisibility(registryDataset, vectorTileLayer) + this._applyStyleLayerPaintProperties(registryDataset, vectorTileLayer) }) // TODO - handle dynamic sources } // onMapSizeChange is not applicable to the esriLayerAdapter async onMapSizeChange () {} + + // Remaining methods are still todo + async applyFeatureFilter (...args) { + console.log('TODO: applyFeatureFilter', args) + } + + async setData (...args) { + console.log('TODO: setData', args) + } + + async applyStyle (...args) { + console.log('TODO: applyStyle', args) + } } diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js index 46bc287b..d27c25e5 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js @@ -234,4 +234,16 @@ describe('esriLayerAdapter', () => { await expect(adapter.onMapSizeChange()).resolves.toBeUndefined() }) }) + + describe('applyGlobalVisibility', () => { + beforeEach(async () => { + await adapter.init() + }) + + it('applies visibility for all datasets', async () => { + const applyStyleLayerVisibilitySpy = jest.spyOn(adapter, '_applyStyleLayerVisibility') + await adapter.applyGlobalVisibility() + expect(applyStyleLayerVisibilitySpy.mock.calls).toHaveLength(7) + }) + }) }) From f87db00d7a1cfb1aadf2c05a262fce594f151f9c Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 13:04:46 +0100 Subject: [PATCH 6/7] IM-394 added tests for addDataset --- .../src/adapters/esri/esriLayerAdapter.js | 3 +- .../adapters/esri/esriLayerAdapter.test.js | 43 +++++++++++++++++++ src/services/__mocks/logger.js | 4 ++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/services/__mocks/logger.js diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js index 0f9e6738..781b214d 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.js @@ -3,6 +3,7 @@ import GroupLayer from '@arcgis/core/layers/GroupLayer.js' import { LayerAdapter } from '../layerAdapter.js' import { datasetRegistry } from '../../registry/datasetRegistry.js' import { EsriDataset } from './registry/esriDataset.js' +import { logger } from '../../../../../../src/services/logger.js' export default class EsriLayerAdapter extends LayerAdapter { constructor (mapProvider, symbolRegistry, patternRegistry) { @@ -79,7 +80,7 @@ export default class EsriLayerAdapter extends LayerAdapter { async addDataset (datasetId) { const registryDataset = datasetRegistry.getDataset(datasetId) if (!registryDataset) { - console.warn(`addDataset called, but Dataset with id ${datasetId} not found in registry`) + logger.warn(`addDataset called, but Dataset with id ${datasetId} not found in registry`) return } await this._addLayers(registryDataset) diff --git a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js index d27c25e5..10bb557d 100644 --- a/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js +++ b/plugins/beta/datasets/src/adapters/esri/esriLayerAdapter.test.js @@ -3,6 +3,8 @@ import EsriLayerAdapter from './esriLayerAdapter.js' import { datasetRegistry } from '../../registry/datasetRegistry.js' jest.mock('../../registry/datasetRegistry.js') +jest.mock('../../../../../../src/services/logger.js') + jest.mock('@arcgis/core/layers/VectorTileLayer.js', () => jest.fn().mockImplementation((opts = {}) => ({ ...opts, @@ -64,6 +66,47 @@ describe('esriLayerAdapter', () => { }) }) + // ─── addDataset ────────────────────────────────────────────────────────────── + + describe('addDataset', () => { + it('copes and returns when the dataset is not in the registry', async () => { + await adapter.addDataset('unknown') + expect(adapter._vectorTileLayers.unknown).toBeUndefined() + }) + + it('adds a standalone dataset to the map and populates internal state', async () => { + await adapter.addDataset('esri-standalone') + expect(adapter._vectorTileLayers['esri-standalone']).toBeDefined() + expect(adapter._vectorTileOpacityLayers['esri-standalone']).toBeDefined() + }) + + it('applies opacity and visibility after adding layers', async () => { + await adapter.addDataset('esri-standalone') + const vtl = adapter._vectorTileLayers['esri-standalone'] + expect(vtl.visible).toBe(true) + expect(adapter._vectorTileOpacityLayers['esri-standalone'].opacity) + .toBe(datasetRegistry.getDataset('esri-standalone').opacity) + }) + + it('applies paint properties for datasets with esriStyleLayerId', async () => { + await adapter.addDataset('esri-standalone') + const vtl = adapter._vectorTileLayers['esri-standalone'] + expect(vtl.setPaintProperties).toHaveBeenCalledWith('standalone-style', expect.any(Object)) + }) + + it('does not apply paint properties for server-style datasets', async () => { + await adapter.addDataset('esri-server') + const vtl = adapter._vectorTileLayers['esri-server'] + expect(vtl.setPaintProperties).not.toHaveBeenCalled() + }) + + it('creates a group layer when adding a grouped dataset', async () => { + await adapter.addDataset('esri-grouped') + expect(adapter._vectorTileLayers['esri-grouped']).toBeDefined() + expect(adapter._groupLayers['my-group']).toBeDefined() + }) + }) + // ─── removeDataset ──────────────────────────────────────────────────────────── describe('removeDataset', () => { diff --git a/src/services/__mocks/logger.js b/src/services/__mocks/logger.js new file mode 100644 index 00000000..ddf96c0c --- /dev/null +++ b/src/services/__mocks/logger.js @@ -0,0 +1,4 @@ +export const logger = { + warn: jest.fn(), + error: jest.fn() +} From 7c9cc0d63cf7191ef37ffd24ecc60c44776e901a Mon Sep 17 00:00:00 2001 From: Mark Fee Date: Thu, 9 Jul 2026 13:09:07 +0100 Subject: [PATCH 7/7] IM-394 added __mocks__ for logger --- jest.config.mjs | 1 + .../src/adapters/maplibre/registry/mapLibreDataset.test.js | 4 +--- plugins/beta/datasets/src/api/getOpacity.test.js | 4 +--- plugins/beta/datasets/src/api/getStyle.test.js | 4 +--- plugins/beta/datasets/src/api/setData.test.js | 4 +--- plugins/beta/datasets/src/api/setFeatureVisibility.test.js | 4 +--- plugins/beta/datasets/src/api/setGlobals.test.js | 4 +--- plugins/beta/datasets/src/reducers/pluginState.test.js | 4 +--- src/App/controls/keyboardActions.test.js | 4 +--- src/App/renderer/mapButtons.test.js | 2 +- src/InteractiveMap/deviceChecker.test.js | 2 +- src/services/{__mocks => __mocks__}/logger.js | 0 12 files changed, 11 insertions(+), 26 deletions(-) rename src/services/{__mocks => __mocks__}/logger.js (100%) diff --git a/jest.config.mjs b/jest.config.mjs index a33d594e..491ac260 100755 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -21,6 +21,7 @@ export default { ], testPathIgnorePatterns: ['/src/test-utils.js'], coveragePathIgnorePatterns: [ + '/__mocks__/', '/src/index.umd.js', '/stylelint.config.js', '/coverage', diff --git a/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js b/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js index 5d6adb4a..dd8c28f3 100644 --- a/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +++ b/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js @@ -4,9 +4,7 @@ import { logger } from '../../../../../../../src/services/logger.js' // Use the mock datasetRegistry with the demo datasets attached before each test // so we can test Dataset methods that depend on parent/sublayer relationships and styles jest.mock('../../../registry/datasetRegistry.js') -jest.mock('../../../../../../../src/services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../../../../../../src/services/logger.js') describe('MapLibreDataset', () => { beforeEach(() => { diff --git a/plugins/beta/datasets/src/api/getOpacity.test.js b/plugins/beta/datasets/src/api/getOpacity.test.js index a1e943e0..772bce0f 100644 --- a/plugins/beta/datasets/src/api/getOpacity.test.js +++ b/plugins/beta/datasets/src/api/getOpacity.test.js @@ -6,9 +6,7 @@ jest.mock('../registry/datasetRegistry.js', () => ({ datasetRegistry: { getDataset: jest.fn() } })) -jest.mock('../../../../../src/services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../../../../src/services/logger.js') describe('getOpacity', () => { beforeEach(() => { diff --git a/plugins/beta/datasets/src/api/getStyle.test.js b/plugins/beta/datasets/src/api/getStyle.test.js index fc1b6232..21702a53 100644 --- a/plugins/beta/datasets/src/api/getStyle.test.js +++ b/plugins/beta/datasets/src/api/getStyle.test.js @@ -6,9 +6,7 @@ jest.mock('../registry/datasetRegistry.js', () => ({ datasetRegistry: { getDataset: jest.fn() } })) -jest.mock('../../../../../src/services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../../../../src/services/logger.js') describe('getStyle', () => { beforeEach(() => { diff --git a/plugins/beta/datasets/src/api/setData.test.js b/plugins/beta/datasets/src/api/setData.test.js index 80b18142..7805bc0a 100644 --- a/plugins/beta/datasets/src/api/setData.test.js +++ b/plugins/beta/datasets/src/api/setData.test.js @@ -13,9 +13,7 @@ jest.mock('../registry/datasetRegistry.js', () => ({ datasetRegistry: { getDataset: jest.fn() } })) -jest.mock('../../../../../src/services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../../../../src/services/logger.js') describe('setData', () => { const geojson = { type: 'FeatureCollection', features: [] } diff --git a/plugins/beta/datasets/src/api/setFeatureVisibility.test.js b/plugins/beta/datasets/src/api/setFeatureVisibility.test.js index 0dd5b5ca..a30b9fb8 100644 --- a/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +++ b/plugins/beta/datasets/src/api/setFeatureVisibility.test.js @@ -6,9 +6,7 @@ jest.mock('../registry/datasetRegistry.js', () => ({ datasetRegistry: { getDataset: jest.fn() } })) -jest.mock('../../../../../src/services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../../../../src/services/logger.js') describe('setFeatureVisibility', () => { const dispatch = jest.fn() diff --git a/plugins/beta/datasets/src/api/setGlobals.test.js b/plugins/beta/datasets/src/api/setGlobals.test.js index bb0e1651..6a107d22 100644 --- a/plugins/beta/datasets/src/api/setGlobals.test.js +++ b/plugins/beta/datasets/src/api/setGlobals.test.js @@ -1,9 +1,7 @@ import { setGlobals } from './setGlobals.js' import { logger } from '../../../../../src/services/logger.js' -jest.mock('../../../../../src/services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../../../../src/services/logger.js') describe('setGlobals', () => { const dispatch = jest.fn() diff --git a/plugins/beta/datasets/src/reducers/pluginState.test.js b/plugins/beta/datasets/src/reducers/pluginState.test.js index 68b4089b..9a608ef8 100644 --- a/plugins/beta/datasets/src/reducers/pluginState.test.js +++ b/plugins/beta/datasets/src/reducers/pluginState.test.js @@ -1,9 +1,7 @@ import { initialState, actions } from './pluginState.js' import { logger } from '../../../../../src/services/logger.js' -jest.mock('../../../../../src/services/logger.js', () => ({ - logger: { error: jest.fn() } -})) +jest.mock('../../../../../src/services/logger.js') // Helper: build a minimal plugin state with some mapped datasets const makeState = (overrides = {}) => ({ diff --git a/src/App/controls/keyboardActions.test.js b/src/App/controls/keyboardActions.test.js index b2f84bbb..620e6fed 100644 --- a/src/App/controls/keyboardActions.test.js +++ b/src/App/controls/keyboardActions.test.js @@ -7,9 +7,7 @@ jest.mock('../../services/reverseGeocode.js', () => ({ hasReverseGeocode: jest.fn() })) -jest.mock('../../services/logger.js', () => ({ - logger: { warn: jest.fn() } -})) +jest.mock('../../services/logger.js') const PAN_DELTA = 10 const NUDGE_PAN_DELTA = 5 diff --git a/src/App/renderer/mapButtons.test.js b/src/App/renderer/mapButtons.test.js index 8171a693..52d8ca12 100755 --- a/src/App/renderer/mapButtons.test.js +++ b/src/App/renderer/mapButtons.test.js @@ -3,7 +3,7 @@ import { mapButtons, getMatchingButtons, applySlotExclusivity, renderButton, res import { logger } from '../../services/logger.js' import { getPanelConfig } from '../registry/panelRegistry.js' -jest.mock('../../services/logger.js', () => ({ logger: { warn: jest.fn() } })) +jest.mock('../../services/logger.js') jest.mock('../registry/buttonRegistry.js') jest.mock('../registry/panelRegistry.js') jest.mock('../components/MapButton/MapButton.jsx', () => ({ diff --git a/src/InteractiveMap/deviceChecker.test.js b/src/InteractiveMap/deviceChecker.test.js index 6102998d..facbfbf2 100755 --- a/src/InteractiveMap/deviceChecker.test.js +++ b/src/InteractiveMap/deviceChecker.test.js @@ -5,7 +5,7 @@ import { logger } from '../services/logger.js' jest.mock('./renderError.js') jest.mock('./domStateManager.js') -jest.mock('../services/logger.js', () => ({ logger: { warn: jest.fn() } })) +jest.mock('../services/logger.js') describe('checkDeviceSupport', () => { let rootEl, config diff --git a/src/services/__mocks/logger.js b/src/services/__mocks__/logger.js similarity index 100% rename from src/services/__mocks/logger.js rename to src/services/__mocks__/logger.js