mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
loadBundledJson's callers passed a literal JSON import as a Node fallback, which made the production build emit a JavaScript copy of every pack beside the JSON the browser fetches. The loader now reads file: URLs itself under Node (through process.getBuiltinModule, synchronously, as promptly as the cached import it replaces), and the callers pass only the URL. On a Node too old to provide getBuiltinModule it says that Node 24.14 or newer is needed. dist/ drops from 54 MB to 42 MB. A test keeps app code from importing a pack as a module. Co-Authored-By: Claude Opus 5.5 <[email protected]>
138 lines
4.5 KiB
JavaScript
138 lines
4.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { createInstallationSource } from './source.js';
|
|
import { createIngestion } from './ingestion.js';
|
|
import { decodeOpenFreeMapMilitaryTile } from '../../sources/openFreeMap.js';
|
|
import {
|
|
createMilitaryNamesLoader,
|
|
loadMilitaryNames,
|
|
} from '../../data/militaryNames.js';
|
|
import { loadBundledJson } from '../../data/bundledJson.js';
|
|
|
|
const box = { south: 30.3, west: -97.8, north: 30.33, east: -97.74 };
|
|
const wide = { south: 20, west: -130, north: 60, east: -60 };
|
|
const tile = decodeOpenFreeMapMilitaryTile(
|
|
readFileSync(
|
|
new URL(
|
|
'../../data/fixtures/ofm-camp-mabry-12-935-1685.pbf',
|
|
import.meta.url,
|
|
),
|
|
),
|
|
12,
|
|
935,
|
|
1685,
|
|
);
|
|
const flush = async () => {
|
|
for (let i = 0; i < 30; i++) await Promise.resolve();
|
|
};
|
|
function deferred() {
|
|
let resolve;
|
|
const promise = new Promise((r) => {
|
|
resolve = r;
|
|
});
|
|
return { promise, resolve };
|
|
}
|
|
function sourceWith(job) {
|
|
return createInstallationSource({
|
|
loadNames: () => job.promise,
|
|
fetchImpl: async () => Response.json({ unavailable: true }),
|
|
mapTiles: { fetchBounds: async () => ({ tiles: [tile] }), clear() {} },
|
|
});
|
|
}
|
|
|
|
test('close polygons publish immediately while a wide consumer can cancel its independent names wait', async () => {
|
|
const job = deferred(),
|
|
source = sourceWith(job),
|
|
abort = new AbortController();
|
|
const waiting = source.getMappedSites(wide, { signal: abort.signal });
|
|
const rejection = assert.rejects(waiting, { name: 'AbortError' });
|
|
const payload = await source.getMappedSites(box);
|
|
assert.ok(payload.records.length);
|
|
assert.ok(payload.records.every((r) => r.name === 'Military area'));
|
|
abort.abort();
|
|
await rejection;
|
|
job.resolve(await loadMilitaryNames());
|
|
const enriched = await payload.enrichment;
|
|
assert.ok(enriched.records.some((r) => r.name === 'Camp Mabry'));
|
|
});
|
|
|
|
for (const stale of [false, true])
|
|
test(`late names ${stale ? 'cannot publish to a superseded view' : 'enrich the current published polygons'}`, async () => {
|
|
const job = deferred(),
|
|
source = sourceWith(job),
|
|
publications = [];
|
|
let currentBox = box;
|
|
const state = {
|
|
enabled: true,
|
|
viewer: {},
|
|
records: [],
|
|
googleSearchRequested: false,
|
|
};
|
|
const ingestion = createIngestion({
|
|
state,
|
|
source,
|
|
services: {
|
|
render: { governorRequestRender() {} },
|
|
ground: { resolveGroundFloorCellsBounded: async () => {} },
|
|
},
|
|
parts: {
|
|
viewport: {
|
|
loadArea: () => ({ box: currentBox, coverage: {} }),
|
|
clearUnavailableRetry() {},
|
|
scheduleUnavailableRetry() {},
|
|
},
|
|
model: { installationWithinViewport: () => true },
|
|
rendering: {
|
|
renderRecords: () => publications.push(state.records),
|
|
warmInstallationFloors() {},
|
|
},
|
|
},
|
|
});
|
|
await ingestion.loadInstallations();
|
|
assert.equal(state.loading, false);
|
|
assert.ok(publications[0].length);
|
|
if (stale) {
|
|
currentBox = wide;
|
|
state.enabled = false;
|
|
state.abort.abort();
|
|
}
|
|
job.resolve(await loadMilitaryNames());
|
|
await flush();
|
|
assert.equal(publications.length, stale ? 1 : 2);
|
|
if (!stale) assert.ok(state.records.some((r) => r.name === 'Camp Mabry'));
|
|
state.abort.abort();
|
|
});
|
|
|
|
for (const stage of ['response', 'body'])
|
|
test(`shared names ${stage} deadline aborts and releases the retryable loader`, async (t) => {
|
|
t.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
|
|
let calls = 0,
|
|
signal;
|
|
t.mock.method(globalThis, 'fetch', async (_url, options) => {
|
|
calls++;
|
|
signal = options.signal;
|
|
if (calls > 1) return Response.json({ records: [], classes: [] });
|
|
if (stage === 'response') return new Promise(() => {});
|
|
return { ok: true, json: () => new Promise(() => {}) };
|
|
});
|
|
const load = createMilitaryNamesLoader({
|
|
timeoutMs: 50,
|
|
cooldownMs: 100,
|
|
loadPack: (signal) =>
|
|
loadBundledJson(new URL('https://example.test/names.json'), { signal }),
|
|
});
|
|
const first = load();
|
|
assert.equal(load(), first, 'shared acquisition');
|
|
const rejected = assert.rejects(first, { name: 'TimeoutError' });
|
|
await flush();
|
|
t.mock.timers.tick(51);
|
|
await rejected;
|
|
assert.equal(signal.aborted, true);
|
|
await assert.rejects(load(), { name: 'TimeoutError' });
|
|
assert.equal(calls, 1);
|
|
t.mock.timers.tick(101);
|
|
assert.deepEqual((await load()).records, []);
|
|
assert.equal(calls, 2);
|
|
});
|