mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
PanelChrome, its collapse-preference restore and the phone shell read a panel's disclosure state back from the gev-panel-chrome store (_shownPanel), falling back to the markup's classes before the panel is first presented, instead of reading the classes v-panel-state draws. The share link and the phone shell share one rule for a panel the person keeps closed (prefersCollapsed). The rails, the accordion and the hover disclosure still read the classes, which the directive draws in the same task as their layout.
152 lines
5.5 KiB
JavaScript
152 lines
5.5 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 { readPanelState } = await import('../ui/rail/panelState.js');
|
|
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,
|
|
shownPanel: readPanelState,
|
|
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;
|
|
}
|
|
});
|