Files
nur-falah-prevention/e2e-info.cjs
T
wmj 4d244db6d0 Add (i) info button to every tab, explained for the average user
New InfoPanel.svelte: shared (i) button next to each module's h2, toggling
a plain-language explainer with three sections — what this tab is, how to
use it, what to enter in each field. One component so tone stays
consistent across all 10 tabs instead of each screen inventing its own
help pattern.

Deliberately avoids fiqh/legal jargon in favor of concrete, everyday
framing (e.g. Hibah explained as "a gift you give right now, while you're
alive" rather than leading with the Arabic term) — written for someone
with no prior estate-planning or Islamic finance background, consistent
with the "convince a 100-year-old grandmother" usability bar already
established for this product.

Wired into: Coverage, Faraid, Assets, Wassiyah, Hibah, Family Waqf,
Nominate, Trigger, Claims (H2), Settings.

e2e-info.cjs: new suite verifying the info button appears, opens a
non-trivial explanation, and closes again on every one of the 10 tabs.
31/31 passing. Re-verified all five prior suites (32/32, 16/16, 12/12,
10/10, 10/10) — 111/111 total, no regressions.
2026-08-13 18:14:28 +08:00

50 lines
2.4 KiB
JavaScript

// Verifies every tab has a working (i) info button that opens plain-language help.
const { chromium } = require('playwright');
const BASE = 'https://moslem04.falahos.my/';
const results = [];
const consoleErrors = [];
function record(name, pass, detail = '') { results.push({ name, pass, detail }); console.log(`${pass ? 'PASS' : 'FAIL'} ${name}${detail ? ' — ' + detail : ''}`); }
const TABS = ['Coverage', 'Faraid', 'Assets', 'Wassiyah', 'Hibah', 'Family Waqf', 'Nominate', 'Trigger', 'Claims (H2)', 'Settings'];
async function main() {
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 390, height: 844 } });
page.on('console', m => { if (m.type() === 'error') consoleErrors.push(m.text()); });
page.on('pageerror', e => consoleErrors.push(e.message));
await page.goto(BASE, { waitUntil: 'networkidle' });
for (const label of TABS) {
await page.locator('nav button.tab', { hasText: label }).click();
await page.waitForTimeout(200);
const infoBtn = page.locator('.module-header .info-btn');
const btnVisible = await infoBtn.isVisible();
record(`"${label}": info button visible`, btnVisible);
if (!btnVisible) continue;
await infoBtn.click();
await page.waitForTimeout(150);
const panelVisible = await page.locator('.info-panel').isVisible();
const whatText = await page.locator('.info-panel .info-section p').first().textContent().catch(() => '');
record(`"${label}": info panel opens with non-trivial explanation`, panelVisible && whatText.length > 40, `${whatText.length} chars`);
// toggle closed
await infoBtn.click();
await page.waitForTimeout(150);
const panelClosed = await page.locator('.info-panel').isVisible().catch(() => false);
record(`"${label}": info panel closes on second click`, !panelClosed);
}
record('No uncaught JS console errors across all info panels', consoleErrors.length === 0, consoleErrors.join(' || '));
await browser.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}`));
process.exit(failCount > 0 ? 1 : 0);
}
main().catch(e => { console.error('SCRIPT ERROR:', e); process.exit(2); });