terriajs
Version:
Geospatial data visualization platform.
345 lines (299 loc) • 13.5 kB
text/typescript
import { action, runInAction } from "mobx";
import Cartesian3 from "terriajs-cesium/Source/Core/Cartesian3";
import queryToObject from "terriajs-cesium/Source/Core/queryToObject";
import Entity from "terriajs-cesium/Source/DataSources/Entity";
import SplitDirection from "terriajs-cesium/Source/Scene/SplitDirection";
import URI from "urijs";
import { USER_ADDED_CATEGORY_ID } from "../../../../../lib/Core/addedByUser";
import PickedFeatures from "../../../../../lib/Map/PickedFeatures/PickedFeatures";
import addUserCatalogMember from "../../../../../lib/Models/Catalog/addUserCatalogMember";
import GeoJsonCatalogItem from "../../../../../lib/Models/Catalog/CatalogItems/GeoJsonCatalogItem";
import WebMapServiceCatalogItem from "../../../../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem";
import CommonStrata from "../../../../../lib/Models/Definition/CommonStrata";
import { BaseModel } from "../../../../../lib/Models/Definition/Model";
import TerriaFeature from "../../../../../lib/Models/Feature/Feature";
import { InitSourceData } from "../../../../../lib/Models/InitSource";
import Terria from "../../../../../lib/Models/Terria";
import { setViewerMode } from "../../../../../lib/Models/ViewerMode";
import ViewState from "../../../../../lib/ReactViewModels/ViewState";
import {
buildShareLink,
isShareable,
SHARE_VERSION
} from "../../../../../lib/ReactViews/Map/Panels/SharePanel/BuildShareLink";
import bikeRacksGeoJson from "../../../../../wwwroot/test/GeoJSON/bike_racks.geojson" with { type: "json" };
let terria: Terria;
let viewState: ViewState;
beforeEach(function () {
terria = new Terria({
baseUrl: "./"
});
// terria.baseMap = {
// name: "Bing Maps Aerial"
// };
viewState = new ViewState({
terria: terria,
catalogSearchProvider: undefined
});
});
const decodeAndParseStartHash = (url: string) => {
const parsed = URI.parse(url);
if (parsed.fragment) {
return JSON.parse(queryToObject(parsed.fragment)["start"]);
}
};
const flattenInitSources = (initSources: InitSourceData[]): InitSourceData =>
initSources.reduce(
(acc: InitSourceData, initSource: InitSourceData) =>
Object.assign(acc, initSource),
{}
);
describe("BuildShareLink", function () {
it("should generate a url with default catalog related flags missing/undefined", function () {
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
expect(params.version).toBe(SHARE_VERSION);
expect(initSources.previewedItemId).toBeUndefined();
});
describe("user added model containing local data", function () {
it("should not be serialized", async function () {
const modelId = "Test";
const model = new GeoJsonCatalogItem(modelId, terria);
const blob = new Blob([JSON.stringify(bikeRacksGeoJson)], {
type: "application/json"
});
model.setFileInput(blob as File);
terria.addModel(model);
expect(terria.getModelById(BaseModel, modelId)).toBe(model);
expect(isShareable(terria)(modelId)).toBe(false);
await addUserCatalogMember(terria, model);
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
expect(
initSources.models?.[USER_ADDED_CATEGORY_ID].members
).not.toContain(model.uniqueId);
});
it("should not be added to workbench in generated url", async function () {
const modelId = "Test";
const model = new GeoJsonCatalogItem(modelId, terria);
const blob = new Blob([JSON.stringify(bikeRacksGeoJson)], {
type: "application/json"
});
model.setFileInput(blob as File);
terria.addModel(model);
await addUserCatalogMember(terria, model);
await terria.workbench.add(model);
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
expect(initSources.workbench).not.toContain(model.uniqueId);
});
});
describe("user added model containing no local data", function () {
let model: BaseModel;
beforeEach(function () {
model = new WebMapServiceCatalogItem("Test", terria);
runInAction(() => {
model.setTrait(
CommonStrata.definition,
"url",
"test/WMS/single_metadata_url.xml"
);
});
terria.addModel(model);
});
it("should be serialized", async function () {
await addUserCatalogMember(terria, model);
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
expect(model.uniqueId).toBeDefined();
expect(isShareable(terria)(model.uniqueId ?? "")).toBe(true);
expect(initSources.models?.[USER_ADDED_CATEGORY_ID].members).toContain(
model.uniqueId
);
});
it("should be added to workbench in generated url", async function () {
await addUserCatalogMember(terria, model);
await terria.workbench.add(model);
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
expect(initSources.workbench).toContain(model.uniqueId);
});
});
describe("should generate a url that opens to the catalog", function () {
beforeEach(function () {
terria.catalog.userAddedDataGroup.addMembersFromJson(CommonStrata.user, [
{
id: "ABC",
name: "abc",
type: "wms",
url: "test/WMS/single_metadata_url.xml"
}
]);
});
// sharing active tab category not implemented in mobx yet
// it("when the explorer window is open without a previewed catalog item", function() {
// viewState.openAddData();
// const shareLink = buildShareLink(terria, viewState);
// const params = decodeAndParseStartHash(shareLink);
// const initSources = flattenInitSources(params.initSources);
// expect(initSources.previewedItemId).toBe(undefined);
// // expect(initSources.sharedFromExplorerPanel).toBe(true);
// // expect(viewState.activeTabCategory).toBe(DATA_CATALOG_NAME);
// });
describe("opening to the user added tab", function () {
// below case is impossible with the UI at the moment, but we might want to
// share the 'empty-user-catalog-as-drag-and-drop' state in the future
// it("without a previewed item", function() {
// viewState.openUserData();
// const shareLink = buildShareLink(terria, viewState);
// const params = decodeAndParseStartHash(shareLink);
// const initSources = flattenInitSources(params.initSources);
// expect(initSources.previewedItemId).toBe(undefined);
// // expect(initSources.sharedFromExplorerPanel).toBe(true);
// // expect(viewState.activeTabCategory).toBe(USER_DATA_NAME);
// });
it("viewing a previewed item", async function () {
const model = terria.catalog.userAddedDataGroup.memberModels[0];
// preview the user added item & the share link should reflect that
await viewState.viewCatalogMember(model);
const shareLink = buildShareLink(terria, viewState);
let params = decodeAndParseStartHash(shareLink);
let initSources = flattenInitSources(params.initSources);
expect(initSources.previewedItemId).toBe(model.uniqueId);
// close the catalog & the share link should reflect that
viewState.closeCatalog();
params = decodeAndParseStartHash(buildShareLink(terria, viewState));
initSources = flattenInitSources(params.initSources);
expect(initSources.previewedItemId).toBeUndefined();
});
});
});
describe("sharing picked features", function () {
it(
"captures the picked position",
action(function () {
terria.pickedFeatures = new PickedFeatures();
terria.pickedFeatures.pickPosition = new Cartesian3(
17832.12,
83234.52,
952313.73
);
terria.pickedFeatures.features.push(new TerriaFeature({}));
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
const pickCoords = initSources.pickedFeatures?.pickCoords;
expect(pickCoords?.lat.toFixed(2)).toEqual("84.93");
expect(pickCoords?.lng.toFixed(2)).toEqual("77.91");
expect(pickCoords?.height.toFixed(2)).toEqual("-5400810.41");
})
);
it(
"captures the tile coordinates of the picked imagery providers",
action(function () {
terria.pickedFeatures = new PickedFeatures();
terria.pickedFeatures.pickPosition = new Cartesian3(
17832.12,
83234.52,
952313.73
);
terria.pickedFeatures.providerCoords = {
"https://foo": { x: 123, y: 456, level: 7 },
"https://bar": { x: 42, y: 42, level: 4 }
};
terria.pickedFeatures.features.push(new TerriaFeature({}));
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
const providerCoords = initSources.pickedFeatures?.providerCoords;
expect(providerCoords).toEqual({
"https://foo": { x: 123, y: 456, level: 7 },
"https://bar": { x: 42, y: 42, level: 4 }
});
})
);
it(
"captures the selected feature",
action(function () {
terria.pickedFeatures = new PickedFeatures();
terria.pickedFeatures.pickPosition = new Cartesian3(
17832.12,
83234.52,
952313.73
);
const feature = new Entity({ name: "testFeature" }) as TerriaFeature;
terria.pickedFeatures.features.push(feature);
terria.selectedFeature = feature;
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
const current = initSources.pickedFeatures?.current;
expect(current?.name).toEqual("testFeature");
expect(current?.hash).toBeDefined();
})
);
it(
"captures all picked vector features",
action(function () {
terria.pickedFeatures = new PickedFeatures();
terria.pickedFeatures.pickPosition = new Cartesian3(
17832.12,
83234.52,
952313.73
);
terria.pickedFeatures.features.push(
new TerriaFeature({ name: "testFeature1" })
);
terria.pickedFeatures.features.push(
new TerriaFeature({ name: "testFeature2" })
);
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
const entities = initSources.pickedFeatures?.entities;
expect(entities?.[0].name).toEqual("testFeature1");
expect(entities?.[0].hash).toBeDefined();
expect(entities?.[1].name).toEqual("testFeature2");
expect(entities?.[1].hash).toBeDefined();
})
);
});
describe("map settings", function () {
it("serialises correctly", async function () {
const testBaseMap = new GeoJsonCatalogItem(
"test-basemap",
terria,
undefined
);
testBaseMap.setTrait(
CommonStrata.definition,
"geoJsonString",
`{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[145.5908203125,-40.17887331434695],[143.349609375,-42.08191667830631],[146.35986328124997,-44.040218713142124],[149.08447265625,-42.859859815062784],[148.55712890625,-41.36031866306708],[145.5908203125,-40.17887331434695]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[75.9375,51.069016659603896],[59.94140624999999,39.095962936305476],[79.453125,42.032974332441405],[80.15625,46.800059446787316],[75.673828125,51.45400691005982],[75.9375,51.069016659603896]]]}}]}`
);
terria.setBaseMaximumScreenSpaceError(1);
terria.setUseNativeResolution(true);
setViewerMode("2d", terria.mainViewer);
terria.timelineStack.setAlwaysShowTimeline(true);
await terria.mainViewer.setBaseMap(testBaseMap);
terria.terrainSplitDirection = SplitDirection.LEFT;
terria.depthTestAgainstTerrainEnabled = true;
const shareLink = buildShareLink(terria, viewState);
const params = decodeAndParseStartHash(shareLink);
const initSources = flattenInitSources(params.initSources);
expect(initSources.viewerMode).toBe("2d");
expect(initSources.settings).toEqual({
baseMaximumScreenSpaceError: 1,
useNativeResolution: true,
alwaysShowTimeline: true,
baseMapId: "test-basemap",
terrainSplitDirection: -1,
depthTestAgainstTerrainEnabled: true
});
});
});
});