← back to Commercialrealestate
5x/graphics-drill-assert.js
82 lines
// TK-10091 — prove every datum on graphics.html drills to a filtered/detail view.
// Verifies: 6 charts each have an onClick handler; stat-bar + expiring-table cells are real
// <a> links with correct hrefs; and the drill targets actually resolve (condos ?status/?city,
// crcp ?broker modal). Basic-auth aware (fetch() 401s on URL-only creds, so use httpCredentials).
const pw = require('/Users/macstudio3/.claude/skills/browserbase/node_modules/playwright-core');
const EXEC = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
const BASE = process.env.BASE || 'http://127.0.0.1:9943';
const CRED = { username: 'admin', password: 'DW2024!' };
const fail = [], pass = [];
const ok = (c, m) => (c ? pass : fail).push(m);
(async () => {
const b = await pw.chromium.launch({ executablePath: EXEC, headless: true });
const ctx = await b.newContext({ httpCredentials: CRED, viewport: { width: 1320, height: 1200 } });
const pg = await ctx.newPage();
const perr = []; pg.on('pageerror', e => perr.push(e.message));
// ---- graphics.html: charts wired + anchors correct ----
await pg.goto(BASE + '/graphics.html', { waitUntil: 'networkidle' });
await pg.waitForTimeout(1200);
const g = await pg.evaluate(() => {
const inst = window.Chart ? Object.values(window.Chart.instances) : [];
const onClicks = inst.map(c => typeof (c.config.options.onClick));
const statHrefs = [...document.querySelectorAll('#stats a.statlink')].map(a => a.getAttribute('href'));
const expLinks = [...document.querySelectorAll('#expTable tbody a.dl')].map(a => a.getAttribute('href'));
const loadErr = /load error/.test(document.querySelector('#stats')?.textContent || '');
return { charts: inst.length, onClicks, statHrefs, expLinks, loadErr };
});
ok(!g.loadErr, 'graphics stats loaded (no load error)');
ok(g.charts === 6, `6 charts rendered (got ${g.charts})`);
ok(g.onClicks.length === 6 && g.onClicks.every(t => t === 'function'), `all 6 charts have onClick (${g.onClicks.join(',')})`);
ok(g.statHrefs.includes('/condos.html?status=fha_expired'), 'stat "FHA-expired" → condos?status=fha_expired');
ok(g.statHrefs.includes('/condos.html?status=fha_approved'), 'stat "FHA-approved" → condos?status=fha_approved');
ok(g.statHrefs.includes('/crcp.html'), 'stat "brokers/firms" → crcp.html');
ok(g.statHrefs.includes('#expCard'), 'stat "lapsing <12mo" → #expCard anchor');
ok(g.expLinks.length >= 5 && g.expLinks.some(h => h.includes('status=fha_expired&q=')), 'expiring rows link project → condos?status=fha_expired&q=');
ok(g.expLinks.some(h => h.startsWith('/condos.html?city=')), 'expiring rows link city → condos?city=');
// ---- drill 1: condos ?status=fha_expired lands filtered ----
await pg.goto(BASE + '/condos.html?status=fha_expired', { waitUntil: 'networkidle' });
await pg.waitForTimeout(1000);
const c1 = await pg.evaluate(() => ({
activeChip: document.querySelector('#fWarr .chip.active')?.dataset.warr || null,
count: document.querySelector('#count')?.textContent || ''
}));
ok(c1.activeChip === 'fha_expired', `condos status deep-link active (chip=${c1.activeChip})`);
// ---- drill 2: condos ?city=Torrance resolves case-insensitively + filters ----
await pg.goto(BASE + '/condos.html?city=TORRANCE', { waitUntil: 'networkidle' });
await pg.waitForTimeout(1000);
const c2 = await pg.evaluate(() => {
const active = [...document.querySelectorAll('#fCity .chip.active')].map(x => x.dataset.cy);
return { active, count: document.querySelector('#count')?.textContent || '' };
});
ok(c2.active.length === 1 && /torrance/i.test(c2.active[0]), `condos ?city=TORRANCE resolved to real chip (${c2.active.join('|')})`);
// ---- drill 3: crcp ?broker=293 opens the broker modal ----
await pg.goto(BASE + '/crcp.html?broker=293&name=Errol%20Spiro', { waitUntil: 'networkidle' });
await pg.waitForTimeout(1400);
const c3 = await pg.evaluate(() => ({
open: document.querySelector('#ov')?.classList.contains('on'),
heading: document.querySelector('#mbody h2')?.textContent || ''
}));
ok(c3.open && /Errol Spiro/.test(c3.heading), `crcp ?broker=293 opened modal (${c3.heading.slice(0, 40)})`);
// ---- drill 4: crcp ?firm=... opens the firm modal ----
await pg.goto(BASE + '/crcp.html?firm=' + encodeURIComponent('Lyon Stahl Investment real Estate'), { waitUntil: 'networkidle' });
await pg.waitForTimeout(1400);
const c4 = await pg.evaluate(() => ({
open: document.querySelector('#ov')?.classList.contains('on'),
heading: document.querySelector('#mbody h2')?.textContent || ''
}));
ok(c4.open && /Lyon Stahl/i.test(c4.heading), `crcp ?firm deep-link opened firm modal (${c4.heading.slice(0, 40)})`);
ok(perr.length === 0, `no page errors (${perr.join(' | ') || 'clean'})`);
await b.close();
console.log('\n PASS (' + pass.length + '):'); pass.forEach(p => console.log(' ✓ ' + p));
if (fail.length) { console.log('\n FAIL (' + fail.length + '):'); fail.forEach(f => console.log(' ✗ ' + f)); process.exit(1); }
console.log('\n ✅ all drill assertions passed');
})().catch(e => { console.error('HARNESS ERROR:', e.message); process.exit(2); });