refactor: export infrastructure layers with explicit application callbacks

This commit is contained in:
Sameh Khamis committed 2026-09-11 13:21:22 -07:00
1 parent e465197cee
commit 142bf583f8
10 files changed
+1338 -1115

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import * as Cesium from 'cesium';
import { createInfrastructureLayers } from 'gods-eye-view/infrastructure';
import { createLocalGeoJsonLayer } from 'gods-eye-view/infrastructure/geojson';
function services() {
const records = new Map();
let selection;
return {
records,
overlayHost: { setEntries() {}, setVisible() {}, clearSource() {} },
registerEntityContext(entity, metadata) { records.set(metadata.id, { entity, ...metadata }); },
selectEntityContext(entity) { selection = entity; },
clearSelectedEntityContextForLayer() { selection = undefined; },
removeEntityContextsForLayer(id) {
for (const [key, record] of records) if (record.layerId === id) records.delete(key);
},
governorRequestRender() {},
selection: () => selection,
};
}
test('package exports import without an application, DOM, fetch, or timers', () => {
const result = spawnSync(process.execPath, ['--input-type=module', '-e', `
globalThis.fetch = () => { throw new Error('unexpected fetch'); };
globalThis.setTimeout = () => { throw new Error('unexpected timer'); };
for (const key of ['window', 'document']) {
delete globalThis[key];
}
await import('gods-eye-view/infrastructure');
await import('gods-eye-view/infrastructure/geojson');
await import('gods-eye-view/infrastructure/lod');
`], { cwd: new URL('../..', import.meta.url), encoding: 'utf8' });
assert.equal(result.status, 0, result.stderr);
});
test('infrastructure factory preserves identity and creates independent state without loading', t => {
t.mock.method(globalThis, 'fetch', () => { throw new Error('factory must not fetch'); });
const first = createInfrastructureLayers(services());
const second = createInfrastructureLayers(services());
assert.deepEqual(first.map(({ id, name, source }) => ({ id, name, source })), [
{ id: 'local-datacenters', name: 'Datacenters', source: 'Local' },
{ id: 'local-dams', name: 'Dams', source: 'USACE' },
]);
first.forEach((layer, index) => {
assert.notEqual(layer, second[index]);
layer.destroy();
assert.deepEqual(second[index].getStats(), { count: 0, lastUpdate: null, error: null });
second[index].destroy();
});
});
test('dataset URLs still name the complete bundled sources', () => {
for (const [file, count] of [['datacenters', 4351], ['dams', 704]]) {
const lines = readFileSync(new URL(`./local_data/${file}/${file}.geojsonl`, import.meta.url), 'utf8')
.split('\n').filter(line => line.trim());
assert.equal(lines.length, count);
}
});
test('two viewers use their supplied contexts and dispose independently', async t => {
t.mock.method(globalThis, 'fetch', async () => ({ ok: true, text: async () => JSON.stringify({
type: 'Feature', id: 'same-id', properties: { name: 'Dam' },
geometry: { type: 'Polygon', coordinates: [[[0, 0], [0.01, 0], [0, 0.01], [0, 0]]] },
}) }));
const hosts = [services(), services()];
const instances = hosts.map(host => {
const sources = new Cesium.DataSourceCollection();
let click;
const layer = createLocalGeoJsonLayer({
id: 'local-dams', name: 'Dams', color: '#0088ff', url: '/dams.geojsonl',
screenSpaceEventHandlerFactory: () => ({ setInputAction(fn) { click = fn; }, destroy() {} }),
}, host);
const viewer = {
dataSources: sources,
scene: {
canvas: {}, preRender: new Cesium.Event(), requestRender() {},
screenSpaceCameraController: { enableInputs: true },
pick: () => ({ id: sources.get(0).entities.values[0] }),
},
camera: { moveEnd: new Cesium.Event(), flyTo() {} },
};
return { layer, viewer, click: () => click({ position: {} }) };
});
t.after(() => instances.forEach(({ layer, viewer }) => layer.destroy(viewer)));
await Promise.all(instances.map(({ layer, viewer }) => layer.enable(viewer)));
assert.equal(hosts[0].records.size, 1);
assert.equal(hosts[1].records.size, 1);
instances[0].click();
assert.ok(hosts[0].selection());
assert.equal(hosts[1].selection(), undefined);
instances[0].layer.destroy(instances[0].viewer);
assert.equal(hosts[0].records.size, 0);
assert.equal(hosts[1].records.size, 1);
assert.equal(instances[1].viewer.dataSources.length, 1);
});