← back to NationalPaperHangers
tests: e2e for /find sort + density controls — 7/7, locks in CLAUDE.md standing rule
0420926f5f3e0abb29c9ca4c7096d40072d817f9 · 2026-05-06 18:11:55 -0700 · Steve
Files touched
A tests/e2e-find-sort-density.js
Diff
commit 0420926f5f3e0abb29c9ca4c7096d40072d817f9
Author: Steve <steve@designerwallcoverings.com>
Date: Wed May 6 18:11:55 2026 -0700
tests: e2e for /find sort + density controls — 7/7, locks in CLAUDE.md standing rule
---
tests/e2e-find-sort-density.js | 74 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/tests/e2e-find-sort-density.js b/tests/e2e-find-sort-density.js
new file mode 100644
index 0000000..4851aa1
--- /dev/null
+++ b/tests/e2e-find-sort-density.js
@@ -0,0 +1,74 @@
+// e2e: /find page must have sort + density controls per CLAUDE.md standing rule.
+// Verifies presence, sort actually re-orders, density actually changes --card-min,
+// and both persist to localStorage.
+
+const { chromium } = require('playwright-core');
+const BASE = process.env.BASE || 'http://localhost:9765';
+
+function findChromium() {
+ const paths = [
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
+ '/Applications/Chromium.app/Contents/MacOS/Chromium',
+ process.env.CHROME_PATH,
+ ].filter(Boolean);
+ for (const p of paths) { try { require('fs').accessSync(p); return p; } catch {} }
+ return null;
+}
+
+(async () => {
+ const exe = findChromium();
+ if (!exe) { console.error('FAIL: no Chromium'); process.exit(2); }
+ const browser = await chromium.launch({ executablePath: exe, headless: true });
+ const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
+ const page = await ctx.newPage();
+ let pass = 0, fail = 0;
+ const assert = (c, m) => { if (c) { console.log(` ✓ ${m}`); pass++; } else { console.log(` ✗ ${m}`); fail++; } };
+ try {
+ console.log('[setup] GET /find');
+ await page.goto(`${BASE}/find`, { waitUntil: 'domcontentloaded' });
+
+ assert(!!(await page.$('#sort-select')), 'sort select present');
+ assert(!!(await page.$('#density-slider')), 'density slider present');
+
+ const cardCount = await page.$$eval('.installer-card', els => els.length);
+ if (cardCount < 2) {
+ console.log(' ⊘ skipped sort assertions — fewer than 2 cards in grid');
+ } else {
+ // Capture default first-card name
+ const firstName0 = await page.$eval('.installer-card:first-child', el => el.dataset.name);
+ // Switch to A→Z and verify reorder
+ await page.selectOption('#sort-select', 'az');
+ await page.waitForTimeout(150);
+ const firstNameAZ = await page.$eval('.installer-card:first-child', el => el.dataset.name);
+ const allNames = await page.$$eval('.installer-card', els => els.map(e => e.dataset.name || ''));
+ const sortedAsc = [...allNames].sort();
+ assert(JSON.stringify(allNames) === JSON.stringify(sortedAsc), 'A→Z sort orders cards alphabetically');
+ // Switch to Z→A
+ await page.selectOption('#sort-select', 'za');
+ await page.waitForTimeout(150);
+ const allNamesZA = await page.$$eval('.installer-card', els => els.map(e => e.dataset.name || ''));
+ const sortedDesc = [...allNamesZA].sort().reverse();
+ assert(JSON.stringify(allNamesZA) === JSON.stringify(sortedDesc), 'Z→A sort orders cards reverse-alphabetically');
+ }
+
+ // Density slider — set min to 400, verify CSS var updates
+ await page.fill('#density-slider', '400');
+ await page.dispatchEvent('#density-slider', 'input');
+ await page.waitForTimeout(100);
+ const cardMin = await page.$eval('#installerGrid', el => el.style.getPropertyValue('--card-min'));
+ assert(cardMin === '400px', `--card-min CSS var updated (got "${cardMin}")`);
+
+ // localStorage persistence
+ const lsSort = await page.evaluate(() => localStorage.getItem('nph-find-sort'));
+ const lsDens = await page.evaluate(() => localStorage.getItem('nph-find-density'));
+ assert(lsSort && ['az','za','default','tier','verified_first','newest_claimed','creds'].includes(lsSort), `sort persisted to localStorage (got "${lsSort}")`);
+ assert(lsDens === '400', `density persisted to localStorage (got "${lsDens}")`);
+
+ } catch (err) {
+ console.error('FATAL:', err.message); fail++;
+ } finally {
+ await browser.close();
+ console.log(`[result] ${pass} pass · ${fail} fail`);
+ process.exit(fail ? 1 : 0);
+ }
+})();
← 72e3f64 find: add sort + density controls per CLAUDE.md standing rul
·
back to NationalPaperHangers
·
tests: e2e claim flow — landing form → email-domain check → eb62adf →