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
99 lines
5 KiB
JavaScript
99 lines
5 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.
|
|
//
|
|
// 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('#login-code')).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 to the choice, and choosing a password reveals it', 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');
|
|
|
|
await expect(page.locator('#login-choice')).toBeVisible();
|
|
// 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 page.click('#btn-login-use-password');
|
|
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. The seed
|
|
// sets registration_enabled true and invite_only true, which is what
|
|
// production runs: registration is open, but a code is required — so the
|
|
// link shows and the invite field is required.
|
|
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')).toBeVisible();
|
|
await expect(page.locator('#reg-invite')).toHaveJSProperty('required', true);
|
|
});
|
|
|
|
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');
|
|
});
|
|
});
|