// Bedside module smoke tests. // Each test navigates to the Calculators tab, opens Bedside, clicks the target // sub-pill, and asserts a known string is rendered. Catches "button doesn't // fire / section goes blank" regressions. const { test, expect } = require('@playwright/test'); // Helper — open Calculators tab + Bedside panel + (optionally) a sub-pill async function openCalculators(page) { await page.goto('/e2e-harness.html'); await page.waitForFunction(() => window.__harnessReady === true); // Give the async innerHTML injection + JS init one more microtask tick await page.waitForSelector('button.calc-nav-pill[data-calc="bedside"]'); } async function openBedside(page, subPill) { await openCalculators(page); await page.click('button.calc-nav-pill[data-calc="bedside"]'); if (subPill) { await page.click(`button.calc-pill[data-em="${subPill}"]`); } } test.describe('Bedside — top-level', () => { test('Calculators tab shows age-weight estimator', async ({ page }) => { await openCalculators(page); await expect(page.locator('#bedside-age')).toBeVisible(); await expect(page.locator('#bedside-formula')).toBeVisible(); await expect(page.locator('#bedside-weight')).toBeVisible(); }); test('Age → Weight: typing 3y auto-fills weight (APLS)', async ({ page }) => { await openCalculators(page); await page.fill('#bedside-age', '3y'); await expect(page.locator('#bedside-weight')).toHaveValue('14'); await expect(page.locator('#bedside-estimate-note')).toContainText('APLS'); }); test('Formula switch to Best Guess updates weight', async ({ page }) => { await openCalculators(page); await page.fill('#bedside-age', '3y'); await page.selectOption('#bedside-formula', 'bestguess'); await expect(page.locator('#bedside-weight')).toHaveValue('16'); // 2 * (3+5) = 16 await expect(page.locator('#bedside-estimate-note')).toContainText('Best Guess'); }); test('Clear button resets the estimator', async ({ page }) => { await openCalculators(page); await page.fill('#bedside-age', '5y'); await page.click('#btn-bedside-clear'); await expect(page.locator('#bedside-age')).toHaveValue(''); await expect(page.locator('#bedside-weight')).toHaveValue(''); }); }); test.describe('Bedside — every sub-pill renders', () => { const subPills = [ { key: 'neonatal', expected: /Neonatal Assessment/i }, { key: 'airway', expected: /Airway Management/i }, { key: 'cardiac', expected: /Cardiac Arrest/i }, { key: 'respiratory', expected: /Respiratory Management/i }, { key: 'ventilation', expected: /Oxygen & Ventilation/i }, { key: 'seizure', expected: /Status Epilepticus/i }, { key: 'sepsis', expected: /Sepsis & Fever/i }, { key: 'anaphylaxis', expected: /Anaphylaxis/i }, { key: 'sedation', expected: /Procedural Sedation/i }, { key: 'agitation', expected: /Acute Agitation/i }, { key: 'antiemetics', expected: /Antiemetics/i }, { key: 'antimicrobials', expected: /Empiric Antimicrobials/i }, { key: 'burns', expected: /Burn Management/i }, { key: 'toxicology', expected: /Toxicology/i }, { key: 'trauma', expected: /Trauma/i }, ]; for (const { key, expected } of subPills) { test(`${key} sub-pill shows header`, async ({ page }) => { await openBedside(page, key); await expect(page.locator(`#em-${key}`)).toContainText(expected); }); } }); test.describe('Bedside — dose calculators fire', () => { test('Status Epilepticus: Show Pathway renders timeline with weight', async ({ page }) => { await openBedside(page, 'seizure'); await page.fill('#seizure-weight', '20'); await page.click('#btn-seizure-calc'); await expect(page.locator('#seizure-result')).toContainText(/20 kg/); await expect(page.locator('#seizure-result')).toContainText(/Lorazepam/); await expect(page.locator('#seizure-result')).toContainText(/0\.1 mg\/kg/); // per-kg visible }); test('Sepsis: Show Approach renders Phoenix criteria + first-hour bundle', async ({ page }) => { await openBedside(page, 'sepsis'); await page.fill('#sepsis-weight', '25'); await page.click('#btn-sepsis-show'); await expect(page.locator('#sepsis-result')).toContainText(/Phoenix/); await expect(page.locator('#sepsis-result')).toContainText(/first-hour/i); }); test('Anaphylaxis: Calculate Doses shows weight-based epinephrine', async ({ page }) => { await openBedside(page, 'anaphylaxis'); await page.fill('#anaph-weight', '25'); await page.click('#btn-anaph-calc'); await expect(page.locator('#anaph-result')).toContainText(/Epinephrine/); await expect(page.locator('#anaph-result')).toContainText(/0\.25 mg/); // 25*0.01 }); test('Burns: body-parts calculator + Parkland', async ({ page }) => { await openBedside(page, 'burns'); await page.fill('#burn-weight', '20'); await page.fill('input[data-burn-region="head"]', '50'); // 50% of 13 (young) = 6.5 await page.fill('input[data-burn-region="ant_trunk"]', '100'); // 100% of 13 = 13 await page.click('#btn-burn-calc'); await expect(page.locator('#burn-result')).toContainText(/Parkland/); await expect(page.locator('#burn-result')).toContainText(/20 kg/); }); test('Airway: Calculate renders RSI drugs with per-kg', async ({ page }) => { await openBedside(page, 'airway'); await page.fill('#airway-weight', '20'); await page.fill('#airway-age', '5'); await page.click('#btn-airway-calc'); await expect(page.locator('#airway-result')).toContainText(/Ketamine/); await expect(page.locator('#airway-result')).toContainText(/mg\/kg/); // per-kg visible await expect(page.locator('#airway-result')).toContainText(/ETT/); }); }); test.describe('Bedside — interactive widgets', () => { test('Lightbox: View pathway image button opens modal', async ({ page }) => { await openBedside(page, 'seizure'); await page.click('button[data-img-src="/img/epilepsy_eiic_pathway.png"]'); await expect(page.locator('#img-lightbox')).toBeVisible(); await page.click('#img-lightbox-close'); await expect(page.locator('#img-lightbox')).toBeHidden(); }); test('Ventilation: Show Reference renders pressure-time SVG', async ({ page }) => { await openBedside(page, 'ventilation'); await page.fill('#vent-weight', '20'); await page.click('#btn-vent-show'); await expect(page.locator('#vent-result svg')).toBeVisible(); await expect(page.locator('#vent-result')).toContainText(/Target SpO2/); await expect(page.locator('#vent-result')).toContainText(/PEEP/); }); });