pediatric-ai-scribe-v3/e2e/tests/auth-screen.spec.js
Daniel 3e3b4866be test(e2e): +44 tests — sick visit, hospital course, auth screen,
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.
2026-04-23 18:58:38 +02:00

73 lines
3.7 KiB
JavaScript

// ============================================================
// AUTH SCREEN — unauthenticated landing page structure.
// These tests do NOT use the `authedPage` fixture; they visit the
// app with a fresh context (no cookie) and assert the sign-in
// form + register + forgot-password transitions render correctly.
// ============================================================
const { test, expect, E2E_BASE } = require('../fixtures');
test.describe('Unauthenticated auth screen', () => {
// Use the base test that doesn't auto-login.
test('landing shows login form with email + password fields', async ({ page }) => {
await page.goto(E2E_BASE + '/');
await expect(page.locator('#auth-screen')).toBeVisible({ timeout: 10000 });
await expect(page.locator('#login-email')).toBeVisible();
await expect(page.locator('#login-password')).toBeVisible();
await expect(page.locator('#btn-local-login')).toBeVisible();
// main app body must be hidden while unauthenticated
await expect(page.locator('#main-app')).toBeHidden();
});
test('register link is present but currently disabled (display:none)', async ({ page }) => {
// Daniel's instance has invite-only registration — the "Create account"
// link is explicitly hidden via inline style, so the HTML is there but
// users can't reach the register form through the UI. Verify the hidden
// state so flipping the style to re-enable it fails loudly.
await page.goto(E2E_BASE + '/');
await page.waitForSelector('#auth-screen', { timeout: 10000 });
const display = await page.locator('#show-register').evaluate(el => el.style.display);
expect(display).toBe('none');
// The register form element still exists in the DOM for programmatic access
await expect(page.locator('#register-form')).toHaveCount(1);
});
test('register form DOM is wired correctly if manually unhidden', async ({ page }) => {
await page.goto(E2E_BASE + '/');
await page.waitForSelector('#auth-screen', { timeout: 10000 });
// Force the link visible so we can exercise the swap path — useful for
// future tests that want to validate the full register flow.
await page.locator('#show-register').evaluate(el => { el.style.display = ''; });
await page.click('#show-register');
await expect(page.locator('#register-form')).toBeVisible();
await expect(page.locator('#reg-name')).toBeVisible();
await expect(page.locator('#reg-email')).toBeVisible();
await expect(page.locator('#reg-password')).toBeVisible();
await page.click('#show-login');
await expect(page.locator('#login-form')).toBeVisible();
await expect(page.locator('#register-form')).toBeHidden();
});
test('clicking "Forgot password?" swaps to forgot form', async ({ page }) => {
await page.goto(E2E_BASE + '/');
await page.waitForSelector('#auth-screen', { timeout: 10000 });
await page.click('#show-forgot');
await expect(page.locator('#forgot-form')).toBeVisible();
await expect(page.locator('#forgot-email')).toBeVisible();
await expect(page.locator('#login-form')).toBeHidden();
// Back link returns to login
await page.click('#show-login-2');
await expect(page.locator('#login-form')).toBeVisible();
await expect(page.locator('#forgot-form')).toBeHidden();
});
test('password minlength enforces 8 chars in register form', async ({ page }) => {
await page.goto(E2E_BASE + '/');
await page.waitForSelector('#auth-screen', { timeout: 10000 });
// Attribute check doesn't require the element to be visible.
const pw = page.locator('#reg-password');
await expect(pw).toHaveAttribute('minlength', '8');
await expect(pw).toHaveAttribute('type', 'password');
});
});