/** * Focolari Voting System - E2E Tests * * Test End-to-End che verificano i flussi completi con browser reale. * * NOTA: Simuliamo il lettore RFID usando il pattern US: ;[codice]? * * Badge di test disponibili nel DB (users_test.json): * - 0008988288: Marco Bianchi (Convocato, ammesso) * - 0007399575: Laura Rossi (Invitato, ammessa) * - 0000514162: Giuseppe Verdi (Tecnico, NON ammesso) * - 0006478281: NON nel DB (per test "non trovato") */ import { test, expect, Page } from '@playwright/test'; // Pausa finale per vedere il risultato del test const PAUSE_FINALE_MS = 1000; // Utility per simulare scansione RFID (pattern US: ;codice?) async function scanBadge(page: Page, badgeCode: string) { console.log(`[E2E] Scansione badge: ${badgeCode}`); // Simula la sequenza: ; + codice + ? const sequence = `;${badgeCode}?`; await page.keyboard.type(sequence, { delay: 50 }); // Pausa per permettere al frontend di processare await page.waitForTimeout(500); } // Utility per aspettare che il caricamento finisca async function waitForAppReady(page: Page) { await expect(page.getByText(/caricamento/i)).not.toBeVisible({ timeout: 15000 }); } // Utility per fare login completo come validatore async function loginAsValidator(page: Page, validatorBadge: string = '0008988288') { await page.goto('/'); await waitForAppReady(page); // Passo 1: Passa il badge console.log('[E2E] Passo badge validatore...'); await scanBadge(page, validatorBadge); // Passo 2: Attendi campo password await expect(page.getByPlaceholder(/password/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] Campo password visibile'); // Passo 3: Inserisci password await page.getByPlaceholder(/password/i).fill('focolari'); await page.waitForTimeout(500); // Passo 4: Click conferma await page.getByRole('button', { name: /conferma/i }).click(); console.log('[E2E] Password inviata'); // Passo 5: Attendi varco attivo (usa heading specifico) await expect(page.getByRole('heading', { name: 'Varco Attivo' })).toBeVisible({ timeout: 10000 }); console.log('[E2E] Login completato - Varco attivo'); await page.waitForTimeout(1000); } // ============================================ // TEST: Flusso Validatore // ============================================ test.describe('Flusso Validatore', () => { test('01 - mostra schermata attesa badge validatore', async ({ page }) => { await page.goto('/'); await waitForAppReady(page); await expect(page.getByText(/passa.*badge/i)).toBeVisible(); console.log('[E2E] ✓ Schermata attesa badge visibile'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('02 - scansione badge mostra campo password', async ({ page }) => { await page.goto('/'); await waitForAppReady(page); // Scansiona un badge await scanBadge(page, '0008988288'); // Dovrebbe mostrare il campo password await expect(page.getByPlaceholder(/password/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] ✓ Campo password visibile dopo scansione badge'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('03 - login completo con password corretta', async ({ page }) => { await loginAsValidator(page, '0008988288'); // Verifica di essere nel varco attivo (usa heading specifico) await expect(page.getByRole('heading', { name: 'Varco Attivo' })).toBeVisible(); console.log('[E2E] ✓ Login completato con successo'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('04 - password errata mostra errore', async ({ page }) => { await page.goto('/'); await waitForAppReady(page); // Scansiona badge await scanBadge(page, '0008988288'); await expect(page.getByPlaceholder(/password/i)).toBeVisible({ timeout: 5000 }); // Inserisci password sbagliata await page.getByPlaceholder(/password/i).fill('sbagliata'); await page.getByRole('button', { name: /conferma/i }).click(); // Dovrebbe mostrare errore await expect(page.getByText(/errata|non corretta|errore/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] ✓ Errore password mostrato'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('05 - pulsante annulla torna a attesa badge', async ({ page }) => { await page.goto('/'); await waitForAppReady(page); // Scansiona badge await scanBadge(page, '0008988288'); await expect(page.getByPlaceholder(/password/i)).toBeVisible({ timeout: 5000 }); // Click annulla await page.getByRole('button', { name: /annulla/i }).click(); // Torna all'attesa badge await expect(page.getByText(/passa.*badge/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] ✓ Annulla funziona correttamente'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); }); // ============================================ // TEST: Flusso Partecipante // ============================================ test.describe('Flusso Partecipante', () => { test('06 - badge ammesso mostra card verde', async ({ page }) => { // Login come validatore await loginAsValidator(page, '1111111111'); // Scansiona badge ammesso (Marco Bianchi) await scanBadge(page, '0008988288'); // Attende la card await expect(page.getByText(/Marco/i)).toBeVisible({ timeout: 5000 }); // Usa selettore specifico per il badge "AMMESSO" await expect(page.getByText('✓ AMMESSO')).toBeVisible(); console.log('[E2E] ✓ Card utente ammesso visualizzata'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('07 - badge NON ammesso mostra card rossa', async ({ page }) => { await loginAsValidator(page, '1111111111'); // Scansiona badge NON ammesso (Giuseppe Verdi) await scanBadge(page, '0000514162'); // Attende la card await expect(page.getByText(/Giuseppe/i)).toBeVisible({ timeout: 5000 }); // Usa selettore specifico per il badge "NON AMMESSO" await expect(page.getByText('✗ NON AMMESSO')).toBeVisible(); console.log('[E2E] ✓ Card utente NON ammesso visualizzata'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('08 - badge non trovato mostra errore', async ({ page }) => { await loginAsValidator(page, '1111111111'); // Scansiona badge inesistente await scanBadge(page, '0006478281'); // Dovrebbe mostrare errore "non trovato" await expect(page.getByText(/non trovato/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] ✓ Errore badge non trovato visualizzato'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('09 - badge diverso sostituisce utente corrente', async ({ page }) => { await loginAsValidator(page, '1111111111'); // Prima scansione (Marco - ammesso) await scanBadge(page, '0008988288'); await expect(page.getByText(/Marco/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] Marco visualizzato'); // Attendi che la card sia completamente caricata await page.waitForTimeout(3000); // Seconda scansione (Giuseppe - NON ammesso) // Usiamo Giuseppe perché sappiamo che esiste nel DB await scanBadge(page, '0000514162'); // Attendi che Giuseppe appaia (sostituisce Marco) await expect(page.getByText(/Giuseppe/i)).toBeVisible({ timeout: 10000 }); console.log('[E2E] ✓ Giuseppe ha sostituito Marco'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); }); // ============================================ // TEST: Conferma Ingresso // ============================================ test.describe('Conferma Ingresso', () => { test('10 - conferma utente ammesso mostra benvenuto', async ({ page }) => { // Login con un badge specifico come validatore await loginAsValidator(page, '1111111111'); // Scansiona utente ammesso await scanBadge(page, '0008988288'); await expect(page.getByText(/Marco/i)).toBeVisible({ timeout: 5000 }); await page.waitForTimeout(2000); // Ri-passa lo stesso badge del validatore per confermare await scanBadge(page, '1111111111'); // Dovrebbe mostrare modal di successo con carosello await expect(page.getByText(/benvenuto|welcome|bienvenue/i)).toBeVisible({ timeout: 8000 }); console.log('[E2E] ✓ Carosello benvenuto mostrato'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); }); // ============================================ // TEST: Debug Page // ============================================ test.describe('Debug Page', () => { test('11 - pagina debug accessibile', async ({ page }) => { await page.goto('/debug'); await expect(page.getByRole('heading', { name: 'Debug RFID' })).toBeVisible(); console.log('[E2E] ✓ Pagina debug accessibile'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); }); // ============================================ // TEST: Session Management // ============================================ test.describe('Session Management', () => { test('12 - logout cancella sessione', async ({ page }) => { await loginAsValidator(page, '0008988288'); // Logout await page.getByRole('button', { name: /esci/i }).click(); // Torna alla schermata iniziale await expect(page.getByText(/passa.*badge/i)).toBeVisible({ timeout: 5000 }); console.log('[E2E] ✓ Logout completato'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); test('13 - refresh mantiene sessione', async ({ page }) => { await loginAsValidator(page, '0008988288'); // Refresh await page.reload(); await waitForAppReady(page); // Dovrebbe essere ancora nel varco attivo (usa heading specifico) await expect(page.getByRole('heading', { name: 'Varco Attivo' })).toBeVisible({ timeout: 5000 }); console.log('[E2E] ✓ Sessione mantenuta dopo refresh'); // Pausa finale await page.waitForTimeout(PAUSE_FINALE_MS); }); }); // ============================================ // TEST: Sicurezza - Bypass Utente Non Ammesso // ============================================ test.describe('Sicurezza Backend', () => { /** * TEST CRITICO: Simulazione di un BUG/HACK nel frontend * * Questo test simula cosa succederebbe se un bug nel frontend * permettesse di inviare una richiesta entry-request per un * utente NON ammesso (Giuseppe Verdi). * * Il backend DEVE rispondere con success: false * Il frontend DEVE mostrare un errore, NON il benvenuto * * Per debuggare: esegui con ./dev.sh test:e2e:ui * e clicca su questo test per vederlo step-by-step */ test('14 - SICUREZZA: bypass utente non ammesso - backend blocca', async ({ page }) => { console.log('[E2E] === TEST SICUREZZA: Bypass utente non ammesso ==='); // Login come validatore await loginAsValidator(page, '1111111111'); console.log('[E2E] Login completato'); // Visualizza utente NON ammesso (Giuseppe Verdi) await scanBadge(page, '0000514162'); await expect(page.getByText(/Giuseppe/i)).toBeVisible({ timeout: 5000 }); await expect(page.getByText('✗ NON AMMESSO')).toBeVisible(); console.log('[E2E] Giuseppe Verdi (NON ammesso) visualizzato'); // Pausa per vedere la card await page.waitForTimeout(3000); // SIMULAZIONE BUG: Intercettiamo la chiamata e forziamo l'invio // In un frontend corretto, questa chiamata NON dovrebbe MAI partire // per un utente non ammesso. Ma simuliamo cosa succederebbe. let requestIntercepted = false; let backendResponse: { success: boolean; message: string } | null = null; await page.route('**/entry-request', async (route, request) => { requestIntercepted = true; console.log('[E2E] ⚠️ Richiesta entry-request INTERCETTATA'); console.log('[E2E] Body:', request.postData()); // Lasciamo passare la richiesta al backend REALE // per vedere cosa risponde const response = await route.fetch(); const json = await response.json(); backendResponse = json; console.log('[E2E] Risposta backend:', JSON.stringify(json)); // Continuiamo con la risposta reale del backend await route.fulfill({ response }); }); // Forziamo l'invio della richiesta passando il badge validatore // (normalmente il frontend NON dovrebbe permetterlo per utenti non ammessi) console.log('[E2E] Tentativo di forzare ingresso...'); await scanBadge(page, '1111111111'); // Aspettiamo un po' per vedere cosa succede await page.waitForTimeout(5000); // VERIFICA: Il carosello di benvenuto NON deve apparire const welcomeVisible = await page.getByText(/benvenuto|welcome/i).isVisible().catch(() => false); if (welcomeVisible) { console.log('[E2E] ❌ ERRORE CRITICO: Carosello benvenuto mostrato per utente NON ammesso!'); } else { console.log('[E2E] ✓ Carosello benvenuto NON mostrato (corretto)'); } // Log finale console.log('[E2E] === RISULTATO TEST SICUREZZA ==='); console.log('[E2E] Richiesta intercettata:', requestIntercepted); console.log('[E2E] Risposta backend:', backendResponse); console.log('[E2E] Benvenuto mostrato:', welcomeVisible); // Il test PASSA se: // 1. Il backend ha risposto con success: false, OPPURE // 2. Il frontend non ha mostrato il benvenuto expect(welcomeVisible).toBe(false); // Pausa finale lunga per debug visivo console.log('[E2E] Pausa per debug visivo...'); await page.waitForTimeout(PAUSE_FINALE_MS); }); });