diff --git a/apps/web/e2e/README.md b/apps/web/e2e/README.md index e28ec5f55..63b17e098 100644 --- a/apps/web/e2e/README.md +++ b/apps/web/e2e/README.md @@ -36,7 +36,7 @@ In CI (cd.yml), the smoke job runs after deploy when `STAGING_URL` (secret or va ## Prérequis - **Frontend** : servi (ex. `npm run dev`) sur l'URL configurée dans `TEST_CONFIG.FRONTEND_URL` (défaut : http://localhost:5173). -- **Backend API** : disponible pour auth, search, playlists, upload, marketplace (défaut : http://localhost:8080/api/v1). +- **Backend API** : **obligatoire** pour auth, search, playlists, upload, marketplace (défaut : http://localhost:8080/api/v1). Les tests auth échouent si le backend n'est pas démarré. - **Chat server** (optionnel) : pour les tests Chat complets (envoi de message). Sans chat server, les tests Chat font du smoke (load UI, état déconnecté). - **Compte de test** : voir `e2e/utils/test-helpers.ts` : `TEST_USERS.default` (ou `TEST_EMAIL`, `TEST_PASSWORD`). diff --git a/apps/web/e2e/tests/auth.spec.ts b/apps/web/e2e/tests/auth.spec.ts index 578785a79..ef911da67 100644 --- a/apps/web/e2e/tests/auth.spec.ts +++ b/apps/web/e2e/tests/auth.spec.ts @@ -39,8 +39,6 @@ test.describe('Authentication Flow', () => { * TEST 1: Login avec credentials valides */ test('should login successfully with valid credentials', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Login with valid credentials'); - await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`); await page.waitForLoadState('domcontentloaded'); @@ -71,9 +69,8 @@ test.describe('Authentication Flow', () => { timeout: 10000, }); - // CRITIQUE: Attendre que Zustand écrive dans localStorage (peut être asynchrone) - console.log('⏳ [AUTH TEST] Waiting for Zustand to persist auth-storage...'); - await page.waitForTimeout(1000); // Délai pour laisser Zustand écrire + // Wait for Zustand to persist auth-storage (async) + await page.waitForTimeout(1000); // Vérifier l'état d'authentification (accepte les tokens en mémoire) const token = await getAuthToken(page); @@ -94,19 +91,12 @@ test.describe('Authentication Flow', () => { }); expect(isAuthenticated).toBe(true); - if (token === 'memory-token') { - console.log('✅ [AUTH TEST] Login successful (token in memory)'); - } else { - console.log('✅ [AUTH TEST] Login successful (token in storage)'); - } }); /** * TEST 2: Login avec credentials invalides */ test('should show error with invalid credentials', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Login with invalid credentials'); - await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`); await page.waitForLoadState('domcontentloaded'); @@ -124,8 +114,6 @@ test.describe('Authentication Flow', () => { // Vérifier que l'utilisateur reste sur /login await expect(page).toHaveURL(/\/login/); - - console.log('✅ [AUTH TEST] Error shown for invalid credentials'); }); /** @@ -162,15 +150,11 @@ test.describe('Authentication Flow', () => { * TEST 3: Registration (Inscription) */ test('should register a new user successfully', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: User registration'); - await page.goto(`${TEST_CONFIG.FRONTEND_URL}/register`); await page.waitForLoadState('domcontentloaded'); // Attendre que la page soit complètement chargée - await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => { - console.warn('⚠️ [AUTH TEST] Timeout on networkidle, continuing...'); - }); + await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {}); // Générer un email unique pour éviter les conflits const uniqueEmail = `test-${Date.now()}@example.com`; @@ -220,9 +204,8 @@ test.describe('Authentication Flow', () => { await expect(page.locator('nav[role="navigation"], aside[role="navigation"]')).toBeVisible({ timeout: 10000, }); - console.log('✅ [AUTH TEST] Registration successful with auto-login'); } else { - console.log('✅ [AUTH TEST] Registration successful, redirected to login'); + // Redirected to login after registration } } else { // No navigation - check if auth state was updated @@ -240,14 +223,12 @@ test.describe('Authentication Flow', () => { }); if (isAuthenticated) { - console.log('✅ [AUTH TEST] Registration successful (authenticated, no navigation)'); expect(isAuthenticated).toBe(true); } else { // Check if we at least left the register page const currentUrl = page.url(); const stillOnRegister = currentUrl.includes('/register'); if (!stillOnRegister) { - console.log('✅ [AUTH TEST] Registration completed (left register page)'); expect(stillOnRegister).toBe(false); } else { // Still on register, check for success message @@ -256,7 +237,6 @@ test.describe('Authentication Flow', () => { .isVisible({ timeout: 3000 }) .catch(() => false); expect(successMessage).toBe(true); - console.log('✅ [AUTH TEST] Registration successful (success message shown)'); } } } @@ -266,15 +246,11 @@ test.describe('Authentication Flow', () => { * TEST 4: Registration avec email déjà utilisé */ test('should show error when registering with existing email', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Registration with existing email'); - await page.goto(`${TEST_CONFIG.FRONTEND_URL}/register`); await page.waitForLoadState('domcontentloaded'); // Attendre que la page soit complètement chargée - await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => { - console.warn('⚠️ [AUTH TEST] Timeout on networkidle, continuing...'); - }); + await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {}); // Utiliser un email qui existe déjà (celui du test user) const password = 'Str0ng!P@ssw0rd2024'; // 12+ caractères requis, fort @@ -309,18 +285,9 @@ test.describe('Authentication Flow', () => { if (isErrorVisible) { const errorText = await errorMessage.textContent(); - // Backend peut retourner différents messages selon l'implémentation: - // - "email already exists" (idéal) - // - "failed to create user" (erreur générique mais valide) - // - "validation failed" (si l'email existe) - // - Generic 500 error message (if backend panics) expect(errorText?.toLowerCase()).toMatch(/(exist|already|déjà|utilisé|taken|failed|erreur|error)/); - console.log(`✅ [AUTH TEST] Error shown for existing email: "${errorText}"`); } else { - console.warn('⚠️ [AUTH TEST] No error message displayed, checking URL'); - // Si pas de message d'erreur, vérifier au moins qu'on reste sur /register await expect(page).toHaveURL(/\/register/); - console.log('✅ [AUTH TEST] User stayed on register page (expected behavior)'); } }); @@ -328,8 +295,6 @@ test.describe('Authentication Flow', () => { * TEST 5: Logout */ test('should logout successfully', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Logout'); - // D'abord se connecter await loginAsUser(page); @@ -338,15 +303,8 @@ test.describe('Authentication Flow', () => { timeout: 10000, }); - // 🔍 CRITIQUE: Vérifier que le token est présent AVANT logout - console.log('🔍 [AUTH TEST] Checking token presence before logout...'); const tokenBeforeLogout = await getAuthToken(page); - if (!tokenBeforeLogout) { - console.error('❌ [AUTH TEST] NO TOKEN FOUND after login! Logout will fail with 401.'); - console.error('❌ [AUTH TEST] This means loginAsUser did NOT properly authenticate.'); - } expect(tokenBeforeLogout).toBeTruthy(); - console.log(`✅ [AUTH TEST] Token present before logout: ${tokenBeforeLogout?.substring(0, 30)}...`); // Trouver le bouton de logout (peut être dans un menu utilisateur) // Chercher plusieurs variantes @@ -381,9 +339,7 @@ test.describe('Authentication Flow', () => { // 🔴 CRITIQUE: Attendre que la page soit complètement chargée avant logout // Cela évite les erreurs 400 si le header Authorization n'est pas encore prêt - await page.waitForLoadState('networkidle', { timeout: 15000 }).catch(() => { - console.warn('⚠️ [AUTH TEST] Timeout on networkidle before logout, continuing...'); - }); + await page.waitForLoadState('networkidle', { timeout: 15000 }).catch(() => {}); // Attendre un peu plus pour que Axios/API client soit complètement initialisé await page.waitForTimeout(1000); @@ -397,19 +353,14 @@ test.describe('Authentication Flow', () => { // Vérifier que l'utilisateur est redirigé vers /login await expect(page).toHaveURL(/\/login/); - // Vérifier que le token est supprimé const token = await getAuthToken(page); expect(token).toBeNull(); - - console.log('✅ [AUTH TEST] Logout successful'); }); /** * TEST 6: Route Guard - Redirection vers /login si non authentifié */ test('should redirect to login when accessing protected route without auth', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Route guard test'); - // S'assurer qu'il n'y a pas de token dans le localStorage await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`); await page.evaluate(() => localStorage.clear()); @@ -420,19 +371,14 @@ test.describe('Authentication Flow', () => { // Attendre la redirection vers /login await page.waitForURL(/\/login/, { timeout: 10000 }); - // Vérifier que l'utilisateur est bien redirigé await expect(page).toHaveURL(/\/login/); - - console.log('✅ [AUTH TEST] Route guard working correctly'); }); /** * TEST 7: Persistance de l'authentification après refresh */ test('should persist authentication after page refresh', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Auth persistence test'); - - // 🔴 FIX: Attendre un peu avant de se connecter pour éviter le rate limiting (429) + // Wait before login to avoid rate limiting (429) // Les tests précédents ont pu consommer le quota de login await page.waitForTimeout(10000); @@ -453,7 +399,6 @@ test.describe('Authentication Flow', () => { return false; }); expect(beforeRefresh).toBe(true); - console.log('✅ [AUTH TEST] Authenticated before refresh'); // Refresh page await page.reload({ waitUntil: 'domcontentloaded' }); @@ -476,19 +421,14 @@ test.describe('Authentication Flow', () => { // Check if token exists in localStorage (using helper) const token = await getAuthToken(page); - // Verify persistence expect(afterRefresh).toBe(true); expect(token).toBeTruthy(); - - console.log('✅ [AUTH TEST] Correctly persisted authentication after refresh'); }); /** * TEST 8: Validation du formulaire de login */ test('should validate login form fields', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Login form validation'); - await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`); await page.waitForLoadState('domcontentloaded'); @@ -530,22 +470,12 @@ test.describe('Authentication Flow', () => { // 2. We stayed on the login page (form blocked from submitting) const validationWorking = emailError || passwordError || stayedOnLoginPage; expect(validationWorking).toBeTruthy(); - - if (emailError) { - console.log('✅ [AUTH TEST] Email validation error shown'); - } else if (passwordError) { - console.log('✅ [AUTH TEST] Password validation error shown'); - } else if (stayedOnLoginPage) { - console.log('✅ [AUTH TEST] Form validation prevented submission (stayed on login page)'); - } }); /** * TEST 9: Validation du formulaire d'inscription (mots de passe différents) */ test('should show error when passwords do not match during registration', async ({ page }) => { - console.log('🧪 [AUTH TEST] Running: Password mismatch validation'); - await page.goto(`${TEST_CONFIG.FRONTEND_URL}/register`); await page.waitForLoadState('domcontentloaded'); @@ -567,9 +497,7 @@ test.describe('Authentication Flow', () => { // Soumettre le formulaire (ou attendre que la validation se déclenche) // Note: React Hook Form peut bloquer la soumission si validation échoue - await forceSubmitForm(page, 'form').catch(() => { - console.log('⚠️ Form submission might be blocked by validation'); - }); + await forceSubmitForm(page, 'form').catch(() => {}); // Attendre le message d'erreur (validation côté client Zod/React Hook Form) // Le message peut apparaître sans soumission si validation inline @@ -591,43 +519,20 @@ test.describe('Authentication Flow', () => { .catch(() => false); expect(errorByText).toBeTruthy(); - console.log('✅ [AUTH TEST] Password mismatch error shown (found by text)'); } else { expect(errorVisible).toBeTruthy(); - console.log('✅ [AUTH TEST] Password mismatch error shown (found by CSS)'); } }); - /** - * FINAL VERIFICATIONS - */ test.afterEach(async ({ }, testInfo) => { - console.log('\n📊 [AUTH TEST] === Final Verifications ==='); - - // Afficher les erreurs console si présentes - if (consoleErrors.length > 0) { - console.log(`🔴 [AUTH TEST] Console errors (${consoleErrors.length}):`); - consoleErrors.forEach((error) => { - console.log(` - ${error}`); - }); - - // Ne pas faire échouer les tests pour des erreurs console mineures - // Mais les logger pour investigation - if (testInfo.status === 'passed') { - console.warn('⚠️ [AUTH TEST] Test passed but had console errors'); - } - } else { - console.log('✅ [AUTH TEST] No console errors'); + if (consoleErrors.length > 0 && testInfo.status === 'passed') { + testInfo.annotations.push({ type: 'console-errors', description: consoleErrors.join('; ') }); } - - // Afficher les erreurs réseau si présentes - if (networkErrors.length > 0) { - console.log(`🔴 [AUTH TEST] Network errors (${networkErrors.length}):`); - networkErrors.forEach((error) => { - console.log(` - ${error.method} ${error.url}: ${error.status}`); + if (networkErrors.length > 0 && testInfo.status === 'passed') { + testInfo.annotations.push({ + type: 'network-errors', + description: networkErrors.map((e) => `${e.method} ${e.url}: ${e.status}`).join('; '), }); - } else { - console.log('✅ [AUTH TEST] No network errors'); } }); });