Files
gods-eye-view/src/tooling/panelStorageDocs.test.mjs
T
Sameh Khamis cd231faae9 feat(panels): build the rail panels on one UiPanel
The Data, Authoring, Weather, Recent Imagery, Context, CCTV, Street Level
and Radio panels each wrote the same frame by hand. They are now one kit
component, UiPanel, with a title, badge/actions/default slots and
v-model:collapsed, drawing Core's panel markup and classes beside the kit's;
props cover the differences (sideways, glow, scroll, railScroller, tag,
toggleWords). RailPanel binds it to the panel chrome store: v-panel-state
writes its state classes at once, and its button's clicks reach PanelChrome.
UiPanelToggle is the collapse button UiPanel and PanelCollapseButton share.

UiPanel's collapsed drives the button and ui-panel--collapsed
only; the owner hides the body by writing the root's collapsed class, since
the rails measure a panel in the task that opens it. PanelCollapseButton
takes startCollapsed instead of initial and initialTitle, so a button shows
its state's glyph and words before startup presents the panel. Titles render
through t() instead of data-i18n, and the unused "Expand panel" string is
pruned. v-panel-state redraws the presented state after a re-render, in
case a root's class binding ever changes.
2026-11-01 08:33:18 -08:00

150 lines
5.4 KiB
JavaScript

import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import test from 'node:test';
import { fileURLToPath } from 'node:url';
const root = fileURLToPath(new URL('../..', import.meta.url));
// Documentation consistency only: that every storage key a document spells out
// is the key the code writes. Whether deleting one has the effect the document
// claims is not checked here.
const DOCUMENTED_KEYS = [
['docs/KNOWN-ISSUES.md', 'godsEyeView.{layout}.panelCollapsed.cctv-panel'],
['docs/KNOWN-ISSUES.md', 'godsEyeView.{layout}.panelCollapsed.<panel-id>'],
['docs/KNOWN-ISSUES.md', 'godsEyeView.{position}.panelPos.<panel-id>'],
['scripts/dev-fresh.sh', 'godsEyeView.{layout}.panelCollapsed.cctv-panel'],
['docs/CURRENT-STATE.md', 'godsEyeView.{position}.panelPos.<panel-id>'],
['docs/CURRENT-STATE.md', 'godsEyeView.{position}.panelPos.<id>'],
['docs/CURRENT-STATE.md', 'godsEyeView.{layout}.panelCollapsed.<panel-id>'],
];
test('documented panel storage keys are the keys the code writes', async () => {
const source = await readFile(
path.join(root, 'src/ui/panelPositionControls.js'),
'utf8',
);
const version = (name) => {
const [, found] =
source.match(new RegExp(`const ${name} = '([^']+)';`)) || [];
assert.ok(found, `panelPositionControls.js must declare ${name}`);
return found;
};
const position = version('PANEL_POSITION_STORAGE_VERSION');
const layout = version('PANEL_LAYOUT_STORAGE_VERSION');
const seen = new Map();
for (const [file, shape] of DOCUMENTED_KEYS) {
if (!seen.has(file))
seen.set(file, await readFile(path.join(root, file), 'utf8'));
const expected = shape
.replace('{position}', position)
.replace('{layout}', layout);
assert.ok(
seen.get(file).includes(expected),
`${file} must use ${expected}`,
);
}
// A document that still names a superseded version sends the reader to a key
// nothing writes.
for (const [file, content] of seen) {
const stalePositions = [
...content.matchAll(/godsEyeView\.(v\d+)\.panelPos/g),
]
.map(([, found]) => found)
.filter((found) => found !== position);
assert.deepEqual(
stalePositions,
[],
`${file} names superseded position keys`,
);
const staleCollapsed = [
...content.matchAll(/godsEyeView\.(v\d+)\.panelCollapsed/g),
]
.map(([, found]) => found)
.filter((found) => found !== layout);
assert.deepEqual(
staleCollapsed,
[],
`${file} names superseded collapsed-state keys`,
);
}
});
test('the documented outcomes hold: default, stored open, stored shut, and a shared view', async () => {
// The instructions promise two different outcomes; both are exercised here
// against the code that decides them.
const { PanelPositionControls } =
await import('../ui/panelPositionControls.js');
const { presentPanelLocally } = await import('../testSupport/panelState.mjs');
const html = await readFile(
path.join(root, 'src/ui/views/panels/CctvPanel.vue'),
'utf8',
);
assert.match(
html,
/<RailPanel id="cctv-panel"[^>]*\bstart-collapsed\b/,
'the CCTV panel starts collapsed in the markup',
);
const saved = {
document: globalThis.document,
localStorage: globalThis.localStorage,
};
const classes = new Set(['panel-collapsible', 'collapsed']);
const panel = {
classList: {
contains: (name) => classes.has(name),
toggle: (name, active) =>
active ? classes.add(name) : classes.delete(name),
add: (name) => classes.add(name),
remove: (name) => classes.delete(name),
},
};
const store = new Map();
globalThis.document = { getElementById: () => panel };
globalThis.localStorage = {
getItem: (key) => (store.has(key) ? store.get(key) : null),
setItem: (key, value) => store.set(key, String(value)),
removeItem: (key) => store.delete(key),
};
try {
const controls = new PanelPositionControls({
presentPanel: presentPanelLocally,
layoutRightPanels: () => {},
syncCctvPanelViewport: () => {},
showToast: () => {},
});
// Nothing stored: the markup default wins, and the panel is collapsed. So
// deleting the key is a reset, not a way to open the panel.
controls._restorePanelCollapsedState('cctv-panel');
assert.equal(classes.has('collapsed'), true);
// The value the documents tell a reader to set.
store.set('godsEyeView.v6.panelCollapsed.cctv-panel', '0');
controls._restorePanelCollapsedState('cctv-panel');
assert.equal(classes.has('collapsed'), false);
// ...and the opposite value keeps it shut, so '0' is doing the work.
store.set('godsEyeView.v6.panelCollapsed.cctv-panel', '1');
controls._restorePanelCollapsedState('cctv-panel');
assert.equal(classes.has('collapsed'), true);
// A view opened from a share link is laid out from the link: the shell
// restores with allowStored false, and the stored value is not consulted.
// This is why the console workaround is documented for ordinary loads only.
store.set('godsEyeView.v6.panelCollapsed.cctv-panel', '0');
controls._restorePanelCollapsedState('cctv-panel', { allowStored: false });
assert.equal(
classes.has('collapsed'),
true,
'a shared view must ignore the stored open state',
);
} finally {
globalThis.document = saved.document;
globalThis.localStorage = saved.localStorage;
}
});