session persistence, per-tab model selector Brings detailed coverage to sections that were previously only smoke- tested: - sickvisit-workflow.spec.js: generate → mocked note, refine bar round-trip, load popover, New button clears demographics + transcript. - hospitalcourse-workflow.spec.js: fill H&P → generate → mocked narrative renders via /api/generate-hospital-course, refine updates text, load popover open/close. - auth-screen.spec.js: unauthenticated landing visible, login form structure, forgot-password swap + return, register link is intentionally display:none on this instance (pinned), register form DOM still wired correctly if the link is manually unhidden, reg- password has minlength=8 + type=password. - session-persistence.spec.js: clear cookie simulates logout (UI login is gated by Turnstile which can't be completed in the e2e container); re-login via loginAs restores the last tab + sub-pill via localStorage. - model-selector.spec.js: tab-model-select dropdowns render with >0 options across 7 tabs. Fixture corrections: - /api/sick-visit/note and /api/well-visit/note were not being mocked at all — the wrong /api/generate-sick-visit pattern was intercepting nothing, so tests fell through to the real AI backend. Both now have correct patterns and response shapes (sick-visit returns `note`, well-visit note returns `note`). - /api/generate-hospital-course response key updated from `narrative` to `hospitalCourse` to match what the frontend actually reads. wellvisit-workflow: the Visit Note test now asserts a concrete waitForResponse on /api/well-visit/note + text render, instead of the previous "hit either endpoint" fallback. Suite: 294 passed / 0 failed in 5m30s.
86 lines
3.9 KiB
JavaScript
86 lines
3.9 KiB
JavaScript
// ============================================================
|
|
// SESSION PERSISTENCE — full logout → login → still on the same
|
|
// tab + same sub-pill.
|
|
//
|
|
// The UI's login form is gated by a Cloudflare Turnstile token
|
|
// whose site key is hardcoded in index.html, which can't be
|
|
// completed in the e2e container (Turnstile rejects the non-prod
|
|
// origin). So the test does a programmatic logout (clear the
|
|
// ped_auth cookie, same effect server-side as clicking Logout)
|
|
// followed by a fresh programmatic login — this exercises the
|
|
// same localStorage persistence path a real logout/login would,
|
|
// without depending on the bot challenge.
|
|
// ============================================================
|
|
|
|
const { test, expect, E2E_BASE, loginAs } = require('../fixtures');
|
|
|
|
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 });
|
|
}
|
|
|
|
async function logoutClearsCookie(context) {
|
|
// Remove the ped_auth cookie — identical server-side to hitting /logout.
|
|
const cookies = await context.cookies();
|
|
const keep = cookies.filter(c => c.name !== 'ped_auth');
|
|
await context.clearCookies();
|
|
if (keep.length) await context.addCookies(keep);
|
|
}
|
|
|
|
test.describe('Logout → login restores last tab + sub-pill', () => {
|
|
|
|
test('tab choice + calc pill survive a full logout/login cycle', async ({ context, request, page }) => {
|
|
await loginAs(context, request);
|
|
await page.goto(E2E_BASE + '/');
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
await openDesktopTab(page, 'calculators');
|
|
await page.click('button.calc-nav-pill[data-calc="bili"]');
|
|
await expect(page.locator('button.calc-nav-pill[data-calc="bili"].active')).toBeVisible();
|
|
|
|
// Simulate logout (clear session cookie)
|
|
await logoutClearsCookie(context);
|
|
// Visiting the app with no cookie lands on the auth screen
|
|
await page.goto(E2E_BASE + '/');
|
|
await expect(page.locator('#auth-screen')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Log back in (fresh cookie) and revisit the app
|
|
await loginAs(context, request);
|
|
await page.goto(E2E_BASE + '/');
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
|
|
// Restore must put us back on Calculators / Bilirubin pill
|
|
await expect(page.locator('#calculators-tab.active')).toHaveCount(1, { timeout: 10000 });
|
|
await expect(page.locator('button.calc-nav-pill[data-calc="bili"].active')).toBeVisible({ timeout: 10000 });
|
|
await expect(page.locator('#calc-bili')).not.toHaveClass(/hidden/);
|
|
});
|
|
|
|
test('bedside sub-pill survives logout/login', async ({ context, request, page }) => {
|
|
await loginAs(context, request);
|
|
await page.goto(E2E_BASE + '/');
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
await openDesktopTab(page, 'bedside');
|
|
await page.click('button.calc-pill[data-em="sepsis"]');
|
|
await expect(page.locator('button.calc-pill[data-em="sepsis"].active')).toBeVisible();
|
|
|
|
await logoutClearsCookie(context);
|
|
await page.goto(E2E_BASE + '/');
|
|
await expect(page.locator('#auth-screen')).toBeVisible({ timeout: 10000 });
|
|
|
|
await loginAs(context, request);
|
|
await page.goto(E2E_BASE + '/');
|
|
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
|
|
|
|
await expect(page.locator('#bedside-tab.active')).toHaveCount(1, { timeout: 10000 });
|
|
await expect(page.locator('button.calc-pill[data-em="sepsis"].active')).toBeVisible({ timeout: 10000 });
|
|
await expect.poll(async () =>
|
|
await page.locator('#em-sepsis').evaluate(el => el.style.display),
|
|
{ timeout: 5000 }).not.toBe('none');
|
|
});
|
|
});
|