From 447016f03bae6fc1348f81e1d8e3c7e274ce7a7c Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 8 Sep 2026 11:19:27 +0200 Subject: [PATCH] Completa la copertura test dell'obiettivo "250 presenze complessive" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C'era solo un confronto circolare (la stessa formula ricalcolata sugli stessi dati reali) più il caso rosa vuota. Aggiunto un unit test con roster piccolo e valori noti (5 + 10 + 15 = 30), e un integration test end-to-end che scrive eventi/risposte veri sul database locale, calcola contaPresenzeGiocatore() (la stessa funzione pura usata da useRosa() in produzione) sui dati riletti, e verifica che obiettiviSquadra() sommi correttamente il risultato. Co-Authored-By: Claude Sonnet 5 --- test/integration/obiettivi.test.ts | 62 +++++++++++++++++++++++++++++- test/unit/obiettivi.test.ts | 9 +++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/test/integration/obiettivi.test.ts b/test/integration/obiettivi.test.ts index 930ae53..2eb31b1 100644 --- a/test/integration/obiettivi.test.ts +++ b/test/integration/obiettivi.test.ts @@ -21,7 +21,7 @@ import assert from "node:assert/strict"; import { giocatori } from "@/lib/crapp-data"; import { obiettiviSquadra } from "@/lib/obiettivi"; -import type { MappaPresenze } from "@/lib/presenze"; +import { contaPresenzeGiocatore, type MappaPresenze } from "@/lib/presenze"; import { statoLocale } from "../helpers/locale"; import { prova, riepilogo, salta } from "../helpers/prova"; @@ -279,6 +279,66 @@ if (!locale) { assert.equal(o2.scadenza, "2099-03-31", "scadenza o2 = ultimo giorno del mese iniettato"); }, ); + + await prova( + "o7 somma presenze calcolate da eventi/risposte reali del database", + async () => { + // o7 non calcola nulla da `ctx`: somma `g.presenze`, un campo già calcolato a monte da + // `contaPresenzeGiocatore()` (che in produzione alimenta `useRosa()`). Qui si esercita + // la stessa funzione pura sui dati appena scritti, per verificare l'intera catena + // DB -> contaPresenzeGiocatore -> o7, non solo la somma finale. + const allenamentoId = `${PREFISSO}-o7-allenamento`; + const partitaId = `${PREFISSO}-o7-partita`; + const OGGI_STR = "2099-01-20"; + + for (const [id, tipo, data] of [ + [allenamentoId, "allenamento", "2099-01-05"], + [partitaId, "partita", "2099-01-08"], + ] as const) { + const inserito = await rest("eventi_app", { + method: "POST", + body: JSON.stringify({ id, tipo, titolo: `Test obiettivi o7 (${tipo})`, data }), + }); + if (!inserito.ok) throw new Error(`inserimento evento fallito: ${await inserito.text()}`); + } + + // g1: presente ai due eventi (2 presenze). g2: presente e in ritardo (2 presenze, + // il ritardo conta). g3: assente a entrambi (0 presenze). + const [g1, g2, g3] = giocatori; + const righe = [ + { evento_id: allenamentoId, giocatore_id: g1!.id, stato: "presente" }, + { evento_id: partitaId, giocatore_id: g1!.id, stato: "presente" }, + { evento_id: allenamentoId, giocatore_id: g2!.id, stato: "presente" }, + { evento_id: partitaId, giocatore_id: g2!.id, stato: "ritardo" }, + { evento_id: allenamentoId, giocatore_id: g3!.id, stato: "assente" }, + { evento_id: partitaId, giocatore_id: g3!.id, stato: "assente" }, + ]; + const inserite = await rest("risposte_presenze", { method: "POST", body: JSON.stringify(righe) }); + if (!inserite.ok) throw new Error(`inserimento presenze fallito: ${await inserite.text()}`); + + const eventiReali = (await leggiEventi()).filter( + (e) => e.id === allenamentoId || e.id === partitaId, + ); + const presenzeReali = { + ...(await leggiPresenze(allenamentoId)), + ...(await leggiPresenze(partitaId)), + }; + + const rosaConPresenzeReali = [g1!, g2!, g3!].map((g) => ({ + ...g, + presenze: contaPresenzeGiocatore(g.id, eventiReali, presenzeReali, OGGI_STR), + })); + + const o7 = obiettiviSquadra(rosaConPresenzeReali, { eventi: [], presenze: {}, pagelle: [] }) + .find((o) => o.id === "o7")!; + + assert.equal( + o7.valore, + 4, + "g1 (2) + g2 (2, il ritardo conta) + g3 (0) = 4, calcolate dal database", + ); + }, + ); } finally { await rest(`risposte_presenze?evento_id=like.${PREFISSO}*`, { method: "DELETE" }); await rest(`eventi_app?id=like.${PREFISSO}*`, { method: "DELETE" }); diff --git a/test/unit/obiettivi.test.ts b/test/unit/obiettivi.test.ts index efa824e..fd7f85b 100644 --- a/test/unit/obiettivi.test.ts +++ b/test/unit/obiettivi.test.ts @@ -176,6 +176,15 @@ assert.equal( "rosa vuota: nessuna presenza", ); +// Valori noti e indipendenti dai dati reali della rosa: non solo la stessa formula +// ricalcolata sugli stessi dati, ma una somma verificabile a mente (5 + 10 + 15 = 30). +const rosaControllata = giocatori.slice(0, 3).map((g, i) => ({ ...g, presenze: [5, 10, 15][i]! })); +assert.equal( + trova(obiettiviSquadra(rosaControllata, contestoVuoto), "o7").valore, + 30, + "somma di presenze note, indipendente dal roster reale", +); + const pagelle: VotoPagella[] = [ { match_id: "m1", votante_id: "g1", votato_id: "g2", voto: 7 }, { match_id: "m1", votante_id: "g2", votato_id: "g1", voto: 8 },