Skip to content

Latest commit

 

History

History
376 lines (280 loc) · 24.3 KB

File metadata and controls

376 lines (280 loc) · 24.3 KB

Test

Panoramica

CineBase ha 639 test backend (xUnit) e ~160 test frontend (Playwright) per un totale di circa 800 test automatici. I test coprono tre livelli:

Livello Tecnologia Cosa testa Tempo esecuzione
Unit test backend xUnit + EF Core InMemory Logica di business pura <1 minuto
Integration test backend xUnit + SQLite in-memory + CustomWebApplicationFactory Pipeline ASP.NET completa, endpoint, DB, servizi fittizi ~60 secondi
Browser audit frontend Playwright (Chromium/Edge) Render frontend con API mockate via page.route() ~2 minuti
E2E smoke Docker Playwright (container) + stack reale Stack completo Docker con richieste HTTP reali ~3 minuti

Backend — Unit test (tests/backend/Unit/)

Testano la logica di business senza la pipeline ASP.NET, usando database EF Core InMemory (creato per-test con GUID univoco) o nessun database.

Finalità

Verificare il comportamento dei servizi di dominio in isolamento: CRUD, validazione input, configurazione SMTP.

Classi e file

File Classe Cosa testa DB
FilmServiceTests.cs FilmServiceTests CRUD film: creazione, lettura, modifica, cancellazione, ricerca per id, input non valido EF Core InMemory
RegistaServiceTests.cs RegistaServiceTests CRUD registi: creazione, lettura, modifica, cancellazione, input non valido, film per regista EF Core InMemory
CinemaServiceTests.cs CinemaServiceTests CRUD cinema: creazione, lettura, modifica, cancellazione EF Core InMemory
BigliettoServiceTests.cs BigliettoServiceTests Metodo ResolveValidationBaseUrl(): URL assoluto (passthrough), URL relativo (normalizzazione), frontend mancante (fallback localhost) Nessuno
SmtpDeliverySettingsTests.cs SmtpDeliverySettingsTests Caricamento configurazione SMTP da variabili d'ambiente: autenticazione vs no-auth, rilevamento Mailpit, default TLS. Include helper privato EnvironmentVariableScope per salvare/ripristinare env vars tra i test. Nessuno

Comandi

# Tutti i test backend (unit + integration)
dotnet test tests/backend/FilmAPI.Tests.csproj

# Solo unit test
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Unit"

Harnessing

  • Nessun server web: il DbContext è creato con UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()), garantendo isolamento completo tra test.
  • Parametrizer: i servizi vengono istanziati direttamente nei test passando il DbContext.
  • Assertion: FluentAssertions (Should().NotBeNull(), Should().BeEquivalentTo(), etc.).

Backend — Integration test (tests/backend/Integration/)

Testano l'intera pipeline ASP.NET Core con un database SQLite in-memory, servizi fittizi (Stripe, email, OAuth, TMDB), e autenticazione simulata. Sono il grosso della suite (30+ classi di test).

Finalità

Verificare che gli endpoint HTTP funzionino correttamente end-to-end: routing, autenticazione, autorizzazione, validazione input, logica di business, persistenza, risposte HTTP, header, cookie.

Architettura del factory

CustomWebApplicationFactory : WebApplicationFactory<FilmDbContext>, IAsyncLifetime

È il cuore di tutti i test di integrazione. Caratteristiche principali:

  • Database: SQLite in-memory (SqliteConnection con DataSource=:memory:, aperto in InitializeAsync e chiuso in DisposeAsync). Ogni factory ha la propria connessione indipendente.
  • Fakes (sostituiscono i servizi reali):
    • FakeStripePaymentGateway — simula l'intera API Stripe: payment intent, checkout session, refund, firma webhook.
    • FakeEmailService — cattura le email inviate (biglietti, cancellazione show). Supporta ForceFailure per testare scenari di errore.
    • FakeAccountEmailService — cattura le email di account (verifica, reset password, invito admin, cambio password, cancellazione account).
    • FakeExternalAuthProvider (Google e Microsoft) — simula il flusso OAuth: state, code exchange, info utente.
    • FakeTmdbImportService — restituisce risultati TMDB fittizi (Fight Club, Pulp Fiction, The Dark Knight).
  • Autenticazione simulata: TestAuthHandler legge header HTTP custom:
    • X-Test-Role — ruolo (Admin, PowerUser, CinemaStaff, User)
    • X-Test-UserId — ID utente
    • X-Test-Email — email
    • X-Test-Nome — nome
  • HttpClient factory:
    • CreateAdminClient(userId) — client autenticato come Admin
    • CreatePowerUserClient(userId) — PowerUser
    • CreateCinemaStaffClient(userId) — CinemaStaff
    • CreateUserClient(userId) — User
    • CreateAnonymousClient() — nessuna autenticazione
    • CreateAuthenticatedClient(role, userId, email, nome) — generico
  • API path canonical handler: CanonicalApiPathPrefixHandler (un DelegatingHandler) riscrive automaticamente i path canonici (es. /films/api/films) per 17 root path API.
  • Cookie container: CookieContainerHandler (un DelegatingHandler) persiste i cookie tra richieste consecutive (fondamentale per testare il flusso refresh token via cinebase_refresh).
  • Reset database: ResetDatabaseAsync(seed?) cancella e ricrea il DB, resetta tutti i fake, opzionalmente esegue una funzione di seed.
  • Configurazione: ConfigureAppConfiguration con AddInMemoryCollection per impostare limiti rate limiter altissimi (10000/1s), disabilitando di fatto il rate limiting nei test standard.
  • Classe non-sealed: permette ereditarietà per factory derivate come TightRateLimitWebApplicationFactory.

TightRateLimitWebApplicationFactory

Factory derivata in RateLimiterIntegrationTests.cs che sovrascrive i limiti del rate limiter in-memory:

config.AddInMemoryCollection(new Dictionary<string, string?>
{
    ["LOGIN_RATE_LIMIT_PERMITS"] = "6",
    ["LOGIN_RATE_LIMIT_WINDOW_SECONDS"] = "60",
    ["FORGOT_PASSWORD_RATE_LIMIT_PERMITS"] = "3",
    ["FORGOT_PASSWORD_RATE_LIMIT_WINDOW_SECONDS"] = "60",
});

Usa builder.Configuration (non Environment.SetEnvironmentVariable) per evitare interferenze con altri test in esecuzione parallela.

Elenco classi di test

# Classe Cosa testa
1 ApiIntegrationTests CRUD registi, film, cinema, upload cover media, paginazione, ricerca, validazione, payload array legacy
2 AuthIntegrationTests Registrazione, login, verifica email, rotazione refresh token, logout, cookie HTTP-only, guardie Origin/Referer, endpoint me
3 AuthLifecycleSmokeTests Rotazione refresh token, logout idempotente, cookie scaduti, prevenzione furto cookie, richieste senza Origin
4 ContainerBootstrapIntegrationTests Health endpoint /api/health/ready: 200 quando DB pronto, 503 quando bootstrap non completato
5 FilmIntegrationTests Ciclo di vita stato film (InCartellone, InArrivo, FuoriCartellone), promozione catalog lifecycle, TMDB ID duplicato, conteggio show
6 ShowIntegrationTests CRUD show, paginazione, filtro per data/cinema/film, rilevamento conflitti orari, occupazione sala, pianificazione batch, publish/unpublish, scope CinemaStaff, film in arrivo
7 CheckoutIntegrationTests Mappa posti, hold posti (creazione, estensione, rilascio, conflitto, concorrenza), creazione ordini con chiavi idempotenza, prezzi per categoria, immutabilità snapshot, guardie show non pubblicati/pubblicati
8 CheckoutHostedIntegrationTests Checkout Stripe hosted: creazione sessione, webhook completamento, riconciliazione, scadenza, pagamento misto (credito+carta), webhook duplicato (idempotenza), fallimento/cancellazione pagamento, auto-scadenza checkout
9 PagamentoCreditoIntegrationTests Flussi pagamento sincrono e misto (Carta, Credito, Misto), addebito credito/audit, ricarica admin, cancellazione ordine pendente, sicurezza replay webhook Stripe
10 TicketIntegrationTests Generazione PDF biglietti, invio email, differenziazione categorie posto nel PDF, controllo accesso download biglietti
11 AdminUserSecurityIntegrationTests Lista/filtro/ricerca utenti admin, flusso invito (PowerUser, Admin, CinemaStaff), promozione/retrocessione ruolo (blocco ultimo admin, utenti social-only, utenti disabilitati), incremento auth version, revoca refresh token su cambio ruolo, endpoint ruoli assegnabili
12 ExternalAuthIntegrationTests Flussi OAuth Google/Microsoft: avvio, callback, code exchange, creazione/linking account, rifiuto ruoli elevati, consumo/invalidazione state, riutilizzo exchange code, email non verificata, account work/personal, nascondere provider non configurati
13 PasswordCredentialsIntegrationTests Cambio password (successo, password corrente errata, rifiuto social-only), login post-cambio, revoca refresh token, incremento auth version, forgot password (messaggio generico, anti-enumerazione, utenti disabilitati), reset password (token valido/invalido/riutilizzato/scaduto, social-only set password), endpoint sicurezza account
14 AccountTokenIntegrationTests Creazione/hashing token, validazione (scopo corretto/errato, token invalido/vuoto/scaduto), consumo (una volta, rifiuto riutilizzo), revoca token esistenti su nuova creazione, audit log, validazione URL redirect
15 AccountDeletionIntegrationTests Export dati utente (JSON), richiesta/conferma cancellazione (token-based), anonimizzazione account (rimozione PII, disabilitazione), cancellazione admin (guardia ultimo admin), toggle abilita/disabilita, revoca assegnazioni CinemaStaff, rimozione external login per ri-registrazione, audit log
16 DashboardStatsIntegrationTests Riepilogo ricavi (settimana corrente/scorsa, mese corrente/scorso, anno, delta), trend ricavi (granularità mensile/settimanale, cumulativo), classifica film, filtro cinema
17 SettingsIntegrationTests GET/PUT impostazioni piattaforma (prezzo base biglietto, buffer minuti, percentuali VIP/Access), validazione (prezzo negativo, buffer fuori range), RBAC (solo Admin), serializzazione UTC
18 SalaIntegrationTests CRUD sale, salvataggio/sostituzione layout posti, categorie posto (Platea, Vip, Access, Galleria), guardie sala disabilitata per show/checkout, conteggio show
19 RegistaIntegrationTests Lista paginata registi con filtro stato film (InCartellone, InArrivo), ordinamento (recenti, nome_az, piu_film), ricerca, verifica conteggio film
20 ProgrammazioneIntegrationTests Programmazione film (tab evidenza/uscita/tutti, filtro cinema, ricerca, filtro categoria, paginazione, esclusione film futuri), lista cinema (ordinamento nome/distanza), scheda film con ShowCalendar, test limiti UTC, set/clear cinema preferito
21 CategoriaIntegrationTests CRUD categorie (lista, creazione, rilevamento duplicati, modifica, cancellazione)
22 RbacIntegrationTests Matrice controllo accessi basata su ruoli: Anonymous → 401, User → 403 su endpoint admin/power, PowerUser → permesso CRUD ma 403 su admin-only, Admin → accesso completo
23 CorsConfigurationIntegrationTests Header CORS per origini permesse/non permesse, preflight, richieste autenticate, upload media
24 MovieIntegrationTests (TMDB) Ricerca TMDB (risultati, rifiuto query troppo corte), import TMDB (crea film con metadati, rilevamento duplicati, RBAC), anteprima film
25 ApiCanonicalNamespaceIntegrationTests Verifica che tutti gli endpoint funzionino sotto /api/*: auth, films, cinemas, shows, checkout, profile, admin, upload media; conferma che gli alias legacy root restituiscano 404
26 CinemaStaffAuthorizationIntegrationTests Enumerazione ruoli CinemaStaff, tabella assegnazioni, rifiuto social login per staff, invito con/senza assegnazioni, CRUD admin su assegnazioni, endpoint cinema operativi staff, gestione show su cinema autorizzati/non autorizzati
27 ShowCancellationIntegrationTests Cancellazione show (nessun biglietto, ordini pendenti, ordini pagati carta/credito/misti), creazione rimborso Stripe, blocco biglietti validati, blocco show iniziati, gestione ordini checkout-in-progress, webhook Stripe rimborso tardivo, risoluzione revisione manuale, lista cancellazioni
28 ValidazioneTicketIntegrationTests Lookup validazione biglietti, validazione (successo, conflitto doppia validazione, mismatch cinema), visualizzazione categoria posto
29 LegalAcceptanceIntegrationTests Registrazione con/senza accettazione legale, memorizzazione versione documenti legali, requisito accettazione per social login, accettazione legale post-autenticazione, esposizione versione legale nella config frontend
30 FrontendHostedSmokeTests Factory speciale: FrontendWebApplicationFactory (non il CustomWebApplicationFactory standard). Testa il progetto web frontend direttamente: route pubbliche (200), shell HTML route protette, .html legacy (404), header CORS/sicurezza (CSP, X-Frame-Options, Permissions-Policy, Referrer-Policy), disponibilità asset statici (runtime-config.js, tailwind.css, font vendor), documentazione deploy edge, prepare-edge-deploy.mjs (genera artefatti SEO, robots.txt, sitemap.xml, HTML pre-renderizzato), guardie regressione codice sorgente (no stili inline, no innerHTML, no route proxy legacy, no naming unitPrice)
31 RateLimiterIntegrationTests 7 test (RL1-RL7): blocco login dopo N tentativi stessa email, email diversa contatore separato, risposta 429 JSON+Retry-After, blocco forgot-password, forgot-password email diversa, X-Forwarded-For diverso contatore separato, body JSON senza email fallback anonimo

Comandi

# Tutti i test backend (639 test)
dotnet test tests/backend/FilmAPI.Tests.csproj

# Solo integration test
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Integration"

# Esecuzione senza restore (VS Code task)
dotnet test tests/backend/FilmAPI.Tests.csproj --no-restore

Harnessing

  • Factory centralizzato: tutti i test di integrazione usano CustomWebApplicationFactory (o sottoclasse) via IClassFixture<T>. xUnit crea una singola istanza della factory condivisa tra tutti i test della classe.
  • Database SQLite: SqliteConnection aperto in InitializeAsync, usato per creare un FilmDbContext con UseSqlite(_connection). La connessione rimane aperta per tutta la durata dei test (pattern "shared in-memory database").
  • Fakes: registrati nel container DI via builder.ConfigureServices() nel factory, sostituiscono le implementazioni reali.
  • Configurazione: ConfigureAppConfiguration con AddInMemoryCollection per override puliti senza toccare variabili d'ambiente globali.
  • Progetto di test: FilmAPI.Tests.csproj (target net10.0) referenzia FilmAPI.csproj, FilmApiSeeder.csproj, e CineBase.Web.csproj. Non ci sono file .runsettings o appsettings.Test.json: tutta la configurazione è programmatica.
  • Copertura codice: coverlet.collector 6.0.4 integrato.

Frontend — Playwright (tests/frontend/)

Cos'è Playwright

Playwright è un framework di automazione browser sviluppato da Microsoft. A differenza di strumenti come Jest o Vitest (che eseguono test in un ambiente Node.js simulato), Playwright apre un vero browser Chromium/Edge e ci interagisce esattamente come farebbe un utente reale.

Cosa significa in pratica:

  • Il JavaScript del frontend viene eseguito realmente nel browser. Playwright non simula il DOM: carica la pagina, esegue tutti gli script, attende il rendering, e poi interagisce con gli elementi.
  • Simula il comportamento utente: click, digitazione, navigazione, scroll, submit di form. Le interazioni sono eventi DOM reali, non mock.
  • Può intercettare il traffico di rete: page.route() permette di mockare le risposte delle API, quindi il frontend viene testato in isolamento dal backend reale.
  • Cattura screenshot e trace: in caso di fallimento, Playwright salva automaticamente screenshot, video, e trace per il debugging.

Modalità di esecuzione

Playwright ha due modalità in CineBase:

1. Browser installato localmente (default)

Playwright usa Chromium (o Edge su Windows) installato sulla macchina. Lancia automaticamente il server frontend via dotnet run e ci connette il browser.

cd frontend/CineBase.Web

# Esegue la suite browser audit
npm run test:browser

# Esegue con browser visibile (non headless)
npm run test:browser:headed

# Valida la coverage matrix + esegue test
npm run test:browser:full

# Valida solo la coverage matrix
npm run test:browser:matrix

# Comando diretto equivalente
npx playwright test -c ../../tests/frontend/playwright.config.cjs

2. Container Docker

Playwright gira in un container Docker (mcr.microsoft.com/playwright:v1.60.0-noble) contro lo stack completo Docker Compose (MariaDB + backend + frontend reali). In questa modalità, le richieste HTTP sono vere: il browser nel container chiama il frontend e il backend reali nel docker network.

# Avvia lo stack E2E (backend, frontend, MariaDB, Mailpit, seeder)
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example up -d --build

# Esegue il Docker Compose smoke test
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright

# Esegue l'intera suite browser audit nel container
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright test -c playwright.config.cjs browser-audit.spec.cjs

# Spegne lo stack
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example down --remove-orphans

Differenze tra le due modalità

Aspetto Browser installato Container Docker
Backend Mockato via page.route() Reale (stack Docker Compose)
Database Nessuno MariaDB con dati seeded
Velocità ~2 minuti ~3 minuti (+ avvio stack)
Dipendenze Node.js, .NET SDK, Chromium/Edge Solo Docker
Isolamento Fronend isolato dal backend Test end-to-end reale
CI/CD Adatto a CI leggero (solo frontend) Adatto a CI completo (stack intero)

File e struttura

File Tipo Contenuto
playwright.config.cjs Configurazione Browser (Chromium/Edge), timeout 30s, workers=1, headless, trace on failure, webserver auto-start (dotnet run)
Dockerfile Immagine Docker Basato su mcr.microsoft.com/playwright:v1.60.0-noble, esegue npm ci, entrypoint playwright
browser-audit.spec.cjs (~2700 righe) Suite principale Testa 34 route del frontend con ~160 stati, usando API mockate via page.route()
docker-compose.smoke.spec.cjs Smoke test Docker Test contro stack reale: pagine pubbliche, login admin, creazione ordine
browser-audit.matrix.cjs Coverage matrix Mappa pagina → stati → titoli test con soglie di copertura
validate-browser-audit-matrix.cjs Validatore Verifica riferimenti matrix, confronta file modificati (git diff) con matrix
unit/parse-utc-datetime.test.cjs Unit test Node.js 10 suite di test per parseUtcDateTime()

browser-audit.spec.cjs — Suite principale

Finalità: testare il rendering e il comportamento del frontend in isolamento dal backend.

Approccio: usa page.route() di Playwright per intercettare tutte le chiamate API e rispondere con dati mock generati da buildState(). Il frontend non sa di essere mockato: il JavaScript si esegue normalmente, fetcha dati, renderizza componenti, e Playwright verifica che tutto funzioni.

buildState() genera uno stato backend completo in memoria:

  • 25 film, 12 cinema, 11 show, 6 ordini, 6 biglietti profilo, 5 utenti
  • Categorie, registi, mappe posti, movimenti credito, dati ricavi, impostazioni

Logout testato: ~40 scenari che coprono:

  • Pagine pubbliche (home, programmazione, scheda film, pagina legale)
  • Flussi autenticati (profilo, acquisto, pagamento, dashboard admin)
  • Backoffice admin (film, cinema, categorie, registi, sale, utenti, show, rimborsi, ricariche)
  • Flussi auth (login, registrazione, forgot/reset password, social login)
  • Validazione biglietti (lookup, validazione, modalità auto)
  • Gestione errori e stati vuoti
  • Gestione date UTC

docker-compose.smoke.spec.cjs — Smoke test Docker

Finalità: verificare che lo stack Docker completo funzioni end-to-end.

Approccio: si connette al frontend e backend reali (nessun page.route()) e testa:

  • Render pagine pubbliche (200)
  • Login admin con credenziali reali
  • Pulsanti OAuth nascosti quando provider non configurati
  • Caricamento pagina checkout
  • Avviso Stripe disabilitato
  • Caricamento pagina revisione rimborsi
  • Creazione ordine pendente via API

Dipendenze: stack Docker avviato con seeder (admin account, film, show, posti disponibili).

Configurazione Playwright (playwright.config.cjs)

{
  testDir: './tests/frontend',
  testMatch: '**/*.spec.cjs',
  workers: 1,                    // Esecuzione sequenziale
  timeout: 30000,                // 30 secondi per test
  expect: { timeout: 5000 },     // 5 secondi per assertion
  use: {
    browserName: 'chromium',
    channel: 'msedge',           // Edge su Windows
    headless: true,
    baseURL: process.env.CINEBASE_PLAYWRIGHT_BASE_URL || 'http://localhost:5101',
    trace: 'retain-on-failure',  // Trace solo su fallimento
  },
  webServer: !process.env.CINEBASE_USE_EXTERNAL_SERVER ? {
    command: 'dotnet run --project frontend/CineBase.Web/CineBase.Web.csproj --no-launch-profile --urls {baseURL}',
    timeout: 120000,
  } : undefined,
}
  • CINEBASE_PLAYWRIGHT_BASE_URL: override URL frontend (default http://localhost:5101)
  • CINEBASE_PLAYWRIGHT_API_ORIGIN: override URL backend per i mock (default http://localhost:5000)
  • CINEBASE_USE_EXTERNAL_SERVER: se 'true', Playwright non avvia dotnet run (usato nei container Docker dove il server è già in esecuzione)

Cosa Playwright testa vs cosa simula

Playwright... Dettaglio
Esegue realmente Il browser (Chromium/Edge), il rendering HTML/CSS, l'esecuzione JavaScript (Web Components, fetch, event listener, state management), il ciclo di vita della pagina (load, DOMContentLoaded, route client-side)
Simula Solo nella suite browser-audit: le risposte API via page.route(). Il JavaScript chiama fetch('/api/...') e Playwright intercetta la richiesta restituendo dati mock. Nella suite docker-compose.smoke: nulla è simulato, tutte le richieste sono reali.
Non testa Il backend (nella suite browser-audit), il database, Stripe, SMTP, OAuth (tutti mockati). Nella suite smoke invece testa l'intero stack.

Unit test Node.js

tests/frontend/unit/parse-utc-datetime.test.cjs — 10 suite di test che verificano la funzione parseUtcDateTime() del frontend. Usa assert di Node.js (nessun framework). Testa: ISO bare, suffisso Z, solo data, secondi, null/empty, stringhe con offset, regressione vs new Date(), equivalenza epoch, whitespace, compatibilità campi backend.

node tests/frontend/unit/parse-utc-datetime.test.cjs

Riepilogo comandi

Backend

# Tutti i test
dotnet test tests/backend/FilmAPI.Tests.csproj

# Solo unit
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Unit"

# Solo integration
dotnet test tests/backend/FilmAPI.Tests.csproj --filter "FullyQualifiedName~Integration"

# Senza restore (task VS Code)
dotnet test tests/backend/FilmAPI.Tests.csproj --no-restore

Frontend (browser installato)

cd frontend/CineBase.Web

npm run test:browser           # Suite browser audit
npm run test:browser:headed    # Modalità headed (browser visibile)
npm run test:browser:full      # Matrix validation + test
npm run test:browser:matrix    # Solo matrix validation

Frontend (container Docker)

# Avvio stack
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example up -d --build

# Smoke test
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright

# Suite completa nel container
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example --profile e2e run --rm --build playwright test -c playwright.config.cjs browser-audit.spec.cjs

# Spegnimento stack
docker compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file .env.docker.example down --remove-orphans

Unit test Node.js

node tests/frontend/unit/parse-utc-datetime.test.cjs