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.
89 lines
3.9 KiB
JavaScript
89 lines
3.9 KiB
JavaScript
// ============================================================
|
|
// SICK VISIT — detailed workflow tests
|
|
// Fills the form, generates a mocked note, verifies output render
|
|
// and the refine + clear flows.
|
|
// ============================================================
|
|
|
|
const { test, expect, E2E_BASE, mockAI } = require('../fixtures');
|
|
|
|
async function openTab(page) {
|
|
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="sickvisit"]');
|
|
await page.waitForFunction(() => {
|
|
const el = document.getElementById('sickvisit-tab');
|
|
return el && el.classList.contains('active') && el.innerHTML.trim().length > 100;
|
|
}, { timeout: 15000 });
|
|
}
|
|
|
|
test.describe('Sick Visit — generate workflow', () => {
|
|
|
|
test('fill demographics + CC + transcript → mocked note renders', async ({ authedPage: _, page }) => {
|
|
await mockAI(page);
|
|
await openTab(page);
|
|
|
|
await page.fill('#sick-age', '6 years');
|
|
await page.selectOption('#sick-gender', 'Male');
|
|
await page.fill('#sick-cc', 'Sore throat x 3 days');
|
|
await page.locator('#sick-transcript').click();
|
|
await page.keyboard.type('6yo with 3 days sore throat, fever, fatigue. No rash.');
|
|
|
|
const [resp] = await Promise.all([
|
|
page.waitForResponse('**/api/sick-visit/note', { timeout: 15000 }),
|
|
page.click('#btn-sick-generate'),
|
|
]);
|
|
expect(resp.status()).toBe(200);
|
|
await expect(page.locator('#sick-note-output')).toBeVisible({ timeout: 10000 });
|
|
await expect(page.locator('#sick-note-text')).toContainText('MOCK sick visit note');
|
|
});
|
|
|
|
test('refine button fires /api/refine and updates the rendered note', async ({ authedPage: _, page }) => {
|
|
await mockAI(page, {
|
|
'**/api/refine': { success: true, refined: 'REFINED sick-visit note — added return precautions.', model: 'mock-gpt' },
|
|
});
|
|
await openTab(page);
|
|
await page.fill('#sick-age', '4 years');
|
|
await page.fill('#sick-cc', 'Cough');
|
|
await page.locator('#sick-transcript').click();
|
|
await page.keyboard.type('Cough x 2 days, no fever, hydrating OK.');
|
|
await page.click('#btn-sick-generate');
|
|
await expect(page.locator('#sick-note-text')).toContainText('MOCK sick visit note', { timeout: 10000 });
|
|
|
|
await page.fill('#sick-refine-input', 'Add return precautions.');
|
|
const [resp] = await Promise.all([
|
|
page.waitForResponse('**/api/refine'),
|
|
page.click('#sick-refine-btn'),
|
|
]);
|
|
expect(resp.status()).toBe(200);
|
|
await expect(page.locator('#sick-note-text')).toContainText('REFINED sick-visit note', { timeout: 10000 });
|
|
});
|
|
|
|
test('load popover opens and closes', async ({ authedPage: _, page }) => {
|
|
await openTab(page);
|
|
await page.click('#btn-sick-load');
|
|
await expect(page.locator('#sick-load-popover')).not.toHaveClass(/hidden/, { timeout: 3000 });
|
|
// Close by clicking the close button inside the popover
|
|
await page.locator('#sick-load-popover .enc-pop-close').click();
|
|
await expect(page.locator('#sick-load-popover')).toHaveClass(/hidden/);
|
|
});
|
|
|
|
test('New button clears demographics + transcript for a new patient', async ({ authedPage: _, page }) => {
|
|
await mockAI(page);
|
|
await openTab(page);
|
|
await page.fill('#sick-age', '5 years');
|
|
await page.selectOption('#sick-gender', 'Male');
|
|
await page.locator('#sick-transcript').click();
|
|
await page.keyboard.type('Temporary transcript');
|
|
await page.click('#btn-sick-new');
|
|
// clearTab() resets demographics + transcript (chief complaint is left so a
|
|
// rapid "next patient with same complaint" doesn't have to retype it).
|
|
await expect(page.locator('#sick-age')).toHaveValue('');
|
|
await expect(page.locator('#sick-gender')).toHaveValue('');
|
|
const txt = await page.locator('#sick-transcript').innerText();
|
|
expect(txt.trim()).toBe('');
|
|
});
|
|
});
|