[object Object]

← 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

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 →