UNPKG

terriajs

Version:

Geospatial data visualization platform.

471 lines (428 loc) 17.4 kB
import { http, HttpResponse } from "msw"; import { runInAction } from "mobx"; import CommonStrata from "../../../../lib/Models/Definition/CommonStrata"; import SensorObservationServiceCatalogItem from "../../../../lib/Models/Catalog/Ows/SensorObservationServiceCatalogItem"; import Terria from "../../../../lib/Models/Terria"; import SimpleCatalogItem from "../../../Helpers/SimpleCatalogItem"; import TableAutomaticStylesStratum from "../../../../lib/Table/TableAutomaticStylesStratum"; import { isEnum } from "../../../../lib/Models/SelectableDimensions/SelectableDimensions"; import { worker } from "../../../mocks/browser"; import GetFeatureOfInterestResponse from "../../../../wwwroot/test/sos/GetFeatureOfInterestResponse.xml"; import EmptyGetFeatureOfInterestResponse from "../../../../wwwroot/test/sos/GetFeatureOfInterestResponse_NoMembers.xml"; import GetObservationResponseDaily from "../../../../wwwroot/test/sos/GetObservationResponse_Daily.xml"; import GetObservationResponseYearly from "../../../../wwwroot/test/sos/GetObservationResponse_Yearly.xml"; import regionMapping from "../../../../wwwroot/data/regionMapping.json"; describe("SensorObservationServiceCatalogItem", function () { let item: SensorObservationServiceCatalogItem; beforeEach(function () { worker.use( http.get("*/build/TerriaJS/data/regionMapping.json", () => HttpResponse.json(regionMapping) ) ); item = new SensorObservationServiceCatalogItem("test", new Terria()); item.setTrait(CommonStrata.user, "url", "https://sos.example.com"); const proc1 = item.addObject(CommonStrata.user, "procedures", "proc1"); proc1?.setTrait(CommonStrata.user, "identifier", "Daily Mean"); proc1?.setTrait(CommonStrata.user, "title", "Daily Mean"); const proc2 = item.addObject(CommonStrata.user, "procedures", "proc2"); proc2?.setTrait(CommonStrata.user, "identifier", "Yearly Mean"); proc2?.setTrait(CommonStrata.user, "title", "Yearly Mean"); const prop1 = item.addObject( CommonStrata.user, "observableProperties", "prop1" ); prop1?.setTrait(CommonStrata.user, "identifier", "Storage Level"); prop1?.setTrait(CommonStrata.user, "title", "Storage Level"); prop1?.setTrait(CommonStrata.user, "units", "mm"); const prop2 = item.addObject( CommonStrata.user, "observableProperties", "prop2" ); prop2?.setTrait(CommonStrata.user, "identifier", "Ph"); prop2?.setTrait(CommonStrata.user, "title", "Ph"); item.setTrait(CommonStrata.user, "proceduresName", "Frequency"); item.setTrait( CommonStrata.user, "observablePropertiesName", "Observation Type" ); }); describe("when constructed", function () { it("correctly sets the sourceReference", function () { const terria = new Terria(); const sourceItem = new SimpleCatalogItem(undefined, terria); const sosItem = new SensorObservationServiceCatalogItem( undefined, terria, sourceItem ); expect(sosItem.sourceReference).toBe(sourceItem); }); it("correctly initializes the automatic stratum", function () { const terria = new Terria(); const sourceItem = new SimpleCatalogItem(undefined, terria); const sosItem = new SensorObservationServiceCatalogItem( undefined, terria, sourceItem ); expect( sosItem.strata.get(TableAutomaticStylesStratum.stratumName) ).toBeDefined(); }); }); describe("features table", function () { describe("when loading", function () { it("makes a GetFeatureOfInterest request", async function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if ( !body.includes("sos:GetFeatureOfInterest") || !body.includes("/foiRetrieval/") || !body.includes( "<sos:observedProperty>Storage Level</sos:observedProperty>" ) || !body.includes( "<sos:observedProperty>Ph</sos:observedProperty>" ) || !body.includes("<sos:procedure>Daily Mean</sos:procedure>") || !body.includes("<sos:procedure>Yearly Mean</sos:procedure>") ) { return HttpResponse.error(); } return new HttpResponse(GetFeatureOfInterestResponse, { headers: { "Content-Type": "text/xml" } }); }) ); const result = await item.loadMapItems(); expect(result.error).toBeUndefined(); }); describe("when `filterByProcedures` is false", function () { it("should not add any procedures to the request", async function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if (body.includes("sos:procedure")) { return HttpResponse.error(); } if (body.includes("<sos:GetFeatureOfInterest")) { return new HttpResponse(GetFeatureOfInterestResponse, { headers: { "Content-Type": "text/xml" } }); } return new HttpResponse(null, { status: 404 }); }) ); item.setTrait(CommonStrata.user, "filterByProcedures", false); const response = await runInAction(() => item.loadMapItems()); expect(response.error).toBeUndefined(); }); }); it("throws an error if features is empty", async function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if (body.includes("<sos:GetFeatureOfInterest")) { return new HttpResponse(EmptyGetFeatureOfInterestResponse, { headers: { "Content-Type": "text/xml" } }); } return new HttpResponse(null, { status: 404 }); }) ); const ex = (await item.loadMapItems()).error; expect(ex).toBeDefined(); }); }); describe("when loaded", function () { beforeEach(function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if ( !body.includes("sos:GetFeatureOfInterest") || !body.includes("/foiRetrieval/") || !body.includes( "<sos:observedProperty>Storage Level</sos:observedProperty>" ) || !body.includes( "<sos:observedProperty>Ph</sos:observedProperty>" ) || !body.includes("<sos:procedure>Daily Mean</sos:procedure>") || !body.includes("<sos:procedure>Yearly Mean</sos:procedure>") ) { return HttpResponse.error(); } if (body.includes("<sos:GetFeatureOfInterest")) { return new HttpResponse(GetFeatureOfInterestResponse, { headers: { "Content-Type": "text/xml" } }); } return new HttpResponse(null, { status: 404 }); }) ); }); it("defines all feature columns", async function () { await item.loadMapItems(); expect(item.tableColumns.map((c) => c.name)).toEqual([ "identifier", "lat", "lon", "name", "id", "type", "chart" ]); }); it("populates the column values correctly", async function () { await item.loadMapItems(); const values: any = { identifier: [ "http://sos.example.com/stations/1", "http://sos.example.com/stations/2", "http://sos.example.com/stations/3" ], lat: ["-36.0", "-32.0", "-34.0"], lon: ["139.0", "126.0", "132.0"], name: ["Feature 1", "Feature 2", "Feature 3"], id: ["Ki.FM.1", "Ki.FM.2", "Ki.FM.3"], type: [ "http://www.opengis.net/def/samplingFeatureType/OGC-OM/2.0/SF_SamplingPoint", "http://www.opengis.net/def/samplingFeatureType/OGC-OM/2.0/SF_SamplingPoint", "http://www.opengis.net/def/samplingFeatureType/OGC-OM/2.0/SF_SamplingPoint" ] }; item.tableColumns .slice(0, -1) .forEach((col) => expect(col.values).toEqual(values[col.name])); // just test that the chart columns have chart component defined item.tableColumns .slice(-1)[0] .values.forEach((value) => expect(value).toContain("<sos-chart ")); }); describe("with a station id whiteliest", function () { it("should only have points for the white listed stations", async function () { item.setTrait(CommonStrata.user, "stationIdWhitelist", [ "http://sos.example.com/stations/1" ]); await item.loadMapItems(); const col = item.findColumnByName("identifier"); expect(col).toBeDefined(); expect(col?.values).toEqual(["http://sos.example.com/stations/1"]); }); }); describe("with a station id blacklist", function () { it("should not have points for the black listed stations", async function () { item.setTrait(CommonStrata.user, "stationIdBlacklist", [ "http://sos.example.com/stations/1" ]); await item.loadMapItems(); const col = item.findColumnByName("identifier"); expect(col).toBeDefined(); expect(col?.values).not.toContain( "http://sos.example.com/stations/1" ); }); }); it("sets the style selectors correctly", async function () { await item.loadMapItems(); expect(item.selectableDimensions.map((s) => s.name)).toEqual([ "Frequency", "Observation Type" ]); }); it("shows all options for the procedure selector", async function () { await item.loadMapItems(); const procedureSelector = item.selectableDimensions.find( (s) => s.name === "Frequency" ); expect(procedureSelector && isEnum(procedureSelector)).toBeTruthy(); if (!procedureSelector || !isEnum(procedureSelector)) throw "Invalid procedureSelector"; if (procedureSelector) { expect(procedureSelector.options?.length).toEqual(4); } }); }); }); describe("observations table", function () { beforeEach(function () { item.setTrait(CommonStrata.user, "showAsChart", true); item.setTrait( CommonStrata.user, "chartFeatureOfInterestIdentifier", "feature1" ); item.setTrait(CommonStrata.user, "startDate", "2020-01-26T03:56:15.025Z"); item.setTrait(CommonStrata.user, "endDate", "2020-03-26T03:56:15.025Z"); }); describe("when loading", function () { it("makes a GetObservation request", async function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if ( !body.includes("sos:GetObservation") || !body.includes("/core/") || !body.includes( "<sos:observedProperty>Storage Level</sos:observedProperty>" ) || !body.includes( "<sos:featureOfInterest>feature1</sos:featureOfInterest>" ) || !body.includes( "<gml:beginPosition>2020-01-26T03:56:15.025Z</gml:beginPosition>" ) || !body.includes( "<gml:beginPosition>2020-01-26T03:56:15.025Z</gml:beginPosition>" ) || !body.includes( "<gml:endPosition>2020-03-26T03:56:15.025Z</gml:endPosition>" ) ) { return HttpResponse.error(); } if (/<sos:GetObservation[\s\S]*Yearly/.test(body)) { return new HttpResponse(GetObservationResponseYearly, { headers: { "Content-Type": "text/xml" } }); } if (/<sos:GetObservation[\s\S]*Daily/.test(body)) { return new HttpResponse(GetObservationResponseDaily, { headers: { "Content-Type": "text/xml" } }); } return new HttpResponse(null, { status: 404 }); }) ); const result = await runInAction(() => item.loadMapItems()); expect(result.error).toBeUndefined(); }); it("sets the procedure based on active style", async function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if (body.includes("<sos:procedure>Yearly Mean</sos:procedure>")) { return HttpResponse.error(); } if (body.includes("<sos:procedure>Daily Mean</sos:procedure>")) { return new HttpResponse(GetObservationResponseDaily, { headers: { "Content-Type": "text/xml" } }); } return HttpResponse.error(); }) ); item.setTrait(CommonStrata.user, "activeStyle", "Daily Mean"); const resultDaily = await item.loadMapItems(); expect(resultDaily.error).toBeUndefined(); worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if (body.includes("<sos:procedure>Daily Mean</sos:procedure>")) { return HttpResponse.error(); } if (body.includes("<sos:procedure>Yearly Mean</sos:procedure>")) { return new HttpResponse(GetObservationResponseYearly, { headers: { "Content-Type": "text/xml" } }); } return HttpResponse.error(); }) ); item.setTrait(CommonStrata.user, "activeStyle", "Yearly Mean"); // Shouldn't have to force this... const responseYearly = await item.loadMapItems(true); expect(responseYearly.error).toBeUndefined(); }); }); describe("when loaded", function () { beforeEach(async function () { worker.use( http.post("https://sos.example.com/", async ({ request }) => { const body = await request.text(); if ( !body.includes("sos:GetObservation") || !body.includes("/core/") || !body.includes( "<sos:observedProperty>Storage Level</sos:observedProperty>" ) || !body.includes( "<sos:featureOfInterest>feature1</sos:featureOfInterest>" ) || !body.includes( "<gml:beginPosition>2020-01-26T03:56:15.025Z</gml:beginPosition>" ) || !body.includes( "<gml:beginPosition>2020-01-26T03:56:15.025Z</gml:beginPosition>" ) || !body.includes( "<gml:endPosition>2020-03-26T03:56:15.025Z</gml:endPosition>" ) ) { return HttpResponse.error(); } if (/<sos:GetObservation[\s\S]*Yearly/.test(body)) { return new HttpResponse(GetObservationResponseYearly, { headers: { "Content-Type": "text/xml" } }); } if (/<sos:GetObservation[\s\S]*Daily/.test(body)) { return new HttpResponse(GetObservationResponseDaily, { headers: { "Content-Type": "text/xml" } }); } return new HttpResponse(null, { status: 404 }); }) ); await runInAction(() => item.loadMapItems()); }); it("defines all feature columns", function () { expect(item.tableColumns.map((c) => c.name)).toEqual([ "date", "values", "observations", "identifiers", "Frequency", "Observation Type" ]); }); it("sets populates the column values correctly", function () { const dates = [ "2016-08-09T02:00:00.000+10:00", "2016-08-10T02:00:00.000+10:00", "2016-08-11T02:00:00.000+10:00", "2016-08-09T02:00:00.000+10:00", "2016-08-10T02:00:00.000+10:00", "2016-08-11T02:00:00.000+10:00", "2016-08-07T00:00:00.000+10:00", "2016-08-08T00:00:00.000+10:00", "2016-08-09T00:00:00.000+10:00", "2016-08-10T00:00:00.000+10:00", "2016-08-11T00:00:00.000+10:00" ]; const values = [ "", "29.425", "23.123", "4.575", "2.991", "", "3.066", "2.981", "10.136", "10.088", "" ]; const cols = item.tableColumns; expect(cols[0].values).toEqual(dates); expect(cols[1].values).toEqual(values); }); }); }); });