tests: snapshot and reset view state around runs

Tests assume a normal board — no super-view, no bucket filter, manual
sort, no hides. When the runner fired with the app left in super-view
or with filters on, selectors like `.card[data-id]` missed the
`.superview-item` DOM and multi-select / due-date assertions read the
wrong initial values.

Snapshot the relevant bits of window.state before the run, force a
clean baseline, then restore the user's view afterwards so opening the
runner doesn't silently wipe their context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-15 19:02:58 +02:00
1 parent 1d6499e5dd
commit 1a889ea435
1 file changed
+84
+84
View File
@@ -170,6 +170,71 @@ export function csrf() {
return getCsrf();
}
// Snapshot the view-affecting bits of window.state so we can force a
// neutral baseline (normal board, no filter, manual sort, no hides)
// for the test run and restore the user's view afterwards. Tests were
// flaky when the runner fired while the board was in super-view: DOM
// selectors like `.card[data-id]` don't match `.superview-item`, so
// multi-select and due-date tests read wrong initial values.
export function snapshotViewState() {
const s = window.state;
if (!s) return null;
return {
superView: s.superView,
activeBucket: s.activeBucket,
activeTags: [...(s.activeTags || [])],
activeGroup: s.activeGroup,
sortMode: s.sortMode,
hideTermine: s.hideTermine,
hideDone: s.hideDone,
hideTagged: s.hideTagged,
boardSplitOpen: s.boardSplitOpen,
};
}
export function resetViewState() {
const s = window.state;
if (!s) return;
s.superView = false;
s.activeBucket = 'all';
s.activeTags = [];
s.activeGroup = null;
s.sortMode = 'manual';
s.hideTermine = false;
s.hideDone = false;
s.hideTagged = false;
s.boardSplitOpen = false;
s.selectedIds?.clear?.();
// Sync super-view toggle visuals with the reset state so tests that
// inspect the button see the correct pose.
const btn = document.getElementById('superview-toggle');
const icon = btn?.querySelector('i');
if (icon) icon.className = 'ph ph-list text-sm';
btn?.classList.remove('active');
window._renderBoard?.();
}
export function restoreViewState(snap) {
const s = window.state;
if (!s || !snap) return;
Object.assign(s, {
superView: snap.superView,
activeBucket: snap.activeBucket,
activeTags: snap.activeTags,
activeGroup: snap.activeGroup,
sortMode: snap.sortMode,
hideTermine: snap.hideTermine,
hideDone: snap.hideDone,
hideTagged: snap.hideTagged,
boardSplitOpen: snap.boardSplitOpen,
});
const btn = document.getElementById('superview-toggle');
const icon = btn?.querySelector('i');
if (icon) icon.className = `ph ${snap.superView ? 'ph-squares-four' : 'ph-list'} text-sm`;
btn?.classList.toggle('active', !!snap.superView);
window._renderBoard?.();
}
export async function closeAll() {
document.getElementById('hterm')?.classList.add('hidden');
for (const id of ['settings-overlay', 'help', 'shortcuts', 'search', 'calendar', 'gallery', 'detail', 'modal', 'tasks', 'dialog']) {
@@ -452,6 +517,15 @@ async function run() {
stopBackgroundSync();
window._testRunning = true;
// 2b. Snapshot + reset view state. Tests assume a normal board with
// no filters / super-view off / manual sort — if the user left the
// app in super-view or with a bucket filter active, assertions on
// .card[data-id], card count, etc. read wrong initial values.
const viewSnap = snapshotViewState();
await closeAll();
resetViewState();
await sleep(50);
// 3. Hide panel so tests run against visible UI
panel.style.display = 'none';
await sleep(100);
@@ -476,6 +550,11 @@ async function run() {
await window._reloadAll?.();
await sleep(200);
} catch {}
// Re-reset the view in case a failing test left it in super-view,
// a bucket filter, or a sorted mode — otherwise the retry runs
// against the same wrong baseline that flaked it the first time.
resetViewState();
await sleep(50);
const retryResults = await runAll(failedKeys);
const retryMap = new Map();
for (const sr of retryResults) {
@@ -508,6 +587,11 @@ async function run() {
await sleep(200);
} catch {}
// 6b. Put the view back the way the user left it (super-view, sort,
// filters, …) so launching the test runner doesn't silently wipe
// their working context.
restoreViewState(viewSnap);
// 7. Resume background sync (delay to avoid immediate re-sync creating duplicates)
window._testRunning = false;
setTimeout(() => startBackgroundSync(), 60000);