pediatric-ai-scribe-v3/e2e/tests/top-calculators.spec.js
Daniel aa3399504b test(e2e): add 27 Playwright smoke tests for top-row calculator tabs
Covers BP / BMI / BSA / Weight-Based Dosing / Growth / Bilirubin / Vitals /
Resus Meds / GCS / Equipment. Each tab gets: panel-loads test + one
full input→calculate→result flow. Extras for BP (Clear), Dose (max cap),
Growth (sub-pill), Bili (Bhutani sub-pill), GCS (motor change, infant switch),
Equipment (empty re-select hides).

All 53 e2e tests pass (26 Bedside + 27 top-calculators).
2026-04-20 23:19:50 +02:00

220 lines
8.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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/);
});
});