opengeos--geolibre
7df9ebf22c
Sync labels / sync (push) Failing after 1m9s
Publish Container Image / Build and publish container image (push) Has been cancelled
Deploy Website / Deploy to GitHub Pages (push) Has been cancelled
Deploy Website / Build website and demo (push) Has been cancelled
Deploy viewer / Deploy viewer proxy to Cloudflare Workers (push) Has been cancelled
Deploy tiles / Deploy planetary tile proxy to Cloudflare Workers (push) Has been cancelled
Deploy collab / Deploy collaboration relay to Cloudflare Workers (push) Has been cancelled
CI / Dependency audit (push) Has been cancelled
CI / E2E smoke (Playwright) (push) Has been cancelled
CI / Validate CITATION.cff (push) Has been cancelled
CI / Build and test (push) Has been cancelled
166 行
5.2 KiB
TypeScript
166 行
5.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { describe, it } from "node:test";
|
|
import type { Map as MapLibreMap } from "maplibre-gl";
|
|
import {
|
|
acquireMercatorProjectionLock,
|
|
ensureMercatorProjection,
|
|
releaseMercatorProjectionLock,
|
|
} from "../packages/plugins/src/plugins/map-projection-utils";
|
|
|
|
type ProjectionType = "globe" | "mercator";
|
|
|
|
function fakeProjectionMap(initialProjection: ProjectionType) {
|
|
let projection = initialProjection;
|
|
const idleHandlers: Array<() => void> = [];
|
|
const setProjectionCalls: ProjectionType[] = [];
|
|
|
|
const map = {
|
|
getProjection: () => ({ type: projection }),
|
|
once: (event: string, handler: () => void) => {
|
|
if (event === "idle") idleHandlers.push(handler);
|
|
return map;
|
|
},
|
|
setProjection: (next: { type: ProjectionType }) => {
|
|
projection = next.type;
|
|
setProjectionCalls.push(next.type);
|
|
return map;
|
|
},
|
|
};
|
|
|
|
return {
|
|
emitIdle: () => {
|
|
for (const handler of idleHandlers.splice(0)) handler();
|
|
},
|
|
flipToGlobe: () => {
|
|
projection = "globe";
|
|
},
|
|
get projection() {
|
|
return projection;
|
|
},
|
|
idleHandlers,
|
|
map: map as unknown as MapLibreMap,
|
|
setProjectionCalls,
|
|
};
|
|
}
|
|
|
|
describe("ensureMercatorProjection", () => {
|
|
it("is a no-op for nullish map values", () => {
|
|
assert.doesNotThrow(() => ensureMercatorProjection(undefined));
|
|
assert.doesNotThrow(() => ensureMercatorProjection(null));
|
|
});
|
|
|
|
it("restores mercator on idle if the map is flipped back to globe", () => {
|
|
const fake = fakeProjectionMap("globe");
|
|
|
|
ensureMercatorProjection(fake.map);
|
|
assert.equal(fake.projection, "mercator");
|
|
assert.equal(fake.idleHandlers.length, 1);
|
|
|
|
fake.flipToGlobe();
|
|
fake.emitIdle();
|
|
|
|
assert.equal(fake.projection, "mercator");
|
|
assert.deepEqual(fake.setProjectionCalls, ["mercator", "mercator"]);
|
|
});
|
|
|
|
it("registers only one pending idle guard per map", () => {
|
|
const fake = fakeProjectionMap("globe");
|
|
|
|
ensureMercatorProjection(fake.map);
|
|
ensureMercatorProjection(fake.map);
|
|
|
|
assert.equal(fake.idleHandlers.length, 1);
|
|
});
|
|
|
|
it("does not call setProjection when already mercator", () => {
|
|
const fake = fakeProjectionMap("mercator");
|
|
|
|
ensureMercatorProjection(fake.map);
|
|
|
|
assert.deepEqual(fake.setProjectionCalls, []);
|
|
assert.equal(fake.idleHandlers.length, 1);
|
|
|
|
fake.emitIdle();
|
|
|
|
assert.deepEqual(fake.setProjectionCalls, []);
|
|
});
|
|
});
|
|
|
|
// A minimal app surface for the shared mercator lock. `getMap` returns null so
|
|
// the internal ensureMercatorProjection() call is a no-op and the test stays
|
|
// focused on the capture/restore bookkeeping. Each test fully releases what it
|
|
// acquires so the module-level lock state resets between cases.
|
|
function fakeProjectionApp(initial: ProjectionType) {
|
|
let projection: ProjectionType = initial;
|
|
const setProjectionCalls: ProjectionType[] = [];
|
|
return {
|
|
app: {
|
|
getMapProjection: () => projection,
|
|
setMapProjection: (next: ProjectionType) => {
|
|
projection = next;
|
|
setProjectionCalls.push(next);
|
|
},
|
|
getMap: () => null,
|
|
},
|
|
get projection() {
|
|
return projection;
|
|
},
|
|
setProjectionCalls,
|
|
};
|
|
}
|
|
|
|
describe("mercator projection lock", () => {
|
|
it("restores the captured projection only after the last holder releases", () => {
|
|
const fake = fakeProjectionApp("globe");
|
|
|
|
// Google acquires first: captures "globe", forces mercator.
|
|
acquireMercatorProjectionLock("google", fake.app);
|
|
assert.equal(fake.projection, "mercator");
|
|
|
|
// I3S acquires while already mercator: must not capture a new "previous".
|
|
acquireMercatorProjectionLock("arcgis-i3s", fake.app);
|
|
assert.equal(fake.projection, "mercator");
|
|
|
|
// Removing Google must not restore globe while I3S still needs mercator.
|
|
releaseMercatorProjectionLock("google", fake.app);
|
|
assert.equal(fake.projection, "mercator");
|
|
|
|
// Removing the last holder restores the originally-captured globe.
|
|
releaseMercatorProjectionLock("arcgis-i3s", fake.app);
|
|
assert.equal(fake.projection, "globe");
|
|
});
|
|
|
|
it("treats repeated acquires for one overlay type as a single hold", () => {
|
|
const fake = fakeProjectionApp("globe");
|
|
|
|
acquireMercatorProjectionLock("google", fake.app);
|
|
acquireMercatorProjectionLock("google", fake.app);
|
|
acquireMercatorProjectionLock("google", fake.app);
|
|
assert.equal(fake.projection, "mercator");
|
|
|
|
// A single release (mirroring the once-per-type teardown) restores globe.
|
|
releaseMercatorProjectionLock("google", fake.app);
|
|
assert.equal(fake.projection, "globe");
|
|
});
|
|
|
|
it("never restores a projection that started as (forced) mercator", () => {
|
|
const fake = fakeProjectionApp("mercator");
|
|
|
|
acquireMercatorProjectionLock("google", fake.app);
|
|
releaseMercatorProjectionLock("google", fake.app);
|
|
|
|
// "mercator" is never captured as worth restoring, so nothing is set back.
|
|
assert.equal(fake.projection, "mercator");
|
|
assert.deepEqual(fake.setProjectionCalls, ["mercator"]);
|
|
});
|
|
|
|
it("ignores a release for a key that never acquired the lock", () => {
|
|
const fake = fakeProjectionApp("globe");
|
|
|
|
releaseMercatorProjectionLock("google", fake.app);
|
|
|
|
assert.deepEqual(fake.setProjectionCalls, []);
|
|
assert.equal(fake.projection, "globe");
|
|
});
|
|
});
|