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).
89 lines
4.2 KiB
JavaScript
89 lines
4.2 KiB
JavaScript
// ============================================================
|
|
// UI STATE PERSISTENCE — sub-pill / sub-tab choices survive a
|
|
// full page reload (simulating sign-out / sign-in or browser
|
|
// restart). Guards against regressions in the ui-state.js +
|
|
// localStorage wiring.
|
|
// ============================================================
|
|
|
|
const { test, expect, E2E_BASE } = require('../fixtures');
|
|
|
|
async function gotoHome(page) {
|
|
await page.goto(E2E_BASE + '/');
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
}
|
|
|
|
async function openDesktopTab(page, name) {
|
|
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('UI state survives page reload', () => {
|
|
|
|
test('ped_last_tab → user lands on last-active tab after reload', async ({ authedPage: _, page }) => {
|
|
await gotoHome(page);
|
|
await openDesktopTab(page, 'calculators');
|
|
// Reload (keeps cookie, clears _componentCache + in-memory DOM state)
|
|
await page.reload();
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
await expect.poll(async () => {
|
|
return await page.locator('#calculators-tab.active').count();
|
|
}, { timeout: 5000 }).toBe(1);
|
|
});
|
|
|
|
test('calculators nav pill persists across reload', async ({ authedPage: _, page }) => {
|
|
await gotoHome(page);
|
|
await openDesktopTab(page, 'calculators');
|
|
// Switch to GCS
|
|
await page.click('button.calc-nav-pill[data-calc="gcs"]');
|
|
await expect(page.locator('button.calc-nav-pill[data-calc="gcs"].active')).toBeVisible();
|
|
await page.reload();
|
|
await page.waitForSelector('button.calc-nav-pill[data-calc="gcs"]', { timeout: 15000 });
|
|
// Same pill should be active after reload
|
|
await expect(page.locator('button.calc-nav-pill[data-calc="gcs"].active')).toBeVisible({ timeout: 5000 });
|
|
// And the corresponding panel should be un-hidden
|
|
await expect(page.locator('#calc-gcs')).not.toHaveClass(/hidden/);
|
|
});
|
|
|
|
test('bedside sub-pill persists across reload', async ({ authedPage: _, page }) => {
|
|
await gotoHome(page);
|
|
await openDesktopTab(page, 'bedside');
|
|
await page.click('button.calc-pill[data-em="anaphylaxis"]');
|
|
await expect(page.locator('button.calc-pill[data-em="anaphylaxis"].active')).toBeVisible();
|
|
await page.reload();
|
|
await page.waitForSelector('button.calc-pill[data-em="anaphylaxis"]', { timeout: 15000 });
|
|
await expect(page.locator('button.calc-pill[data-em="anaphylaxis"].active')).toBeVisible({ timeout: 5000 });
|
|
// The anaphylaxis em-section should be the visible one
|
|
await expect.poll(async () => {
|
|
return await page.locator('#em-anaphylaxis').evaluate(el => el.style.display);
|
|
}, { timeout: 5000 }).not.toBe('none');
|
|
});
|
|
|
|
test('well-visit sub-tab persists across reload', async ({ authedPage: _, page }) => {
|
|
await gotoHome(page);
|
|
await openDesktopTab(page, 'wellvisit');
|
|
await page.click('button.wv-subtab-btn[data-subtab="milestones"]');
|
|
await expect(page.locator('#wv-panel-milestones')).not.toHaveClass(/hidden/);
|
|
await page.reload();
|
|
await page.waitForSelector('button.wv-subtab-btn[data-subtab="milestones"]', { timeout: 15000 });
|
|
await expect(page.locator('#wv-panel-milestones')).not.toHaveClass(/hidden/, { timeout: 5000 });
|
|
});
|
|
|
|
test('PE guide age group + system persist across reload', async ({ authedPage: _, page }) => {
|
|
await gotoHome(page);
|
|
await openDesktopTab(page, 'peguide');
|
|
await page.selectOption('#pe-age-group', 'adolescent');
|
|
await page.click('button[data-pesystem="neuro"]');
|
|
await expect(page.locator('button[data-pesystem="neuro"].active')).toBeVisible();
|
|
await page.reload();
|
|
await page.waitForSelector('#pe-age-group', { timeout: 15000 });
|
|
await expect(page.locator('#pe-age-group')).toHaveValue('adolescent', { timeout: 5000 });
|
|
await expect(page.locator('button[data-pesystem="neuro"].active')).toBeVisible({ timeout: 5000 });
|
|
});
|
|
});
|