import { test, expect, Page } from '@playwright/test'; const BASE_URL = process.env.VITE_API_URL || 'http://localhost'; const API_URL = process.env.VITE_API_URL || 'http://localhost:8080/api/v1'; interface TestResult { test: string; status: 'pass' | 'fail' | 'skip'; error?: string; details?: any; } const results: TestResult[] = []; // Helper pour capturer les erreurs console async function captureConsoleErrors(page: Page): Promise { const errors: string[] = []; page.on('console', msg => { if (msg.type() === 'error') { errors.push(msg.text()); } }); return errors; } // Helper pour capturer les erreurs réseau async function captureNetworkErrors(page: Page): Promise { const networkErrors: any[] = []; page.on('response', response => { if (response.status() >= 400) { networkErrors.push({ url: response.url(), status: response.status(), statusText: response.statusText(), }); } }); return networkErrors; } test.describe('QA E2E Audit - Veza Frontend', () => { let page: Page; let consoleErrors: string[] = []; let networkErrors: any[] = []; const testUser = { email: `test.veza.qa+${Date.now()}@example.com`, password: 'Test1234!@#', username: `qa_test_user_${Date.now()}`, }; test.beforeEach(async ({ page: testPage }) => { page = testPage; consoleErrors = []; networkErrors = []; // Capturer les erreurs page.on('console', msg => { if (msg.type() === 'error') { consoleErrors.push(msg.text()); } }); page.on('response', response => { if (response.status() >= 400) { networkErrors.push({ url: response.url(), status: response.status(), statusText: response.statusText(), }); } }); }); test('1. Health Check - Backend API', async () => { const response = await page.request.get(`${API_URL}/health`); expect(response.status()).toBe(200); results.push({ test: 'Backend API Health', status: response.status() === 200 ? 'pass' : 'fail', details: await response.json(), }); }); test('2.1. Register - Test complet', async () => { await page.goto(`${BASE_URL}/register`); await page.waitForLoadState('networkidle'); // Test 1: Inscription avec données valides await page.fill('input[name="email"]', testUser.email); await page.fill('input[name="username"]', testUser.username); await page.fill('input[name="password"]', testUser.password); await page.fill('input[name="confirmPassword"]', testUser.password); // Accepter les termes si checkbox existe const termsCheckbox = page.locator('input[type="checkbox"]').first(); if (await termsCheckbox.isVisible()) { await termsCheckbox.check(); } // Capturer la réponse avant soumission const responsePromise = page.waitForResponse( response => response.url().includes('/auth/register') && response.request().method() === 'POST' ); await page.click('button[type="submit"]'); try { const response = await responsePromise; const status = response.status(); const body = await response.json().catch(() => ({})); results.push({ test: 'Register - Valid data', status: status === 200 || status === 201 ? 'pass' : 'fail', error: status >= 400 ? `Status ${status}: ${JSON.stringify(body)}` : undefined, details: { status, body, consoleErrors: [...consoleErrors], networkErrors: [...networkErrors] }, }); if (status === 200 || status === 201) { // Vérifier redirection vers dashboard await page.waitForURL('**/dashboard', { timeout: 5000 }).catch(() => {}); } } catch (error: any) { results.push({ test: 'Register - Valid data', status: 'fail', error: error.message, details: { consoleErrors: [...consoleErrors], networkErrors: [...networkErrors] }, }); } }); test('2.2. Register - Validation errors', async () => { await page.goto(`${BASE_URL}/register`); await page.waitForLoadState('networkidle'); // Test email invalide await page.fill('input[name="email"]', 'invalid-email'); await page.fill('input[name="password"]', 'short'); await page.click('button[type="submit"]'); const emailError = await page.locator('text=/email|Email/i').first().isVisible().catch(() => false); results.push({ test: 'Register - Email validation', status: emailError ? 'pass' : 'fail', details: { emailError }, }); // Test mot de passe court await page.fill('input[name="email"]', 'test@example.com'); await page.fill('input[name="password"]', 'short'); await page.click('button[type="submit"]'); const passwordError = await page.locator('text=/password|mot de passe/i').first().isVisible().catch(() => false); results.push({ test: 'Register - Password validation', status: passwordError ? 'pass' : 'fail', details: { passwordError }, }); }); test('2.3. Login - Test complet', async () => { await page.goto(`${BASE_URL}/login`); await page.waitForLoadState('networkidle'); // Test login avec mauvais mot de passe await page.fill('input[name="email"]', testUser.email); await page.fill('input[name="password"]', 'wrongpassword'); const responsePromise = page.waitForResponse( response => response.url().includes('/auth/login') && response.request().method() === 'POST' ); await page.click('button[type="submit"]'); try { const response = await responsePromise; const status = response.status(); results.push({ test: 'Login - Wrong password', status: status === 401 ? 'pass' : 'fail', error: status !== 401 ? `Expected 401, got ${status}` : undefined, details: { status }, }); } catch (error: any) { results.push({ test: 'Login - Wrong password', status: 'fail', error: error.message, }); } // Test login valide await page.fill('input[name="password"]', testUser.password); const loginResponsePromise = page.waitForResponse( response => response.url().includes('/auth/login') && response.request().method() === 'POST' ); await page.click('button[type="submit"]'); try { const response = await loginResponsePromise; const status = response.status(); const body = await response.json().catch(() => ({})); results.push({ test: 'Login - Valid credentials', status: status === 200 ? 'pass' : 'fail', error: status !== 200 ? `Status ${status}: ${JSON.stringify(body)}` : undefined, details: { status, body }, }); if (status === 200) { await page.waitForURL('**/dashboard', { timeout: 5000 }).catch(() => {}); } } catch (error: any) { results.push({ test: 'Login - Valid credentials', status: 'fail', error: error.message, }); } }); test('3. Navigation - Toutes les pages', async () => { // Se connecter d'abord await page.goto(`${BASE_URL}/login`); await page.fill('input[name="email"]', testUser.email); await page.fill('input[name="password"]', testUser.password); await page.click('button[type="submit"]'); await page.waitForURL('**/dashboard', { timeout: 10000 }).catch(() => {}); const pages = [ { name: 'Dashboard', path: '/dashboard' }, { name: 'Chat', path: '/chat' }, { name: 'Library', path: '/library' }, { name: 'Profile', path: '/profile' }, { name: 'Settings', path: '/settings' }, { name: 'Marketplace', path: '/marketplace' }, ]; for (const pageInfo of pages) { await page.goto(`${BASE_URL}${pageInfo.path}`); await page.waitForLoadState('networkidle'); const title = await page.title(); const url = page.url(); const hasErrors = consoleErrors.length > 0 || networkErrors.length > 0; results.push({ test: `Navigation - ${pageInfo.name}`, status: url.includes(pageInfo.path) && !hasErrors ? 'pass' : 'fail', error: hasErrors ? `Console errors: ${consoleErrors.length}, Network errors: ${networkErrors.length}` : undefined, details: { url, title, consoleErrors: [...consoleErrors], networkErrors: [...networkErrors] }, }); // Reset errors pour la prochaine page consoleErrors = []; networkErrors = []; } }); test('4. Buttons and Actions - Dashboard', async () => { await page.goto(`${BASE_URL}/dashboard`); await page.waitForLoadState('networkidle'); // Tester tous les boutons visibles const buttons = await page.locator('button').all(); const buttonTests: any[] = []; for (const button of buttons.slice(0, 10)) { // Limiter à 10 pour éviter trop de tests const text = await button.textContent().catch(() => ''); const isVisible = await button.isVisible().catch(() => false); const isEnabled = await button.isEnabled().catch(() => false); buttonTests.push({ text, isVisible, isEnabled }); } results.push({ test: 'Dashboard - Buttons', status: 'pass', details: { buttons: buttonTests }, }); }); test('5. Logout', async () => { await page.goto(`${BASE_URL}/dashboard`); await page.waitForLoadState('networkidle'); // Ouvrir le menu utilisateur const userMenuButton = page.locator('button[aria-label*="user" i], button:has-text("User")').first(); if (await userMenuButton.isVisible()) { await userMenuButton.click(); await page.waitForTimeout(500); // Cliquer sur logout const logoutButton = page.locator('text=/logout|déconnexion/i').first(); if (await logoutButton.isVisible()) { await logoutButton.click(); await page.waitForURL('**/login', { timeout: 5000 }).catch(() => {}); results.push({ test: 'Logout', status: page.url().includes('/login') ? 'pass' : 'fail', details: { finalUrl: page.url() }, }); } } }); test.afterAll(async () => { // Générer le rapport console.log('\n=== QA AUDIT RESULTS ===\n'); results.forEach(result => { const icon = result.status === 'pass' ? '✅' : result.status === 'fail' ? '❌' : '⏭️'; console.log(`${icon} ${result.test}: ${result.status}`); if (result.error) { console.log(` Error: ${result.error}`); } }); }); });