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).
This commit is contained in:
Daniel 2026-04-20 23:19:49 +02:00
parent 7e7d469172
commit fe7b3687ee

View file

@ -0,0 +1,220 @@
// 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/);
});
});