// ============================================================ // 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. // // Signing in is a stepped flow, not one form: email first, then a choice // between a password and an emailed code. The password field exists in the // DOM from the start but stays hidden until that choice is made, so asserting // it visible on the landing screen tests a page that no longer exists. test('landing asks for the email only, and hides the rest of the flow', 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('#btn-login-continue')).toBeVisible(); // Later steps are present but not yet offered. await expect(page.locator('#login-password')).toBeHidden(); await expect(page.locator('#btn-local-login')).toBeHidden(); // main app body must be hidden while unauthenticated await expect(page.locator('#main-app')).toBeHidden(); }); test('an email leads straight to the password', async ({ page }) => { await page.goto(E2E_BASE + '/'); await page.waitForSelector('#auth-screen', { timeout: 10000 }); await page.fill('#login-email', 'someone@ped-ai.test'); await page.click('#btn-login-continue'); // The address is fixed once the flow has moved past it; "use a different // email" is how you go back, and it only appears after the first step. await expect(page.locator('#login-email')).toHaveJSProperty('readOnly', true); await expect(page.locator('#login-change-email')).toBeVisible(); await expect(page.locator('#login-password')).toBeVisible(); await expect(page.locator('#btn-local-login')).toBeVisible(); }); test('the register link follows the registration setting', async ({ page }) => { // Hidden by default and shown only when registration is enabled, which the // seed turns on. No invitation field: invitations are the SSO's. await page.goto(E2E_BASE + '/'); await page.waitForSelector('#auth-screen', { timeout: 10000 }); await expect(page.locator('#show-register')).toBeVisible(); await expect(page.locator('#register-form')).toHaveCount(1); await page.click('#show-register'); await expect(page.locator('#reg-invite')).toHaveCount(0); }); 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'); }); });