← back to Quadrille Showroom
scripts/verify-sort-density-persist.mjs
51 lines
// verify-sort-density-persist.mjs — proves the standing sort+density rule's localStorage
// requirement: change sort + density, RELOAD, and assert both survive. Repeatable (not a
// one-time manual drive). Exit 1 on any failure. Resolves playwright from a skill install
// since the project itself doesn't depend on it.
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const CANDIDATES = [
'playwright',
'/Users/macstudio3/.claude/skills/hero-readability-auditor/node_modules/playwright/index.js',
'/Users/macstudio3/.claude/skills/app-demo-video/node_modules/playwright/index.js',
];
let chromium=null;
for (const c of CANDIDATES){ try { ({ chromium } = require(c)); if (chromium) break; } catch {} }
if (!chromium){ console.error('playwright not found'); process.exit(2); }
const URL = process.env.URL || 'http://127.0.0.1:7690';
const openControls = async (p) => {
await p.locator('#qh-burger').click({ timeout:6000 }); await p.waitForTimeout(400);
await p.locator('#qh-menu .qh-menu-item', { hasText:'Controls' }).first().click({ timeout:5000 });
await p.waitForTimeout(1200);
};
const b = await chromium.launch({ channel:'chrome' });
const ctx = await b.newContext({ httpCredentials:{ username:'admin', password:'DWSecure2024!' } });
const p = await ctx.newPage();
let fail=0;
await p.goto(URL,{ waitUntil:'load', timeout:20000 }); await p.waitForTimeout(3500);
await openControls(p);
// change sort → newest, density → 30
await p.selectOption('#sort-select','newest',{ timeout:6000 });
await p.locator('#density-range').evaluate(el=>{ el.value=30; el.dispatchEvent(new Event('change',{bubbles:true})); });
await p.waitForTimeout(800);
const ls1 = await p.evaluate(()=>({ sort:localStorage.getItem('qh_sort'), dens:localStorage.getItem('qh_density') }));
console.log('after change →', JSON.stringify(ls1));
if (ls1.sort!=='newest'){ console.log('❌ qh_sort not written'); fail++; }
if (String(ls1.dens)!=='30'){ console.log('❌ qh_density not written'); fail++; }
// RELOAD — the real test
await p.reload({ waitUntil:'load', timeout:20000 }); await p.waitForTimeout(3500);
await openControls(p);
const after = await p.evaluate(()=>({
ls:{ sort:localStorage.getItem('qh_sort'), dens:localStorage.getItem('qh_density') },
sel:document.getElementById('sort-select')?.value,
slider:document.getElementById('density-range')?.value,
}));
console.log('after reload →', JSON.stringify(after));
if (after.ls.sort!=='newest'){ console.log('❌ qh_sort lost on reload'); fail++; }
if (after.sel!=='newest'){ console.log('❌ sort <select> did not restore to newest'); fail++; }
if (String(after.slider)!=='30'){ console.log('❌ density slider did not restore to 30'); fail++; }
await b.close();
console.log(fail ? `\n❌ ${fail} persistence assertion(s) FAILED` : '\n✅ sort + density persist across reload (standing rule satisfied)');
process.exit(fail?1:0);