pediatric-ai-scribe-v3/e2e/tests/auth-gated-smoke.spec.js
Daniel 6b039c4d87 test: bring the e2e specs up to date with the app they test
Three specs were asserting screens that no longer exist. They passed for
as long as they did only because the e2e stack shared production's
database and its configuration; against a clean one they failed honestly.

Signing in is a stepped flow now — email, then a choice between a
password and an emailed code — so #login-password is in the DOM but
hidden until that choice is made. The spec asserted it visible on the
landing screen. Replaced with one test for the landing step and a new
one that walks the transition, which nothing covered before.

The register link is hidden only when registration is disabled. This
install has it enabled and invite-gated, so the link shows and the
invite field is required; the spec asserted display:none.

Connecting Nextcloud by signing in to Nextcloud is now the offered path,
with the username and app-password fields folded behind "Use an app
password instead". The spec asserted all three visible at once; it now
checks the primary path and then opens the fallback.

learning-tab.spec.js is deleted and `learning` is out of the smoke tab
list — that feature was removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-13 00:49:37 +02:00

66 lines
3.1 KiB
JavaScript

// Smoke tests for pages behind the auth wall. Runs against the separate
// `pediatric-ai-scribe-e2e` container (port 3553 on host, 3000 internal) which
// has TURNSTILE_SECRET_KEY="" + SMTP_HOST="" so tests can log in without a
// bot challenge and register auto-verifies.
//
// Each test logs in via the API (no UI interaction needed) and injects the
// session cookie into the browser context.
// Uses the shared fixture so the token cache is unified across every spec
// — each Playwright worker does ONE login for the whole run, staying under
// the 10/15min login rate-limit.
const { test, expect, E2E_BASE, loginAs } = require('../fixtures');
// ── Tests ────────────────────────────────────────────────────────────
test.describe('Auth-gated pages — main tabs', () => {
test.beforeEach(async ({ context, request }) => {
await loginAs(context, request);
});
test('Landing page shows tab navigation after login', async ({ page }) => {
await page.goto(E2E_BASE + '/');
await expect(page.locator('button.tab-btn').first()).toBeVisible({ timeout: 15000 });
});
// Each auth-gated tab test: activate the tab, assert its container becomes
// visible + contains the expected anchor string. We use getTabPanel helpers
// because components load lazily from /components/<tab>.html.
const tabs = [
{ name: 'encounter', anchor: /New Encounter|encounter|SOAP/i },
{ name: 'wellvisit', anchor: /Well Visit|well visit/i },
{ name: 'chart', anchor: /Chart|visits|patients/i },
{ name: 'vaxschedule', anchor: /Vaccine|schedule|dose/i },
{ name: 'catchup', anchor: /Catch-up|catch up|schedule/i },
{ name: 'dictation', anchor: /Dictation|record|transcrib/i },
{ name: 'settings', anchor: /Setting|profile|preferences|account/i },
{ name: 'calculators', anchor: /Pediatric Calculator|BP Percentile|BMI/i },
{ name: 'faq', anchor: /FAQ|question|answer/i },
];
for (const { name, anchor } of tabs) {
test(`${name} tab loads content`, async ({ page, viewport }) => {
await page.goto(E2E_BASE + '/');
// On mobile the sidebar is hidden behind a hamburger. Open it so the
// tab buttons become interactable.
if (viewport && viewport.width <= 768) {
await page.click('#btn-menu-toggle').catch(() => {});
}
await page.waitForSelector('button.tab-btn', { timeout: 15000 });
const tabBtn = page.locator(`button.tab-btn[data-tab="${name}"]`);
const isHidden = await tabBtn.evaluate((el) => el.classList.contains('hidden')).catch(() => true);
test.skip(isHidden, `Tab "${name}" is hidden for this user role`);
await tabBtn.click();
// Wait for lazy component load to complete
await page.waitForFunction(
(t) => {
const el = document.getElementById(t + '-tab');
return el && el.classList.contains('active') && el.innerHTML.trim().length > 100;
},
name,
{ timeout: 15000 }
);
await expect(page.locator(`#${name}-tab`)).toContainText(anchor);
});
}
});