← back to Commercialrealestate

5x/crcp-assert.js

58 lines

// Strong crcp.html gate: tiles render with data (no NaN), 8 segment rows ATTACHED+correct, collapsed panel
// expands to visible, segment modal opens with a call-list, broker sort reorders, empty-data degrades clean.
const pw=require('/Users/macstudio3/.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('**/api/segments',r=>r.fulfill({status:200,contentType:'application/json',body:'{"segments":[]}'}));
    await pg.route('**/api/crcp/stats',r=>r.fulfill({status:200,contentType:'application/json',body:'{}'}));
  }
  await pg.goto('http://127.0.0.1:9911/crcp.html',{waitUntil:'networkidle'}); await pg.waitForTimeout(1500);
  const base=await pg.evaluate(()=>{
    const tiles=[...document.querySelectorAll('#tiles .tile .v')].map(v=>v.textContent);
    const srows=[...document.querySelectorAll('.srow')];
    const cellText=srows.map(r=>r.textContent).join(' ');
    return { tiles, segRowsAttached:srows.length, anyNaN:/NaN|undefined/.test(cellText+' '+tiles.join(' ')),
      segVisibleBefore: srows.length?srows[0].offsetParent!==null:false };
  });
  let expanded=false, modal={}, sortOk=null;
  if(!mockEmpty){
    // expand the Call Segments panel (the .panel that holds #segTbl)
    expanded=await pg.evaluate(()=>{ const t=document.querySelector('#segTbl'); const p=t&&t.closest('.panel');
      if(!p) return false; const h=p.querySelector('h3'); if(p.classList.contains('collapsed')) h.click();
      return !p.classList.contains('collapsed'); });
    await pg.waitForTimeout(250);
    const visAfter=await pg.evaluate(()=>{ const r=document.querySelector('.srow'); return r? r.offsetParent!==null:false; });
    // click first clickable segment row → modal with call list
    await pg.evaluate(()=>{ const r=[...document.querySelectorAll('.srow')].find(x=>x.style.cursor==='pointer'); if(r)r.click(); });
    await pg.waitForTimeout(900);
    modal=await pg.evaluate(()=>({ open:document.querySelector('#ov')?.classList.contains('on'),
      items:document.querySelectorAll('#mbody .brow3').length, hasHeading:!!document.querySelector('#mbody h2') }));
    await pg.evaluate(()=>{ const ov=document.querySelector('#ov'); if(ov)ov.classList.remove('on'); });
    modal.visAfterExpand=visAfter;
    // broker table sort: expand its panel, capture order, click a header, compare
    sortOk=await pg.evaluate(async()=>{ const t=document.querySelector('#brTbl'); const p=t&&t.closest('.panel');
      if(p&&p.classList.contains('collapsed')) p.querySelector('h3').click();
      await new Promise(r=>setTimeout(r,150));
      const before=[...document.querySelectorAll('#brTbl tbody tr')].map(r=>r.textContent).slice(0,5).join('|');
      const th=document.querySelector('#brTbl th.srt[data-col=name]'); if(!th) return null; th.click();
      await new Promise(r=>setTimeout(r,200));
      const after=[...document.querySelectorAll('#brTbl tbody tr')].map(r=>r.textContent).slice(0,5).join('|');
      return { changed: before!==after, rows: document.querySelectorAll('#brTbl tbody tr').length }; });
  }
  await b.close();
  return { mockEmpty, ...base, expanded, modal, sortOk, jsErrors:errors };
}
(async()=>{
  const normal=await run(false); const empty=await run(true);
  const passNormal = normal.segRowsAttached>=7 && !normal.anyNaN && normal.expanded && normal.modal.visAfterExpand
    && normal.modal.open && normal.modal.hasHeading && (normal.modal.items>0) && normal.sortOk && normal.sortOk.changed && normal.jsErrors.length===0;
  const passEmpty = !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);});