From 66e3435d6061e164774176d71532fca0c59891c3 Mon Sep 17 00:00:00 2001 From: Matteo V Date: Tue, 27 Aug 2019 15:05:49 +0200 Subject: [PATCH] Fix #4009 wms records and improved error handling (#4109) * Fix #4009 wms records and improved error handling * fix lint error --- docs/developer-guide/map-query-parameters.md | 10 +-- web/client/actions/__tests__/catalog-test.js | 10 ++- web/client/actions/catalog.js | 11 +++ web/client/epics/__tests__/catalog-test.js | 87 +++++++++++++++++++ web/client/epics/catalog.js | 47 ++++++---- web/client/translations/data.de-DE | 2 + web/client/translations/data.en-US | 2 + web/client/translations/data.es-ES | 2 + web/client/translations/data.fr-FR | 2 + web/client/translations/data.hr-HR | 2 + web/client/translations/data.it-IT | 2 + web/client/translations/data.nl-NL | 11 ++- web/client/translations/data.pt-PT | 2 + web/client/translations/data.vi-VN | 2 + web/client/translations/data.zh-ZH | 2 + web/client/utils/CatalogUtils.js | 4 +- .../utils/__tests__/CatalogUtils-test.js | 17 ++++ 17 files changed, 190 insertions(+), 25 deletions(-) diff --git a/docs/developer-guide/map-query-parameters.md b/docs/developer-guide/map-query-parameters.md index 08ced0e044..99eb18c61b 100644 --- a/docs/developer-guide/map-query-parameters.md +++ b/docs/developer-guide/map-query-parameters.md @@ -19,7 +19,7 @@ To dispatch additional actions when the map viewer is started, the **actions** q "initialActionsWhiteList": ["ZOOM_TO_EXTENT", "ADD_LAYER", ...] ``` -The value of this paramater is a JSON string containing an array with an object per action. The structure of the object consist of a property type and a bunch of other properties depending on the action. +The value of this parameter is a JSON string containing an array with an object per action. The structure of the object consist of a property type and a bunch of other properties depending on the action. ### Available actions Only the following actions can be used in the **actions** json string. @@ -78,18 +78,18 @@ For more details check out the [searchLayerWithFilter](https://mapstore2.geo-sol #### Add Layers -This action allows to add layers from catalog present in the map +This action allows to add layers directly to the map by taking them from the Catalogs Requirements: -- the number of values must be even -- catalog name must be present in the map +- The number of layers should match the number of sources +- The source name must match a catalog service name present in the map Example: ``` { "type": "CATALOG:ADD_LAYERS_FROM_CATALOGS", - "layers": ["layer1", "layer2"], + "layers": ["workspace1:layer1", "workspace2:layer2"], "sources": ["catalog1", "catalog2"] } ?actions=[{"type":"CATALOG:ADD_LAYERS_FROM_CATALOGS","layers":["layer1", "layer2"],"sources":["catalog1", "catalog2"]}] diff --git a/web/client/actions/__tests__/catalog-test.js b/web/client/actions/__tests__/catalog-test.js index 62e8ac1b1c..e2b51acfe5 100644 --- a/web/client/actions/__tests__/catalog-test.js +++ b/web/client/actions/__tests__/catalog-test.js @@ -21,9 +21,11 @@ const { changeUrl, CHANGE_URL, changeType, CHANGE_TYPE, addService, ADD_SERVICE, addCatalogService, ADD_CATALOG_SERVICE, resetCatalog, RESET_CATALOG, changeAutoload, CHANGE_AUTOLOAD, deleteCatalogService, DELETE_CATALOG_SERVICE, deleteService, DELETE_SERVICE, savingService, SAVING_SERVICE, DESCRIBE_ERROR, initCatalog, CATALOG_INITED, changeText, CHANGE_TEXT, - TOGGLE_ADVANCED_SETTINGS, toggleAdvancedSettings, TOGGLE_THUMBNAIL, toggleThumbnail, TOGGLE_TEMPLATE, toggleTemplate, CHANGE_METADATA_TEMPLATE, changeMetadataTemplate, SET_LOADING + TOGGLE_ADVANCED_SETTINGS, toggleAdvancedSettings, TOGGLE_THUMBNAIL, toggleThumbnail, TOGGLE_TEMPLATE, toggleTemplate, CHANGE_METADATA_TEMPLATE, changeMetadataTemplate, SET_LOADING, + recordsNotFound } = require('../catalog'); const {CHANGE_LAYER_PROPERTIES, ADD_LAYER} = require('../layers'); +const {SHOW_NOTIFICATION} = require('../notifications'); describe('Test correctness of the catalog actions', () => { it('addLayersMapViewerUrl', () => { @@ -295,4 +297,10 @@ describe('Test correctness of the catalog actions', () => { expect(action.type).toBe(CHANGE_METADATA_TEMPLATE); expect(action.metadataTemplate).toBe("${title}"); }); + it('test recordsNotFound action', () => { + const action = recordsNotFound("topp:states , topp:states-tasmania"); + expect(action.type).toBe(SHOW_NOTIFICATION); + expect(action.message).toBe("catalog.notification.errorSearchingRecords"); + expect(action.values).toEqual({records: "topp:states , topp:states-tasmania"}); + }); }); diff --git a/web/client/actions/catalog.js b/web/client/actions/catalog.js index 087e361f7e..6360f2988b 100644 --- a/web/client/actions/catalog.js +++ b/web/client/actions/catalog.js @@ -22,6 +22,7 @@ import * as ConfigUtils from '../utils/ConfigUtils'; import {find} from 'lodash'; import {authkeyParamNameSelector} from '../selectors/catalog'; + export const ADD_LAYERS_FROM_CATALOGS = 'CATALOG:ADD_LAYERS_FROM_CATALOGS'; export const TEXT_SEARCH = 'CATALOG:TEXT_SEARCH'; export const RECORD_LIST_LOADED = 'CATALOG:RECORD_LIST_LOADED'; @@ -281,3 +282,13 @@ export const changeMetadataTemplate = (metadataTemplate) => ({type: CHANGE_METAD export const toggleAdvancedSettings = () => ({type: TOGGLE_ADVANCED_SETTINGS}); export const toggleTemplate = () => ({type: TOGGLE_TEMPLATE}); export const toggleThumbnail = () => ({type: TOGGLE_THUMBNAIL}); + +import {error} from './notifications'; + +export function recordsNotFound(records = "") { + return error({ + title: "catalog.notification.errorTitle", + message: "catalog.notification.errorSearchingRecords", + values: {records} + }); +} diff --git a/web/client/epics/__tests__/catalog-test.js b/web/client/epics/__tests__/catalog-test.js index 5a029d64c2..8d344aceda 100644 --- a/web/client/epics/__tests__/catalog-test.js +++ b/web/client/epics/__tests__/catalog-test.js @@ -8,9 +8,11 @@ import expect from 'expect'; import csw from '../../api/CSW'; +import wms from '../../api/WMS'; import wmts from '../../api/WMTS'; const API = { csw, + wms, wmts }; import catalog from '../catalog'; @@ -37,6 +39,7 @@ import { SET_LOADING } from '../../actions/catalog'; + describe('catalog Epics', () => { it('getMetadataRecordById', (done) => { testEpic(getMetadataRecordById, 2, initAction(), (actions) => { @@ -185,6 +188,90 @@ describe('catalog Epics', () => { } }); }); + it('addLayersFromCatalogsEpic csw and wms both found', (done) => { + const NUM_ACTIONS = 3; + testEpic(addTimeoutEpic(addLayersFromCatalogsEpic, 10), NUM_ACTIONS, addLayersMapViewerUrl(["gs:us_states", "some_layer"], ["cswCatalog", "wmsCatalog"]), (actions) => { + expect(actions.length).toBe(NUM_ACTIONS); + actions.map((action) => { + switch (action.type) { + case ADD_LAYER: + if (action.layer.name === "gs:us_states") { + expect(action.layer.title).toBe("States of US"); + expect(action.layer.type).toBe("wms"); + expect(action.layer.url).toBe("https://sample.server/geoserver/wms"); + } else { + expect(action.layer.name).toBe("some_layer"); + expect(action.layer.title).toBe("some layer"); + expect(action.layer.type).toBe("wms"); + expect(action.layer.url).toBe("base/web/client/test-resources/wms/attribution.xml"); + } + break; + case TEST_TIMEOUT: + break; + default: + expect(true).toBe(false); + } + }); + done(); + }, { + catalog: { + delayAutoSearch: 50, + selectedService: "cswCatalog", + services: { + "cswCatalog": { + type: "csw", + url: "base/web/client/test-resources/csw/getRecordsResponse-gs-us_states.xml" + }, + "wmsCatalog": { + type: "wms", + url: "base/web/client/test-resources/wms/attribution.xml" + } + }, + pageSize: 2 + } + }); + }); + it('addLayersFromCatalogsEpic csw found and wms not found', (done) => { + const NUM_ACTIONS = 3; + testEpic(addTimeoutEpic(addLayersFromCatalogsEpic, 10), NUM_ACTIONS, addLayersMapViewerUrl(["gs:us_states", "not_found"], ["cswCatalog", "wmsCatalog"]), (actions) => { + expect(actions.length).toBe(NUM_ACTIONS); + actions.map((action) => { + switch (action.type) { + case ADD_LAYER: + expect(action.layer.name).toBe("gs:us_states"); + expect(action.layer.title).toBe("States of US"); + expect(action.layer.type).toBe("wms"); + expect(action.layer.url).toBe("https://sample.server/geoserver/wms"); + break; + case SHOW_NOTIFICATION: + expect(action.message).toBe("catalog.notification.errorSearchingRecords"); + expect(action.values).toEqual({records: "not_found"}); + break; + case TEST_TIMEOUT: + break; + default: + expect(true).toBe(false); + } + }); + done(); + }, { + catalog: { + delayAutoSearch: 50, + selectedService: "cswCatalog", + services: { + "cswCatalog": { + type: "csw", + url: "base/web/client/test-resources/csw/getRecordsResponse-gs-us_states.xml" + }, + "wmsCatalog": { + type: "wms", + url: "base/web/client/test-resources/wms/attribution.xml" + } + }, + pageSize: 2 + } + }); + }); it('addLayersFromCatalogsEpic wmts', (done) => { const NUM_ACTIONS = 2; testEpic(addTimeoutEpic(addLayersFromCatalogsEpic, 0), NUM_ACTIONS, addLayersMapViewerUrl(["topp:tasmania_cities_hidden"], ["cswCatalog"]), (actions) => { diff --git a/web/client/epics/catalog.js b/web/client/epics/catalog.js index 3bece0ad7b..6a8019cf31 100644 --- a/web/client/epics/catalog.js +++ b/web/client/epics/catalog.js @@ -7,7 +7,7 @@ */ import * as Rx from 'rxjs'; -import {head, isArray} from 'lodash'; +import {head, isArray, isString, isObject} from 'lodash'; import { ADD_SERVICE, ADD_LAYERS_FROM_CATALOGS, @@ -18,6 +18,7 @@ import { addCatalogService, setLoading, deleteCatalogService, + recordsNotFound, recordsLoaded, recordsLoadError, savingService, @@ -94,7 +95,9 @@ module.exports = (API) => ({ addLayersFromCatalogsEpic: (action$, store) => action$.ofType(ADD_LAYERS_FROM_CATALOGS) .filter(({layers, sources}) => isArray(layers) && isArray(sources) && layers.length && layers.length === sources.length) - .switchMap(({layers, sources, options, startPosition = 1, maxRecords = 1 }) => { + // maxRecords is 4 (by default), but there can be a possibility that the record desired is not among + // the results. In that case a more detailed search with full record name can be helpful + .switchMap(({layers, sources, options, startPosition = 1, maxRecords = 4 }) => { const state = store.getState(); const addLayerOptions = options || searchOptionsSelector(state); const services = servicesSelector(state); @@ -104,23 +107,17 @@ module.exports = (API) => ({ const {type: format, url} = services[sources[i]]; const text = layers[i]; return Rx.Observable.defer( () => - API[format].textSearch(url, startPosition, maxRecords, text, addLayerOptions) - ).map(r => ({...r, format, url})); + API[format].textSearch(url, startPosition, maxRecords, text, addLayerOptions).catch(() => ({results: []})) + ).map(r => ({...r, format, url, text})); }); return Rx.Observable.forkJoin(actions) .switchMap((results) => { if (isArray(results) && results.length) { - return Rx.Observable.from(results.filter(r => { - // filter results with no records - const {format, url, ...result} = r; + return Rx.Observable.of(results.map(r => { + const {format, url, text, ...result} = r; const locales = currentMessagesSelector(state); const records = getCatalogRecords(format, result, addLayerOptions, locales) || []; - return records && records.length >= 1; - }).map(r => { - const {format, url, ...result} = r; - const locales = currentMessagesSelector(state); - const records = getCatalogRecords(format, result, addLayerOptions, locales) || []; - const record = head(records); + const record = head(records.filter(rec => rec.identifier === text)); // exact match of text and record identifier const {wms, wmts} = extractOGCServicesReferences(record); let layer = {}; const layerBaseConfig = {}; // DO WE NEED TO FETCH IT FROM STATE??? @@ -133,7 +130,7 @@ module.exports = (API) => ({ } layer = recordToLayer(record, "wms", { removeParams: authkeyParamName, - catalogURL: format === 'csw' && url ? url + "?request=GetRecordById&service=CSW&version=2.0.2&elementSetName=full&id=" + record.identifier : null + catalogURL: format === 'csw' && url ? url + "?request=GetRecordById&service=CSW&version=2.0.2&elementSetName=full&id=" + record.identifier : url }, layerBaseConfig); } else if (wmts) { layer = {}; @@ -151,12 +148,30 @@ module.exports = (API) => ({ layer = esriToLayer(record, layerBaseConfig); } } - return addLayer(layer); + if (!record) { + return text; + } + return layer; })); } return Rx.Observable.empty(); }); - }).catch( () => { + }) + .mergeMap(results => { + if (results) { + const allRecordsNotFound = results.filter(r => isString(r)).join(" "); + let actions = []; + if (allRecordsNotFound) { + // return one notification for all records that have not been found + actions = [recordsNotFound(allRecordsNotFound)]; + } + // add all layers found to the map + actions = [...actions, ...results.filter(r => isObject(r)).map(r => addLayer(r))]; + return Rx.Observable.from(actions); + } + return Rx.Observable.empty(); + }) + .catch( () => { return Rx.Observable.empty(); }), /** diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE index 633852ed70..d32af36b65 100644 --- a/web/client/translations/data.de-DE +++ b/web/client/translations/data.de-DE @@ -1138,6 +1138,8 @@ "advancedSettings": "Erweiterte Einstellungen", "templateMetadataAvailable": "Metadaten im Dublin Core-Format verfügbar: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Einige Datensätze wurden nicht gefunden: {records} . Bitte überprüfen Sie die URL des Abfrageparameters", "warningAddCatalogService": "Geben Sie eine gültige URL und einen Titel ein", "addCatalogService": "Service wurde korrekt hinzugefügt", "duplicatedServiceTitle": "Ein Service mit diesem Titel existiert bereits, bitte ändere den Titel", diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US index e3cb0ea7c3..38cc550ff7 100644 --- a/web/client/translations/data.en-US +++ b/web/client/translations/data.en-US @@ -1139,6 +1139,8 @@ "advancedSettings": "Advanced settings", "templateMetadataAvailable": "Metadata available from Dublin Core format: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Some records have not been found: {records} Please check the query param url", "warningAddCatalogService": "Insert a valid url and title", "addCatalogService": "Service added correctly", "duplicatedServiceTitle": "A service with that title already exists. Please, change title", diff --git a/web/client/translations/data.es-ES b/web/client/translations/data.es-ES index 3749a85e88..55b62cabdc 100644 --- a/web/client/translations/data.es-ES +++ b/web/client/translations/data.es-ES @@ -1138,6 +1138,8 @@ "advancedSettings": "Ajustes avanzados", "templateMetadataAvailable": "Metadatos disponibles en formato Dublin Core: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "No se han encontrado algunos registros: {records} . Por favor revise la consulta param url", "warningAddCatalogService": "Introduzca una url y un título válidos", "addCatalogService": "Servicio añadido correctamente", "duplicatedServiceTitle": "Ya existe un servicio con ese título, Por favor, cambie el título", diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR index b544f6b83b..d8130d5874 100644 --- a/web/client/translations/data.fr-FR +++ b/web/client/translations/data.fr-FR @@ -1138,6 +1138,8 @@ "advancedSettings": "Réglages avancés", "templateMetadataAvailable": "Métadonnées disponibles au format Dublin Core: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Erreur", + "errorSearchingRecords": "Certains enregistrements n'ont pas été trouvés: {records} . S'il vous plaît vérifier la requête param url", "warningAddCatalogService": "Insérer une URL et un titre valides", "addCatalogService": "Service ajouté correctement", "duplicatedServiceTitle": "Un service avec ce titre existe déjà, veuillez modifier le titre", diff --git a/web/client/translations/data.hr-HR b/web/client/translations/data.hr-HR index 9aa9bb8026..1dab3e482e 100644 --- a/web/client/translations/data.hr-HR +++ b/web/client/translations/data.hr-HR @@ -1139,6 +1139,8 @@ "advancedSettings": "Napredne mogućnosti", "templateMetadataAvailable": "Metapodaci distupni iz Dublin Core formata: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Some records have not been found: {records} Please check the query param url", "warningAddCatalogService": "Unesi ispravni url i naslov", "addCatalogService": "Servis je dodan ispravno", "duplicatedServiceTitle": "Servis sa tim naslovom već postoji. Molim, promijenite naslov", diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT index 6e57a1ab5f..8fcd223337 100644 --- a/web/client/translations/data.it-IT +++ b/web/client/translations/data.it-IT @@ -1138,6 +1138,8 @@ "advancedSettings": "Impostazioni avanzante", "templateMetadataAvailable": "Metadati disponibili del formato Dublin Core: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Errore", + "errorSearchingRecords": "Alcuni record non sono stati trovati: {records} . Controlla la lista dei parametri nella barra degli indirizzi", "warningAddCatalogService": "Inserisci un url e titolo validi.", "addCatalogService": "Servizio aggiunto corretamente.", "duplicatedServiceTitle": "Un servizio con quel titolo esiste già, Per favore cambia titolo", diff --git a/web/client/translations/data.nl-NL b/web/client/translations/data.nl-NL index 0cee8968a8..534b64699e 100644 --- a/web/client/translations/data.nl-NL +++ b/web/client/translations/data.nl-NL @@ -1062,7 +1062,16 @@ "showTemplate": "Show metadata template", "showPreview": "Show preview", "advancedSettings": "Advanced Settings", - "templateMetadataAvailable": "Metadata available from Dublin Core format: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri" + "templateMetadataAvailable": "Metadata available from Dublin Core format: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", + "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Some records have not been found: {records} Please check the query param url", + "warningAddCatalogService": "Insert a valid url and title", + "addCatalogService": "Service added correctly", + "duplicatedServiceTitle": "A service with that title already exists. Please, change title", + "serviceDeletedCorrectly": "The service was deleted correctly", + "errorServiceUrl": "Service not available. Please, check the provided url" + } }, "uploader": { "filename": "File Name", diff --git a/web/client/translations/data.pt-PT b/web/client/translations/data.pt-PT index 2569f79e6a..8f06d348b8 100644 --- a/web/client/translations/data.pt-PT +++ b/web/client/translations/data.pt-PT @@ -1115,6 +1115,8 @@ "advancedSettings": "Advanced Settings", "templateMetadataAvailable": "Metadata available from Dublin Core format: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Some records have not been found: {records} Please check the query param url", "warningAddCatalogService": "Insert a valid url and title", "addCatalogService": "Service added correctly", "duplicatedServiceTitle": "A service with that title already exists. Please, change title", diff --git a/web/client/translations/data.vi-VN b/web/client/translations/data.vi-VN index 0b6741e5b8..6f3d71d173 100644 --- a/web/client/translations/data.vi-VN +++ b/web/client/translations/data.vi-VN @@ -144,6 +144,8 @@ "noResultsText": "Không có kết quả", "notAvailable": "Không có sẵn", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Some records have not been found: {records} Please check the query param url", "addCatalogService": "Dịch vụ được thêm chính xác", "duplicatedServiceTitle": "Một dịch vụ với tiêu đề đó đã tồn tại. Xin vui lòng đổi tiêu đề", "errorServiceUrl": "Dịch vụ không có sẵn. Vui lòng kiểm tra URL được cung cấp", diff --git a/web/client/translations/data.zh-ZH b/web/client/translations/data.zh-ZH index a71a726c59..dd0abd2b74 100644 --- a/web/client/translations/data.zh-ZH +++ b/web/client/translations/data.zh-ZH @@ -1091,6 +1091,8 @@ "advancedSettings": "Advanced Settings", "templateMetadataAvailable": "Metadata available from Dublin Core format: abstract, boundingBox, contributor, creator, description, format, identifier, references, rights, source, subject, temporal, title, type, uri", "notification": { + "errorTitle": "Error", + "errorSearchingRecords": "Some records have not been found: {records} Please check the query param url", "warningAddCatalogService": "Insert a valid url and title", "addCatalogService": "Service added correctly", "duplicatedServiceTitle": "A service with that title already exists. Please, change title", diff --git a/web/client/utils/CatalogUtils.js b/web/client/utils/CatalogUtils.js index 12d3b913b9..7d7b9085c4 100644 --- a/web/client/utils/CatalogUtils.js +++ b/web/client/utils/CatalogUtils.js @@ -414,11 +414,11 @@ const CatalogUtils = { const urls = ogcServiceReference.url; // extract additional parameters and alternative URLs. - if (isArray(urls)) { + if (urls && isArray(urls)) { originalUrl = urls.map( u => cleanURL(u)).map( ({url: u}) => u); params = urls.map(u => cleanURL(u)).map(({params: p}) => p).reduce( (prev, cur) => ({...prev, ...cur}), {}); } else { - const { url: uu, params: pp } = cleanURL(urls); + const { url: uu, params: pp } = cleanURL(urls || catalogURL); originalUrl = uu; params = pp; } diff --git a/web/client/utils/__tests__/CatalogUtils-test.js b/web/client/utils/__tests__/CatalogUtils-test.js index 3c263236bd..3d34853599 100644 --- a/web/client/utils/__tests__/CatalogUtils-test.js +++ b/web/client/utils/__tests__/CatalogUtils-test.js @@ -98,6 +98,23 @@ describe('Test the CatalogUtils', () => { expect(layer.allowedSRS['EPSG:5041']).toNotExist(); }); + it('wms with no ogcServiceReference.url', () => { + const records = CatalogUtils.getCatalogRecords( + 'wms', + { + records: [{ + SRS: ['EPSG:4326', 'EPSG:3857', 'EPSG:5041'] + }] + }, { + url: undefined + }); + expect(records.length).toBe(1); + const sampleUrl = "http://sample"; + const layer = CatalogUtils.recordToLayer(records[0], "wms", {catalogURL: sampleUrl}); + + expect(layer.url).toBe(sampleUrl); + }); + it('wmts', () => { const records = CatalogUtils.getCatalogRecords('wmts', { records: [{}]