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
66 lines
3.1 KiB
JavaScript
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);
|
|
});
|
|
}
|
|
});
|