// Smoke tests for the 10 top-row calculator tabs (everything except Bedside). // Each test navigates to its tab, fills inputs, clicks Calculate/Assess, // and asserts a known string appears in the result. Catches the "tab loads // but button does nothing" class of regression. const { test, expect } = require('@playwright/test'); async function openCalculators(page) { await page.goto('/e2e-harness.html'); await page.waitForFunction(() => window.__harnessReady === true); await page.waitForSelector('button.calc-nav-pill[data-calc="bp"]'); } async function selectTab(page, tabName) { await page.click(`button.calc-nav-pill[data-calc="${tabName}"]`); await expect(page.locator(`#calc-${tabName}`)).toBeVisible(); } test.describe('Top-level calculators — panel loads', () => { const tabs = ['bp', 'bmi', 'growth', 'bili', 'vitals', 'bsa', 'dose', 'resus', 'gcs', 'equipment']; for (const tab of tabs) { test(`${tab} panel becomes visible when pill clicked`, async ({ page }) => { await openCalculators(page); await selectTab(page, tab); }); } }); test.describe('Blood Pressure percentile', () => { test('5 yr, male, height 110, BP 105/65 → produces a result', async ({ page }) => { await openCalculators(page); await selectTab(page, 'bp'); await page.fill('#bp-age', '5'); await page.selectOption('#bp-sex', 'male'); await page.fill('#bp-height', '110'); await page.fill('#bp-systolic', '105'); await page.fill('#bp-diastolic', '65'); await page.click('#btn-calc-bp'); await expect(page.locator('#bp-result')).not.toHaveClass(/hidden/); // Result should mention a percentile or classification await expect(page.locator('#bp-result')).toContainText(/percentile|Normal|Elevated|HTN|Stage/i); }); test('Clear button hides result', async ({ page }) => { await openCalculators(page); await selectTab(page, 'bp'); await page.fill('#bp-age', '5'); await page.selectOption('#bp-sex', 'male'); await page.fill('#bp-height', '110'); await page.fill('#bp-systolic', '105'); await page.fill('#bp-diastolic', '65'); await page.click('#btn-calc-bp'); await page.click('#btn-clear-bp'); await expect(page.locator('#bp-result')).toHaveClass(/hidden/); await expect(page.locator('#bp-age')).toHaveValue(''); }); }); test.describe('BMI percentile', () => { test('7 yr, male, 25 kg, 120 cm → BMI computed', async ({ page }) => { await openCalculators(page); await selectTab(page, 'bmi'); await page.fill('#bmi-age-yr', '7'); await page.selectOption('#bmi-age-mo', '0'); await page.selectOption('#bmi-sex', 'male'); await page.fill('#bmi-weight', '25'); await page.fill('#bmi-height', '120'); await page.click('#btn-calc-bmi'); await expect(page.locator('#bmi-result')).not.toHaveClass(/hidden/); // BMI = 25 / 1.20² = 17.36 — expect something recognizable await expect(page.locator('#bmi-result')).toContainText(/17\.|BMI|percentile/i); }); }); test.describe('Body Surface Area (Mosteller)', () => { test('20 kg, 110 cm → BSA shown', async ({ page }) => { await openCalculators(page); await selectTab(page, 'bsa'); await page.fill('#bsa-weight', '20'); await page.fill('#bsa-height', '110'); await page.click('#btn-calc-bsa'); await expect(page.locator('#bsa-result')).not.toHaveClass(/hidden/); // sqrt(110*20/3600) = 0.782 await expect(page.locator('#bsa-result')).toContainText(/0\.78|BSA|m²|m2/i); }); }); test.describe('Weight-based dosing', () => { test('15 kg × 10 mg/kg → 150 mg shown', async ({ page }) => { await openCalculators(page); await selectTab(page, 'dose'); await page.fill('#dose-weight', '15'); await page.fill('#dose-per-kg', '10'); await page.click('#btn-calc-dose'); await expect(page.locator('#dose-result')).not.toHaveClass(/hidden/); await expect(page.locator('#dose-result')).toContainText(/150/); }); test('Max cap respected: 15 kg × 100 mg/kg capped at 500 mg', async ({ page }) => { await openCalculators(page); await selectTab(page, 'dose'); await page.fill('#dose-weight', '15'); await page.fill('#dose-per-kg', '100'); await page.fill('#dose-max', '500'); await page.click('#btn-calc-dose'); await expect(page.locator('#dose-result')).toContainText(/500/); }); }); test.describe('Growth charts', () => { test('3 yr male, 14 kg → Weight-for-Age result', async ({ page }) => { await openCalculators(page); await selectTab(page, 'growth'); await page.selectOption('#growth-sex', 'male'); await page.fill('#growth-age-yr', '3'); await page.fill('#growth-weight', '14'); await page.click('#btn-calc-growth'); await expect(page.locator('#growth-result')).not.toHaveClass(/hidden/); await expect(page.locator('#growth-result')).toContainText(/percentile|z-score|%ile|z=/i); }); test('Sub-pill switches to Length-for-Age', async ({ page }) => { await openCalculators(page); await selectTab(page, 'growth'); await page.click('button.calc-pill[data-growth="lfa"]'); await expect(page.locator('button.calc-pill[data-growth="lfa"]')).toHaveClass(/active/); }); }); test.describe('Bilirubin (AAP 2022)', () => { test('GA 38, age 48h, TSB 12.5, no risk factors → AAP assessment', async ({ page }) => { await openCalculators(page); await selectTab(page, 'bili'); await page.selectOption('#bili-ga', '38'); await page.fill('#bili-age-hours', '48'); await page.fill('#bili-tsb', '12.5'); await page.selectOption('#bili-risk', 'none'); await page.click('#btn-calc-bili-aap'); await expect(page.locator('#bili-result')).not.toHaveClass(/hidden/); await expect(page.locator('#bili-result')).toContainText(/phototherapy|threshold|AAP|bilirubin/i); }); test('Bhutani sub-pill: age 48h, TSB 8.5 → risk zone', async ({ page }) => { await openCalculators(page); await selectTab(page, 'bili'); await page.click('button.calc-pill[data-bili="bhutani"]'); await page.fill('#bhutani-age', '48'); await page.fill('#bhutani-tsb', '8.5'); await page.click('#btn-calc-bhutani'); await expect(page.locator('#bili-result')).not.toHaveClass(/hidden/); await expect(page.locator('#bili-result')).toContainText(/risk|zone|low|high|intermediate/i); }); }); test.describe('Vital signs reference', () => { test('Selecting 1-3 yr shows HR range', async ({ page }) => { await openCalculators(page); await selectTab(page, 'vitals'); await page.selectOption('#vitals-age-select', '1-3yr'); await expect(page.locator('#vitals-result')).not.toHaveClass(/hidden/); // Expected: HR 70-110 await expect(page.locator('#vitals-result')).toContainText(/70|HR/i); }); }); test.describe('Resus meds', () => { test('15 kg → multiple weight-based drug doses rendered', async ({ page }) => { await openCalculators(page); await selectTab(page, 'resus'); await page.fill('#resus-weight', '15'); await page.click('#btn-calc-resus'); await expect(page.locator('#resus-result')).not.toHaveClass(/hidden/); // At least epinephrine + atropine should appear for any resus dose table await expect(page.locator('#resus-result')).toContainText(/epinephrine|epi/i); await expect(page.locator('#resus-result')).toContainText(/atropine/i); }); }); test.describe('Glasgow Coma Scale', () => { test('Child defaults (4/5/6) → GCS 15 shown', async ({ page }) => { await openCalculators(page); await selectTab(page, 'gcs'); // selects default to max scores → 4+5+6 = 15 await expect(page.locator('#gcs-result')).toContainText(/15/); }); test('Changing motor to "None" (1) → GCS drops', async ({ page }) => { await openCalculators(page); await selectTab(page, 'gcs'); await page.selectOption('#gcs-child-motor', '1'); await expect(page.locator('#gcs-result')).toContainText(/10/); // 4+5+1 }); test('Switch to infant panel', async ({ page }) => { await openCalculators(page); await selectTab(page, 'gcs'); await page.click('button.calc-pill[data-gcs="infant"]'); await expect(page.locator('#gcs-infant-panel')).toBeVisible(); await expect(page.locator('#gcs-child-panel')).toBeHidden(); }); }); test.describe('Equipment sizing', () => { test('Selecting "1 year" renders sizes', async ({ page }) => { await openCalculators(page); await selectTab(page, 'equipment'); await page.selectOption('#equip-age-select', '1yr'); await expect(page.locator('#equip-result')).not.toHaveClass(/hidden/); // Should mention ETT and at least one other item await expect(page.locator('#equip-result')).toContainText(/ETT|Endotracheal/i); }); test('Selecting empty option hides result', async ({ page }) => { await openCalculators(page); await selectTab(page, 'equipment'); await page.selectOption('#equip-age-select', '1yr'); await page.selectOption('#equip-age-select', ''); await expect(page.locator('#equip-result')).toHaveClass(/hidden/); }); });