← back to Commercialrealestate
5x/rentrolls-assert.js
35 lines
// Strong rent-rolls.html gate: rolls render with unit table + NOI, DSCR calculator computes a real number,
// changing an input recomputes DSCR, no NaN; empty-data shows the empty state with no error.
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:1200,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/rent-rolls',r=>r.fulfill({status:200,contentType:'application/json',body:'{"rentRolls":[],"count":0}'}));
await pg.goto('http://127.0.0.1:9911/rent-rolls.html',{waitUntil:'networkidle'}); await pg.waitForTimeout(1200);
const base=await pg.evaluate(()=>({
rolls:document.querySelectorAll('.roll').length, unitRows:document.querySelectorAll('.roll tbody tr').length,
empty:!!document.querySelector('.empty'),
dscr:document.querySelector('.dscrbig')?.textContent||null,
anyNaN:/NaN|\$NaN|undefined/.test(document.body.textContent) }));
let recalcOk=null;
if(!mockEmpty){
recalcOk=await pg.evaluate(async()=>{ const before=document.querySelector('.dscrbig')?.textContent;
const rate=document.querySelector('[data-f="rate"]'); if(!rate) return null;
rate.value=String((parseFloat(rate.value)||6)+2); rate.dispatchEvent(new Event('input'));
await new Promise(r=>setTimeout(r,250)); return { before, after:document.querySelector('.dscrbig')?.textContent, changed:before!==document.querySelector('.dscrbig')?.textContent }; });
}
await b.close();
return { mockEmpty, ...base, recalcOk, jsErrors:errors };
}
(async()=>{
const normal=await run(false); const empty=await run(true);
const passNormal = normal.rolls>0 && normal.unitRows>0 && !normal.anyNaN && /\d\.\d/.test(normal.dscr||'')
&& normal.recalcOk && normal.recalcOk.changed && normal.jsErrors.length===0;
const passEmpty = empty.empty && !empty.anyNaN && empty.jsErrors.length===0; // empty state shown, no NaN/error
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);});