import { test, expect } from '@playwright/test'; import { getTestToken } from './test-utils'; test.describe('Account Activation Flow', () => { test.describe('Token Validation', () => { test('displays error for invalid token', async ({ page }) => { await page.goto('/activate/invalid-token-uuid-format'); // Wait for the error state await expect(page.getByRole('heading', { name: /lien invalide/i })).toBeVisible(); await expect(page.getByText(/contacter votre établissement/i)).toBeVisible(); }); test('displays error for non-existent token', async ({ page }) => { // Use a valid UUID format but non-existent token await page.goto('/activate/00000000-0000-0000-0000-000000000000'); // Shows error because token doesn't exist const heading = page.getByRole('heading', { name: /lien invalide/i }); await expect(heading).toBeVisible(); }); }); test.describe('Password Form', () => { test('validates password requirements in real-time', async ({ page }) => { const token = getTestToken(); await page.goto(`/activate/${token}`); // Wait for form to be visible (token must be valid) const form = page.locator('form'); await expect(form).toBeVisible({ timeout: 5000 }); const passwordInput = page.locator('#password'); // Test minimum length requirement - should NOT be valid yet await passwordInput.fill('Abc1'); const minLengthItem = page.locator('.password-requirements li').filter({ hasText: /8 caractères/ }); await expect(minLengthItem).not.toHaveClass(/valid/); // Test uppercase requirement - missing await passwordInput.fill('abcd1234'); const uppercaseItem = page.locator('.password-requirements li').filter({ hasText: /majuscule/ }); await expect(uppercaseItem).not.toHaveClass(/valid/); // Test digit requirement - missing await passwordInput.fill('Abcdefgh'); const digitItem = page.locator('.password-requirements li').filter({ hasText: /chiffre/ }); await expect(digitItem).not.toHaveClass(/valid/); // Valid password should show all checkmarks await passwordInput.fill('Abcdefgh1'); const validItems = page.locator('.password-requirements li.valid'); await expect(validItems).toHaveCount(3); }); test('requires password confirmation to match', async ({ page }) => { const token = getTestToken(); await page.goto(`/activate/${token}`); const form = page.locator('form'); await expect(form).toBeVisible({ timeout: 5000 }); const passwordInput = page.locator('#password'); const confirmInput = page.locator('#passwordConfirmation'); await passwordInput.fill('SecurePass123'); await confirmInput.fill('DifferentPass123'); await expect(page.getByText(/mots de passe ne correspondent pas/i)).toBeVisible(); // Fix confirmation await confirmInput.fill('SecurePass123'); await expect(page.getByText(/mots de passe ne correspondent pas/i)).not.toBeVisible(); }); test('submit button is disabled until form is valid', async ({ page }) => { const token = getTestToken(); await page.goto(`/activate/${token}`); const form = page.locator('form'); await expect(form).toBeVisible({ timeout: 5000 }); const submitButton = page.getByRole('button', { name: /activer mon compte/i }); // Initially disabled await expect(submitButton).toBeDisabled(); // Fill valid password await page.locator('#password').fill('SecurePass123'); await page.locator('#passwordConfirmation').fill('SecurePass123'); // Should now be enabled await expect(submitButton).toBeEnabled(); }); }); test.describe('Establishment Info Display', () => { test('shows establishment name and role when token is valid', async ({ page }) => { const token = getTestToken(); await page.goto(`/activate/${token}`); const form = page.locator('form'); await expect(form).toBeVisible({ timeout: 5000 }); // School info should be visible await expect(page.locator('.school-info')).toBeVisible(); await expect(page.locator('.school-name')).toBeVisible(); await expect(page.locator('.account-type')).toBeVisible(); }); }); test.describe('Password Visibility Toggle', () => { test('toggles password visibility', async ({ page }) => { const token = getTestToken(); await page.goto(`/activate/${token}`); const form = page.locator('form'); await expect(form).toBeVisible({ timeout: 5000 }); const passwordInput = page.locator('#password'); const toggleButton = page.locator('.toggle-password'); // Initially password type await expect(passwordInput).toHaveAttribute('type', 'password'); // Click toggle await toggleButton.click(); await expect(passwordInput).toHaveAttribute('type', 'text'); // Click again to hide await toggleButton.click(); await expect(passwordInput).toHaveAttribute('type', 'password'); }); }); test.describe('Full Activation Flow', () => { test('activates account and redirects to login', async ({ page }) => { const token = getTestToken(); await page.goto(`/activate/${token}`); const form = page.locator('form'); await expect(form).toBeVisible({ timeout: 5000 }); // Fill valid password await page.locator('#password').fill('SecurePass123'); await page.locator('#passwordConfirmation').fill('SecurePass123'); // Submit await page.getByRole('button', { name: /activer mon compte/i }).click(); // Should redirect to login with success message await expect(page).toHaveURL(/\/login\?activated=true/); await expect(page.getByText(/compte a été activé avec succès/i)).toBeVisible(); }); }); }); test.describe('Login Page After Activation', () => { test('shows success message when redirected after activation', async ({ page }) => { await page.goto('/login?activated=true'); await expect(page.getByText(/compte a été activé avec succès/i)).toBeVisible(); await expect(page.getByRole('heading', { name: /connexion/i })).toBeVisible(); }); test('does not show success message without query param', async ({ page }) => { await page.goto('/login'); await expect(page.getByText(/compte a été activé avec succès/i)).not.toBeVisible(); await expect(page.getByRole('heading', { name: /connexion/i })).toBeVisible(); }); }); test.describe('Parental Consent Flow (Minor User)', () => { // These tests would require seeded data for a minor user test.skip('shows consent required message for minor without consent', async () => { // Would navigate to activation page for a minor user token // and verify the consent required message is displayed }); test.skip('allows activation after parental consent is given', async () => { // Would verify the full flow: // 1. Minor receives activation link // 2. Parent gives consent // 3. Minor can then activate their account }); });