Files
Focolari-Voting-System/frontend/e2e/app.spec.ts

399 lines
14 KiB
TypeScript

/**
* 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('**/api/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);
});
});