// Verifies the 5 dummy demo families actually render correctly in the live // app — not just that the SQL inserts succeeded. Logs in as each owner, // checks the family switcher shows exactly one family, and inspects // Coverage/Assets/Tree for expected content. const { chromium } = require('playwright'); const BASE = 'https://moslem04.falahos.my/'; const results = []; function record(name, pass, detail = '') { results.push({ name, pass, detail }); console.log(`${pass ? 'PASS' : 'FAIL'} ${name}${detail ? ' — ' + detail : ''}`); } const FAMILIES = [ { email: 'nf.demo.ismail@gmail.com', name: 'The Ismail Family', expectedAssets: 5, expectedPeople: 6 }, { email: 'nf.demo.rahman@gmail.com', name: 'The Rahman Family (UK)', expectedAssets: 4, expectedPeople: 4 }, { email: 'nf.demo.osman@gmail.com', name: 'The Osman Family', expectedAssets: 6, expectedPeople: 6 }, { email: 'nf.demo.yusuf@gmail.com', name: 'The Yusuf Family', expectedAssets: 4, expectedPeople: 3 }, { email: 'nf.demo.karim@gmail.com', name: 'The Karim Family', expectedAssets: 3, expectedPeople: 3 }, ]; const PASSWORD = 'DemoPassword123!'; async function main() { const browser = await chromium.launch(); for (const fam of FAMILIES) { const page = await (await browser.newContext({ viewport: { width: 390, height: 844 } })).newPage(); await page.goto(BASE, { waitUntil: 'networkidle' }); await page.locator('.field:has-text("Email") input').fill(fam.email); await page.locator('.field:has-text("Password") input').fill(PASSWORD); await page.locator('button.btn-primary', { hasText: 'Sign in' }).click(); await page.waitForTimeout(1500); // Owner may land on the family switcher (their own family plus, in some // seeded cases, no others) — select the family by name if so. const switcherVisible = await page.locator('.switcher-screen').isVisible({ timeout: 8000 }).catch(() => false); if (switcherVisible) { const familyRowVisible = await page.locator('.family-row', { hasText: fam.name }).isVisible().catch(() => false); record(`${fam.name}: family switcher shows this family by name`, familyRowVisible); if (familyRowVisible) { await page.locator('.family-row', { hasText: fam.name }).click(); await page.waitForTimeout(1000); } } const onMainApp = await page.locator('nav button[aria-label="Coverage"]').isVisible({ timeout: 8000 }).catch(() => false); record(`${fam.name}: owner reaches the main app`, onMainApp); if (!onMainApp) { await page.close(); continue; } // Assets await page.locator('nav button[aria-label="Assets"]').click(); await page.waitForTimeout(800); const assetCount = await page.locator('.asset-row').count(); record(`${fam.name}: has ${fam.expectedAssets} assets`, assetCount === fam.expectedAssets, `found ${assetCount}`); const totalText = await page.locator('.total-card strong').textContent().catch(() => ''); record(`${fam.name}: estate total is non-zero`, /[1-9]/.test(totalText), totalText.trim()); // Coverage await page.locator('nav button[aria-label="Coverage"]').click(); await page.waitForTimeout(800); const pctText = await page.locator('.big-percent').textContent().catch(() => ''); record(`${fam.name}: Coverage Dashboard shows a percentage`, /%/.test(pctText), pctText.trim()); // Family Tree await page.locator('nav button[aria-label="Tree"]').click(); await page.waitForTimeout(800); const peopleCount = await page.locator('.person-card').count(); record(`${fam.name}: has ${fam.expectedPeople} people in the tree`, peopleCount === fam.expectedPeople, `found ${peopleCount}`); const treeText = await page.locator('.tree-section').innerText().catch(() => ''); const hasTreeContent = treeText.length > 20 && !treeText.includes('Add people and relationships above'); record(`${fam.name}: generational tree actually renders (not empty)`, hasTreeContent, treeText.replace(/\s+/g, ' ').slice(0, 150)); await page.close(); } const passCount = results.filter(r => r.pass).length; const failCount = results.length - passCount; console.log(`\n${passCount} passed, ${failCount} failed, ${results.length} total`); if (failCount > 0) results.filter(r => !r.pass).forEach(r => console.log(` - ${r.name}: ${r.detail}`)); await browser.close(); process.exit(failCount > 0 ? 1 : 0); } main().catch(e => { console.error('SCRIPT ERROR:', e); process.exit(2); });