← 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);});