map: click a region to switch the dossier to its owner; fix "no owner" (v0.7.0)
CI / build + unit + e2e (pull_request) Successful in 1m58s
CI / build + unit + e2e (pull_request) Successful in 1m58s
This commit is contained in:
+65
-1
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildRegionMap } from './map';
|
||||
import { nationColor } from '../shared/protocol';
|
||||
import { nationColor, regionOwner, type RegionMap } from '../shared/protocol';
|
||||
import type { GameState } from '../shared/types';
|
||||
|
||||
const state: GameState = {
|
||||
@@ -33,6 +33,9 @@ const state: GameState = {
|
||||
version: 1,
|
||||
};
|
||||
|
||||
// The RegionMap built from the fixture: the authoritative ISO_A3 → owner source.
|
||||
const regions: RegionMap = buildRegionMap(state);
|
||||
|
||||
describe('buildRegionMap', () => {
|
||||
it('maps each ISO_A3 region to its owner + that nation\'s stable color', () => {
|
||||
const m = buildRegionMap(state);
|
||||
@@ -44,6 +47,67 @@ describe('buildRegionMap', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('regionOwner', () => {
|
||||
it('resolves an owned region\'s ISO_A3 to its owner record', () => {
|
||||
expect(regionOwner(regions, 'GBR')).toEqual({
|
||||
color: nationColor('uk'),
|
||||
owner: 'UK',
|
||||
ownerId: 'uk',
|
||||
});
|
||||
expect(regionOwner(regions, 'DEU')).toEqual({
|
||||
color: nationColor('de'),
|
||||
owner: 'DE',
|
||||
ownerId: 'de',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns undefined for an unowned region (no RegionMap entry)', () => {
|
||||
expect(regionOwner(regions, 'FRA')).toBeUndefined();
|
||||
expect(regionOwner(regions, 'USA')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined for an empty or missing code', () => {
|
||||
expect(regionOwner(regions, '')).toBeUndefined();
|
||||
expect(regionOwner(regions, null)).toBeUndefined();
|
||||
expect(regionOwner(regions, undefined)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* #6 regression guard. The click/hover handlers resolve the owning nation from a
|
||||
* map feature. MapLibre repacks a GeoJSON source's top-level `id` (the ISO_A3
|
||||
* string) into a *numeric index* when it stores the source, so a feature the map
|
||||
* hands back at interaction time has a number for `id` and the ISO_A3 only lives
|
||||
* in `properties.regionId`. This test pins the exact data shape and proves the
|
||||
* fix: resolution via `properties.regionId` works, while the pre-fix path that
|
||||
* read `feature.id` does not.
|
||||
*/
|
||||
describe('#6 — owner must be resolved from properties.regionId, not the repacked feature.id', () => {
|
||||
// The shape MapLibre returns for a source feature after setData(): `id` is a
|
||||
// number (here 0, as observed in the live map), and the ISO_A3 is preserved
|
||||
// only in properties (the client stamps it as `regionId`).
|
||||
const repackedFeature = {
|
||||
id: 0,
|
||||
properties: { name: 'DE', regionId: 'DEU' },
|
||||
};
|
||||
|
||||
it('resolves the owner from properties.regionId (the fix)', () => {
|
||||
const code = typeof repackedFeature.properties.regionId === 'string' ? repackedFeature.properties.regionId : '';
|
||||
expect(regionOwner(regions, code)).toEqual({
|
||||
color: nationColor('de'),
|
||||
owner: 'DE',
|
||||
ownerId: 'de',
|
||||
});
|
||||
});
|
||||
|
||||
it('the old path (feature.id as a string key) does NOT resolve — the bug', () => {
|
||||
// String(0) === '0' is not a valid ISO_A3 key, so the pre-fix lookup failed
|
||||
// and the click popup reported "No owner" even for owned regions.
|
||||
expect(regions[String(repackedFeature.id)]).toBeUndefined();
|
||||
expect(regionOwner(regions, String(repackedFeature.id))).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('nationColor', () => {
|
||||
it('is deterministic per id and distinct across different ids', () => {
|
||||
expect(nationColor('uk')).toBe(nationColor('uk'));
|
||||
|
||||
Reference in New Issue
Block a user