Tab-level choice (ped_last_tab) already survived sign-out/in via localStorage, but sub-pill and sub-tab selections inside a loaded tab lived only in memory — they reset to defaults after a reload or browser restart. Now the following are persisted under the ped_ui/ namespace: - Calculators nav pill (BP / BMI / GCS / …) - Bedside sub-pill (neonatal / airway / …) - Well Visit sub-tab (byvisit / milestones / shadess / note) - Physical Exam Guide age group + system Implementation: - Added public/js/ui-state.js — a ~30-line window.UIState wrapper around localStorage with a ped_ui/ prefix and try/catch around both read and write (Safari private mode + quota errors silently no-op). - Each tab's click handler now also calls UIState.set; each tab's init path calls UIState.get and replays the saved value through the same function a click would call — so there is exactly one code path for "show this selection", whether it came from the user or from a restore. For Bedside, the restore additionally listens for tabChanged so the lazy-loaded HTML is guaranteed to exist by the time we re-activate the pill. Tests: - e2e/tests/ui-state-persistence.spec.js — 5 specs × 2 viewports = 10 tests. Each clicks the feature, reloads the page, and asserts the same pill / subtab / dropdown value is still active. Catches any future regression in the persistence wiring. - e2e/tests/soap-hospital-workflow.spec.js — fills SOAP transcript, generates via mocked AI, clears, opens/closes load popovers; also smoke-tests the Hospital Course save-bar. Suite: 250 passed / 0 failed (+ 20 over the last run).
75 lines
3.1 KiB
JavaScript
75 lines
3.1 KiB
JavaScript
// ============================================================
|
|
// SOAP + HOSPITAL COURSE — detailed workflow for the two notes
|
|
// tabs that previously only had smoke coverage.
|
|
// ============================================================
|
|
|
|
const { test, expect, E2E_BASE, mockAI } = require('../fixtures');
|
|
|
|
async function openTab(page, name) {
|
|
await page.goto(E2E_BASE + '/');
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
const vp = page.viewportSize();
|
|
if (vp && vp.width <= 768) {
|
|
await page.click('#btn-menu-toggle').catch(() => {});
|
|
}
|
|
await page.click(`button.tab-btn[data-tab="${name}"]`);
|
|
await page.waitForFunction((t) => {
|
|
const el = document.getElementById(t + '-tab');
|
|
return el && el.classList.contains('active') && el.innerHTML.trim().length > 100;
|
|
}, name, { timeout: 15000 });
|
|
}
|
|
|
|
test.describe('SOAP Note — generate + refine', () => {
|
|
|
|
test('fill transcript + generate → mocked SOAP renders', async ({ authedPage: _, page }) => {
|
|
await mockAI(page);
|
|
await openTab(page, 'soap');
|
|
|
|
await page.fill('#soap-age', '5 years');
|
|
await page.selectOption('#soap-gender', 'Male');
|
|
await page.locator('#soap-transcript').click();
|
|
await page.keyboard.type('Patient presents with 3 days of fever, cough, and runny nose.');
|
|
|
|
const [resp] = await Promise.all([
|
|
page.waitForResponse('**/api/generate-soap', { timeout: 15000 }),
|
|
page.click('#soap-generate-btn'),
|
|
]);
|
|
expect(resp.status()).toBe(200);
|
|
await expect(page.locator('#soap-output')).toBeVisible({ timeout: 10000 });
|
|
await expect(page.locator('#soap-text')).toContainText('MOCK SOAP NOTE');
|
|
});
|
|
|
|
test('clear transcript button empties the contenteditable', async ({ authedPage: _, page }) => {
|
|
await mockAI(page);
|
|
await openTab(page, 'soap');
|
|
await page.locator('#soap-transcript').click();
|
|
await page.keyboard.type('some transcript');
|
|
await expect(page.locator('#soap-transcript')).toContainText('some transcript');
|
|
await page.click('#soap-clear');
|
|
const text = await page.locator('#soap-transcript').innerText();
|
|
expect(text.trim()).toBe('');
|
|
});
|
|
|
|
test('load popover opens and closes', async ({ authedPage: _, page }) => {
|
|
await openTab(page, 'soap');
|
|
await page.click('#btn-soap-load').catch(() => page.click('button[id*="soap-load"]'));
|
|
await expect(page.locator('#soap-load-popover')).not.toHaveClass(/hidden/, { timeout: 3000 });
|
|
});
|
|
});
|
|
|
|
test.describe('Hospital Course — tab loads with save/load bar', () => {
|
|
|
|
test('tab renders with label input + save/load/new buttons', async ({ authedPage: _, page }) => {
|
|
await openTab(page, 'hospital');
|
|
await expect(page.locator('#hosp-label')).toBeVisible();
|
|
await expect(page.locator('#hosp-save-bar')).toBeVisible();
|
|
});
|
|
|
|
test('load popover opens and closes', async ({ authedPage: _, page }) => {
|
|
await openTab(page, 'hospital');
|
|
// Any button with id that looks like load
|
|
const loadBtn = page.locator('button[id*="hosp-load"], button[id*="btn-hosp-load"]').first();
|
|
await loadBtn.click();
|
|
await expect(page.locator('#hosp-load-popover')).not.toHaveClass(/hidden/, { timeout: 3000 });
|
|
});
|
|
});
|