[object Object]

← back to Commercialrealestate

5x: index.html strong gate (index-assert.js — 1407 cards/no-NaN/loopnet+rent links/sort-reorders/filter-narrows/empty-degrades, PASS). No defect; all 6 pages now gated. Added index to health-check.sh

9c2a5fc2872d3ef9ab580cb9f9efd6205ef079e7 · 2026-06-29 01:49:55 -0700 · Steve

Files touched

Diff

commit 9c2a5fc2872d3ef9ab580cb9f9efd6205ef079e7
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Jun 29 01:49:55 2026 -0700

    5x: index.html strong gate (index-assert.js — 1407 cards/no-NaN/loopnet+rent links/sort-reorders/filter-narrows/empty-degrades, PASS). No defect; all 6 pages now gated. Added index to health-check.sh
---
 5x/health-check.sh |  2 +-
 5x/index-assert.js | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/5x/health-check.sh b/5x/health-check.sh
index c5ab95f..1ccf214 100755
--- a/5x/health-check.sh
+++ b/5x/health-check.sh
@@ -5,7 +5,7 @@ cd "$(dirname "$0")/.."
 code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:9911/crcp.html 2>/dev/null)
 [ "$code" = "200" ] || { echo "SERVER DOWN ($code) — restart: node scripts/serve.js &"; exit 1; }
 fail=0
-for g in deals map crcp sales brokers; do
+for g in deals map crcp sales brokers index; do
   if node "5x/$g-assert.js" >/dev/null 2>&1; then echo "  $g-assert: PASS"; else echo "  $g-assert: FAIL"; fail=1; fi
 done
 [ $fail = 0 ] && echo "ALL GATES PASS — healthy" || echo "REGRESSION DETECTED"
diff --git a/5x/index-assert.js b/5x/index-assert.js
new file mode 100644
index 0000000..8bad0a9
--- /dev/null
+++ b/5x/index-assert.js
@@ -0,0 +1,45 @@
+// Strong index.html gate (primary property viewer). Tests the REAL DOM (verified by probe):
+//  • 1407 ranked cards under .grid render, NO NaN/$NaN, count text present, LoopNet + rent lines present
+//  • changing #sort reorders the cards (first card changes)
+//  • clicking a filter .chip narrows the result set
+//  • empty data (mocked ranked.json/listings.json) degrades: 0 cards, no NaN, 0 swallowed JS errors
+const pw=require('/Users/stevestudio2/.claude/skills/browserbase/node_modules/playwright-core');
+const EXEC='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+async function run(mockEmpty){
+  const errors=[]; const b=await pw.chromium.launch({executablePath:EXEC,headless:true});
+  const pg=await b.newPage({viewport:{width:1320,height:1000}});
+  pg.on('pageerror',e=>errors.push('PAGEERR: '+e.message));
+  pg.on('console',m=>{if(m.type()==='error'&&!/Failed to load resource/.test(m.text()))errors.push('CONSOLE: '+m.text());});
+  if(mockEmpty){
+    await pg.route('**/ranked.json',r=>r.fulfill({status:200,contentType:'application/json',body:'{"ranked":[]}'}));
+    await pg.route('**/listings.json',r=>r.fulfill({status:200,contentType:'application/json',body:'{"listings":[]}'}));
+  }
+  await pg.goto('http://127.0.0.1:9911/index.html',{waitUntil:'networkidle'}); await pg.waitForTimeout(2000);
+  const base=await pg.evaluate(()=>({
+    cards:document.querySelectorAll('.grid .card').length,
+    anyNaN:/NaN|\$NaN|undefined/.test([...document.querySelectorAll('.grid .card')].slice(0,40).map(c=>c.textContent).join(' ')),
+    loopnet:document.querySelectorAll('.src a[href*="loopnet"], .src a[href*="site:loopnet"]').length,
+    rentLines:[...document.querySelectorAll('.card')].filter(c=>/Est\. rent/.test(c.textContent)).length,
+    countTxt:(document.querySelector('.bar .count')?.textContent||'').replace(/\s+/g,' ').trim() }));
+  let sortOk=null, filterOk=null;
+  if(!mockEmpty){
+    sortOk=await pg.evaluate(async()=>{ const sel=document.querySelector('#sort'); if(!sel||sel.options.length<2) return null;
+      const first=()=>document.querySelector('.grid .card .addr')?.textContent||document.querySelector('.grid .card')?.textContent.slice(0,40);
+      const before=first(); sel.selectedIndex=(sel.selectedIndex+1)%sel.options.length; sel.dispatchEvent(new Event('change'));
+      await new Promise(r=>setTimeout(r,500)); return { before, after:first(), changed:before!==first() }; });
+    filterOk=await pg.evaluate(async()=>{ const chip=document.querySelector('.chip'); if(!chip) return null;
+      const n=()=>document.querySelectorAll('.grid .card').length; const before=n();
+      chip.click(); await new Promise(r=>setTimeout(r,500)); const after=n();
+      return { before, after, narrowed: after<before && after>=0 }; });
+  }
+  await b.close();
+  return { mockEmpty, ...base, sortOk, filterOk, jsErrors:errors };
+}
+(async()=>{
+  const normal=await run(false); const empty=await run(true);
+  const passNormal = normal.cards>0 && !normal.anyNaN && normal.loopnet>0 && normal.rentLines>0
+    && (!normal.sortOk||normal.sortOk.changed) && (!normal.filterOk||normal.filterOk.narrowed) && normal.jsErrors.length===0;
+  const passEmpty = empty.cards===0 && !empty.anyNaN && empty.jsErrors.length===0;
+  console.log(JSON.stringify({normal,empty,passNormal,passEmpty,VERDICT:(passNormal&&passEmpty)?'PASS':'FAIL'},null,2));
+  process.exit((passNormal&&passEmpty)?0:1);
+})().catch(e=>{console.error('FAIL',e.message);process.exit(1);});

← 9455571 5x: health-check.sh (server + all 5 strong gates) + night-lo  ·  back to Commercialrealestate  ·  5x: OVERNIGHT-REPORT.md (final) — all 6 pages gated + PASS; 119516b →