Add region-keys.test.ts: 1,796 unique <slug>-<4char> keys, geo-id join (v0.19 P1 of #16)

This commit is contained in:
2026-10-14 08:32:36 +00:00
parent 2b84c34f41
commit 2cfa2f78f9
+61
View File
@@ -0,0 +1,61 @@
/**
* scripts/region-keys.test.ts — validation for the committed `public/region-keys.json`.
*
* The manifest maps each sub-region's **stable feature id** (from
* `public/regions.geo.json`) to a deterministic, human-readable, globally
* unique region key of the form `<name-slug>-<4char>` (built by
* `scripts/build-region-keys.mjs`). Region-level ownership (v0.19) keys both
* `Nation.territory` and the `RegionMap` on these keys, so the manifest is a
* load-bearing data artifact — this test pins its contract.
*
* Deliberately dependency-free: it reads both JSON files with plain
* `fs`/`JSON.parse` and never imports `@turf`/geojson types (importing one
* pulls `@types/geojson` into the tsc program and breaks `WorldMap.tsx`; see
* the v0.17 changelog note). Mirrors the style of `scripts/regions.test.ts`.
*/
import { readFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
const here = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(here, '..');
function readJson(rel: string): Record<string, unknown> {
return JSON.parse(readFileSync(path.join(root, rel), 'utf8'));
}
describe('region-keys.json', () => {
const manifest = readJson('public/region-keys.json') as Record<string, string>;
const geo = readJson('public/regions.geo.json') as {
features?: Array<{ id?: string | number }>;
};
const keys = Object.values(manifest);
const featureIds = (geo.features ?? []).map((f) => String(f.id));
it('has exactly 1,796 entries (one per region)', () => {
expect(Object.keys(manifest)).toHaveLength(1796);
});
it('has 1,796 unique keys (no collisions)', () => {
expect(new Set(keys).size).toBe(keys.length);
expect(new Set(keys).size).toBe(1796);
});
it('keys each end in -[a-z]{4} and contain at least one hyphen', () => {
const ending = /-[a-z]{4}$/;
for (const k of keys) {
expect(k, `key does not end in -[a-z]{4}: ${k}`).toMatch(ending);
expect(k, `key has no hyphen: ${k}`).toContain('-');
}
});
it('is a stable join: its keys are exactly the regions.geo.json feature ids', () => {
// The manifest is looked up by feature id, so its key set must line up
// 1:1 with the geo file (catches drift if the geo is regenerated without
// rebuilding the keys).
expect(featureIds).toHaveLength(1796);
const manifestIds = Object.keys(manifest);
expect(new Set(manifestIds)).toEqual(new Set(featureIds));
});
});