Il badge Sherpa dei palloni conta solo i turni confermati, non le proposte

rosa.ts calcolava Giocatore.palloni su completaTurni() (turni salvati + proposte
automatiche di rotazione non ancora confermate da nessuno): un giocatore poteva
avanzare nel badge senza aver mai confermato un turno, solo perché l'algoritmo lo
proponeva per un evento passato. Ora passa a conteggioTurni() solo turniSalvati
(i turni davvero confermati in turni_palloni); completaTurni() resta in uso solo
per la UI di rotazione (TurnoPalloni.tsx, PromemoriaPalloni.tsx). Corregge anche
la StatTile "quante volte hai portato i palloni" nel profilo, che leggeva lo
stesso valore.

Aggiornato palloni-badge.test.ts per verificare il nuovo comportamento (un evento
non confermato non conta più per nessuno) invece del vecchio. docs/modules/
badge.md e palloni.md aggiornati di conseguenza, spostando la voce da "Limiti
noti" a "risolto".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 14:43:58 +02:00
co-authored by Claude Sonnet 5
parent 4fb05748c3
commit d250f41749
4 changed files with 77 additions and 71 deletions
+27 -23
View File
@@ -36,13 +36,12 @@ badge assegnati per voto dai compagni.
- **Badge Sherpa dei palloni** (`palloni`, in `badgeDefs`): `g.palloni` non è un contatore - **Badge Sherpa dei palloni** (`palloni`, in `badgeDefs`): `g.palloni` non è un contatore
incrementato a ogni evento, ma ricalcolato da `conteggioTurni()` (`palloni-core.ts`) su incrementato a ogni evento, ma ricalcolato da `conteggioTurni()` (`palloni-core.ts`) su
`Giocatore.palloni` (`rosa.ts`) — meccanismo di turni/rotazione descritto per intero in `Giocatore.palloni` (`rosa.ts`) — meccanismo di turni/rotazione descritto per intero in
[palloni.md](palloni.md), non ripetuto qui. Un punto rilevante per il badge, **non ovvio**: [palloni.md](palloni.md), non ripetuto qui. `rosa.ts` passa a `conteggioTurni()` **solo i
il conteggio include anche le proposte automatiche di `completaTurni()` **non ancora turni confermati** (`turniSalvati` da `useTurniPalloni()`), non l'output di
confermate** da nessuno (solo per partite/eventi, mai per allenamenti), non solo i turni `completaTurni()`: le proposte automatiche di rotazione (usate altrove, per la UI di
salvati esplicitamente in `turni_palloni` — un giocatore può ricevere credito per un turno `TurnoPalloni.tsx`) non contano per il badge, che premia solo chi ha davvero confermato di
che non ha mai confermato di aver fatto, semplicemente perché l'algoritmo di rotazione lo ha aver portato i palloni. Conta solo per eventi già trascorsi (`e.data < oggi`, stesso
proposto per un evento ormai passato. Conta solo per eventi già trascorsi (`e.data < oggi`, criterio delle presenze).
stesso criterio delle presenze).
- **Badge Pagellone** (`pagella`, in `badgeDefs`): a differenza degli altri badge da - **Badge Pagellone** (`pagella`, in `badgeDefs`): a differenza degli altri badge da
contatore, richiede un numero minimo di voti (`VOTI_MINIMI_PAGELLA = 5`, `badges.ts`) prima contatore, richiede un numero minimo di voti (`VOTI_MINIMI_PAGELLA = 5`, `badges.ts`) prima
che `g.mediaVoto` conti — sotto soglia `valore(g)` è forzato a `0` (badge bloccato), anche che `g.mediaVoto` conti — sotto soglia `valore(g)` è forzato a `0` (badge bloccato), anche
@@ -91,7 +90,7 @@ soglia raggiunta o superata (soglie inclusive), oltre l'oro resta oro.
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `mvp` | MVP | partite vinte nettamente al voto MVP dei compagni (`g.mvp`, vedi pipeline sopra) | 1 / 3 / 5 | | `mvp` | MVP | partite vinte nettamente al voto MVP dei compagni (`g.mvp`, vedi pipeline sopra) | 1 / 3 / 5 |
| `pagella` | Pagellone | media dei voti pagella ricevuti dai compagni a fine partita (`g.mediaVoto`), solo se ne ha ricevuti almeno `VOTI_MINIMI_PAGELLA` (5) | 6.5 / 7.5 / 8.5 | | `pagella` | Pagellone | media dei voti pagella ricevuti dai compagni a fine partita (`g.mediaVoto`), solo se ne ha ricevuti almeno `VOTI_MINIMI_PAGELLA` (5) | 6.5 / 7.5 / 8.5 |
| `palloni` | Sherpa dei palloni | quante volte hai fatto (o ti è stato proposto, vedi sopra) il turno palloni (`g.palloni`) | 3 / 6 / 10 | | `palloni` | Sherpa dei palloni | quante volte hai confermato il turno palloni (`g.palloni`) — le proposte automatiche non ancora confermate non contano | 3 / 6 / 10 |
| `presenze` | Presenza fissa | totale presenze (presente o ritardo) a eventi/partite di sempre, non solo della stagione in corso (`g.presenze`) | 5 / 15 / 30 | | `presenze` | Presenza fissa | totale presenze (presente o ritardo) a eventi/partite di sempre, non solo della stagione in corso (`g.presenze`) | 5 / 15 / 30 |
| `serie-allenamenti` | Sempre in palestra | allenamenti consecutivi presenti (`g.serieAllenamenti`); un infortunio non spezza la serie, un'assenza sì | 3 / 6 / 10 | | `serie-allenamenti` | Sempre in palestra | allenamenti consecutivi presenti (`g.serieAllenamenti`); un infortunio non spezza la serie, un'assenza sì | 3 / 6 / 10 |
| `serie-conferme` | Risposta lampo | conferme di presenza consecutive date entro 24h dalla convocazione (`g.serieConferme`) | 3 / 8 / 15 | | `serie-conferme` | Risposta lampo | conferme di presenza consecutive date entro 24h dalla convocazione (`g.serieConferme`) | 3 / 8 / 15 |
@@ -205,22 +204,22 @@ dopo l'analisi che ha trovato il gap "un voto solo sblocca il badge"):
tenga il badge bloccato sotto soglia, lo sblocchi al voto minimo con il grado giusto, e tenga il badge bloccato sotto soglia, lo sblocchi al voto minimo con il grado giusto, e
applichi le soglie normali sopra soglia. applichi le soglie normali sopra soglia.
**Badge Sherpa dei palloni — pipeline end-to-end e proposte non confermate** (analisi **Badge Sherpa dei palloni — pipeline end-to-end, ora senza contare le proposte non
dedicata: nessun bug trovato, ma il comportamento "le proposte contano" — già in confermate** (analisi dedicata: trovato e sistemato il gap "le proposte contano", che
`palloni.md` — non era mai stato dimostrato con dati veri): gonfiava il badge di turni mai confermati da nessuno — vedi "Problemi noti da sistemare"):
- Unit: `badges.test.ts:93-104` — soglie 3/6/10 (confine incluso, oltre l'oro resta oro) + - Unit: `badges.test.ts:93-104` — soglie 3/6/10 (confine incluso, oltre l'oro resta oro) +
`palloni-core.test.ts`, già completo prima di questa sessione (`completaTurni()`, `palloni-core.test.ts`, già completo prima di questa sessione (`completaTurni()`,
`conteggioTurni()`, rotazione bilanciata su un giro completo di partite, allenamenti mai `conteggioTurni()`, rotazione bilanciata su un giro completo di partite, allenamenti mai
proposti in automatico, turno di un giocatore non più in rosa che non rompe il conteggio). proposti in automatico, turno di un giocatore non più in rosa che non rompe il conteggio).
- Integration (`npx supabase start` richiesto): - Integration (`npx supabase start` richiesto):
- `scritture.test.ts` — un turno resta uno per evento (l'upsert sostituisce, non aggiunge). - `scritture.test.ts` — un turno resta uno per evento (l'upsert sostituisce, non aggiunge).
- `palloni-badge.test.ts` (nuovo) — end-to-end reale: scrive eventi e turni **solo - `palloni-badge.test.ts` — end-to-end reale: scrive eventi e turni **solo parzialmente
parzialmente confermati** su `eventi_app`/`turni_palloni`, rilegge via REST come fa confermati** su `eventi_app`/`turni_palloni`, rilegge via REST come fa `fetchTurni()`/
`fetchTurni()`/`daRiga()`, passa i dati per `completaTurni()``conteggioTurni()` fino a `daRiga()` e passa `turniSalvati` (solo confermati, mai l'output di `completaTurni()`) a
`statoBadge()`: dimostra che un evento passato senza turno confermato riceve comunque una `conteggioTurni()` fino a `statoBadge()`: dimostra che un evento passato senza turno
proposta automatica che **conta per il badge di chi viene scelto**, anche se non ha mai confermato **non conta per nessuno**, anche se un algoritmo di rotazione (usato altrove
confermato nulla; verifica anche che un evento futuro non conti, pur avendo già per la UI) lo proporrebbe automaticamente; verifica anche che un evento futuro non conti,
un'assegnazione. pur avendo già una conferma.
**Badge Presenza fissa — pipeline end-to-end** (analisi dedicata: nessun bug trovato; a **Badge Presenza fissa — pipeline end-to-end** (analisi dedicata: nessun bug trovato; a
differenza di MVP/pagelle/badge social, per questo badge **non serve** l'estensione RLS di differenza di MVP/pagelle/badge social, per questo badge **non serve** l'estensione RLS di
@@ -318,14 +317,19 @@ Trovati in audit, nessuno bloccante (nessun bug nella logica di calcolo):
risposte precedenti a `m9`: su quelle righe la serie è un'approssimazione. risposte precedenti a `m9`: su quelle righe la serie è un'approssimazione.
- Nessuno storico dei badge sbloccati: se cambiano le soglie o i dati sorgente, un badge già - Nessuno storico dei badge sbloccati: se cambiano le soglie o i dati sorgente, un badge già
"ottenuto" può sparire o apparire retroattivamente. "ottenuto" può sparire o apparire retroattivamente.
- **Sherpa dei palloni conta anche le proposte non confermate**: `g.palloni` include i turni
che `completaTurni()` propone in automatico per un evento passato senza assegnazione
esplicita, non solo quelli confermati in `turni_palloni` — comportamento voluto (documentato
in [palloni.md](palloni.md)), dimostrato con dati veri in `palloni-badge.test.ts`, ma non
intuitivo: un giocatore può vedere avanzare il badge senza aver mai cliccato nulla.
- Notifiche "nuovo badge" solo locali al dispositivo (localStorage), si ripetono cambiando - Notifiche "nuovo badge" solo locali al dispositivo (localStorage), si ripetono cambiando
browser o dispositivo. browser o dispositivo.
**Risolto (analisi del badge Sherpa dei palloni)**: prima `g.palloni` (`rosa.ts`) includeva
anche i turni che `completaTurni()` propone in automatico per un evento passato senza
assegnazione esplicita, non solo quelli confermati in `turni_palloni` — un giocatore poteva
vedere avanzare il badge senza aver mai confermato nulla, semplicemente perché l'algoritmo di
rotazione l'aveva proposto. Ora `rosa.ts` passa a `conteggioTurni()` solo `turniSalvati` (i
turni confermati), non l'output di `completaTurni()`: quest'ultimo resta in uso solo per la
UI di rotazione (`TurnoPalloni.tsx`, `PromemoriaPalloni.tsx`), mai per il conteggio del badge.
Dimostrato con dati veri in `palloni-badge.test.ts`. [palloni.md](palloni.md) aggiornato di
conseguenza.
**Risolto (M13, `20260908120000_m13_convocati_e_pagelle_chiuse.sql`)**: prima la policy di M11 **Risolto (M13, `20260908120000_m13_convocati_e_pagelle_chiuse.sql`)**: prima la policy di M11
garantiva solo che il voto fosse firmato con il proprio `votante_id`, non che il votato (né il garantiva solo che il voto fosse firmato con il proprio `votante_id`, non che il votato (né il
votante) fossero convocati per quella partita — filtro solo applicativo, aggirabile scrivendo votante) fossero convocati per quella partita — filtro solo applicativo, aggirabile scrivendo
+6 -7
View File
@@ -33,11 +33,12 @@ compaiono.
- `useAssegnaTurno()` (`palloni.ts`) conferma una proposta o riassegna manualmente, con - `useAssegnaTurno()` (`palloni.ts`) conferma una proposta o riassegna manualmente, con
upsert su `evento_id`. upsert su `evento_id`.
- Il conteggio "quante volte hai portato i palloni" mostrato nel profilo e nei badge è - Il conteggio "quante volte hai portato i palloni" mostrato nel profilo e nei badge è
ricalcolato a runtime da `conteggioTurni()` su turni salvati **più proposte non ancora ricalcolato a runtime da `conteggioTurni()` sui **soli turni confermati** (`turniSalvati`
confermate** (partite/eventi) — non è uno storico in tabella dedicata. Conta solo gli in `rosa.ts`) — non è uno storico in tabella dedicata, ma non include le proposte
eventi già passati (`e.data < oggi`, stesso criterio delle presenze): un turno assegnato automatiche di `completaTurni()` (quelle restano solo per la UI di rotazione,
in anticipo per un allenamento futuro non è ancora "portato", quindi non sale finché quel `TurnoPalloni.tsx`/`PromemoriaPalloni.tsx`). Conta solo gli eventi già passati (`e.data <
giorno non arriva. oggi`, stesso criterio delle presenze): un turno assegnato in anticipo per un allenamento
futuro non è ancora "portato", quindi non sale finché quel giorno non arriva.
- `TurnoPalloni.tsx` mostra/assegna il turno sulla card di un evento; `PromemoriaPalloni.tsx` - `TurnoPalloni.tsx` mostra/assegna il turno sulla card di un evento; `PromemoriaPalloni.tsx`
è il banner in Home per il giocatore di turno. è il banner in Home per il giocatore di turno.
@@ -62,8 +63,6 @@ nessuna chiamata di rete. Stesso meccanismo di `apri-sondaggio` (vedi
- **L'invio è manuale**: nessun cron manda il promemoria da solo, se l'admin non preme il - **L'invio è manuale**: nessun cron manda il promemoria da solo, se l'admin non preme il
pulsante non parte niente (DD-025). `destinatariPromemoriaPalloni()` — la versione "chi è di pulsante non parte niente (DD-025). `destinatariPromemoriaPalloni()` — la versione "chi è di
turno oggi" — resta in `palloni-core.ts` ma non la chiama più nessuno. turno oggi" — resta in `palloni-core.ts` ma non la chiama più nessuno.
- Il conteggio dei turni include anche le proposte non confermate: badge e statistiche
possono contare turni mai effettivamente convalidati da nessuno.
- La rotazione non considera le assenze dichiarate: può proporre il turno a chi ha risposto - La rotazione non considera le assenze dichiarate: può proporre il turno a chi ha risposto
"assente" o "infortunato" per quell'evento. "assente" o "infortunato" per quell'evento.
+17 -3
View File
@@ -61,7 +61,7 @@ export function useRosa(): Giocatore[] {
const voti = useVotiMvp(); const voti = useVotiMvp();
const { voti: pagelle } = usePagelle(); const { voti: pagelle } = usePagelle();
const { righe: cacche } = useCacche(); const { righe: cacche } = useCacche();
const { turni } = useTurniPalloni(); const { salvati: turniSalvati } = useTurniPalloni();
const { infortuni, ritardi } = useInfortuniERitardi(); const { infortuni, ritardi } = useInfortuniERitardi();
const { eventi } = useEventi(); const { eventi } = useEventi();
const { presenze: mappaPresenze, tempi } = useRispostePresenze(); const { presenze: mappaPresenze, tempi } = useRispostePresenze();
@@ -71,7 +71,10 @@ export function useRosa(): Giocatore[] {
return useMemo(() => { return useMemo(() => {
const medie = mediePagelle(pagelle); const medie = mediePagelle(pagelle);
const statCacche = statisticheCacche(cacche); const statCacche = statisticheCacche(cacche);
const palloni = conteggioTurni(turni, eventi); // Solo i turni confermati, non le proposte automatiche di completaTurni(): il badge deve
// premiare chi ha davvero portato i palloni, non chi l'algoritmo di rotazione ha
// scelto per un evento passato senza che nessuno confermasse nulla.
const palloni = conteggioTurni(turniSalvati, eventi);
const mvpVinti = mvpVintiPerGiocatore(votiMvp); const mvpVinti = mvpVintiPerGiocatore(votiMvp);
return squadra return squadra
@@ -98,7 +101,18 @@ export function useRosa(): Giocatore[] {
infortuni: infortuni[g.id] ?? 0, infortuni: infortuni[g.id] ?? 0,
ritardi: ritardi[g.id] ?? 0, ritardi: ritardi[g.id] ?? 0,
})); }));
}, [squadra, votiMvp, pagelle, cacche, turni, infortuni, ritardi, eventi, mappaPresenze, tempi]); }, [
squadra,
votiMvp,
pagelle,
cacche,
turniSalvati,
infortuni,
ritardi,
eventi,
mappaPresenze,
tempi,
]);
} }
/** Il giocatore selezionato sul dispositivo, con le statistiche complete. */ /** Il giocatore selezionato sul dispositivo, con le statistiche complete. */
+27 -38
View File
@@ -3,24 +3,26 @@
* `bun test/integration/palloni-badge.test.ts`. * `bun test/integration/palloni-badge.test.ts`.
* *
* I test unitari (`test/unit/palloni-core.test.ts`, `test/unit/badges.test.ts`) verificano * I test unitari (`test/unit/palloni-core.test.ts`, `test/unit/badges.test.ts`) verificano
* `completaTurni()`/`conteggioTurni()` e `statoBadge()` come funzioni pure, con eventi e turni * `conteggioTurni()` e `statoBadge()` come funzioni pure, con eventi e turni costruiti a mano.
* costruiti a mano. Qui invece si scrivono eventi e turni veri su `eventi_app`/`turni_palloni`, * Qui invece si scrivono eventi e turni veri su `eventi_app`/`turni_palloni`, si rileggono via
* si rileggono via REST con la stessa forma di `fetchTurni()`/`daRiga()`, e si passa il * REST con la stessa forma di `fetchTurni()`/`daRiga()`, e si passa il risultato attraverso
* risultato attraverso `completaTurni()` → `conteggioTurni()` fino a `statoBadge()` sul badge * `conteggioTurni()` fino a `statoBadge()` sul badge `palloni`: se una colonna cambia nome o la
* `palloni`: se una colonna cambia nome o la mappatura si rompe, qui il grado del badge torna * mappatura si rompe, qui il grado del badge torna sbagliato anche se i test unitari restano
* sbagliato anche se i test unitari restano verdi, perché quelli non toccano mai il database. * verdi, perché quelli non toccano mai il database.
* *
* Copre in particolare un comportamento **documentato ma non ovvio** (`docs/modules/ * Verifica in particolare che il badge conti **solo i turni confermati**
* palloni.md` § Limiti noti): il conteggio usato dal badge include anche le proposte * (`Giocatore.palloni` in `rosa.ts` usa `turniSalvati`, non l'output di `completaTurni()`):
* automatiche non ancora confermate da nessuno, non solo i turni salvati esplicitamente. Qui * un evento passato senza turno confermato non deve avanzare il badge di nessuno, anche se
* lo si dimostra con dati veri, non solo con l'affermazione in doc. * `completaTurni()` (usato altrove, per la UI di rotazione) lo proporrebbe automaticamente a
* qualcuno. Prima di questo fix il badge includeva anche le proposte non confermate — vedi
* `docs/modules/badge.md` § Limiti noti (risolto) per il dettaglio del bug e della correzione.
* *
* Gira solo sullo stack locale (`npx supabase start`) e cancella le proprie righe alla fine: * Gira solo sullo stack locale (`npx supabase start`) e cancella le proprie righe alla fine:
* usa id con il prefisso `test-palloni-badge`, che nessun dato vero può avere. * usa id con il prefisso `test-palloni-badge`, che nessun dato vero può avere.
*/ */
import assert from "node:assert/strict"; import assert from "node:assert/strict";
import { badgeDefs, statoBadge } from "@/lib/badges"; import { badgeDefs, statoBadge } from "@/lib/badges";
import { completaTurni, conteggioTurni, type CandidatoTurno } from "@/lib/palloni-core"; import { conteggioTurni } from "@/lib/palloni-core";
import { daRiga, type RigaEvento, type Evento } from "@/lib/eventi"; import { daRiga, type RigaEvento, type Evento } from "@/lib/eventi";
import { giocatori, type Giocatore } from "@/lib/crapp-data"; import { giocatori, type Giocatore } from "@/lib/crapp-data";
import { statoLocale } from "../helpers/locale"; import { statoLocale } from "../helpers/locale";
@@ -41,11 +43,6 @@ if (!locale) {
// così restano "passati" (e quindi contati) a prescindere da quando gira il test. // così restano "passati" (e quindi contati) a prescindere da quando gira il test.
const OGGI = "2099-01-01"; const OGGI = "2099-01-01";
const ROSA: CandidatoTurno[] = [
{ id: "pv1", nome: "Uno" },
{ id: "pv2", nome: "Due" },
];
const rest = (percorso: string, init?: RequestInit) => const rest = (percorso: string, init?: RequestInit) =>
fetch(`${URL_BASE}/rest/v1/${percorso}`, { fetch(`${URL_BASE}/rest/v1/${percorso}`, {
...init, ...init,
@@ -86,6 +83,7 @@ if (!locale) {
return righe.map(daRiga); return righe.map(daRiga);
} }
/** Rilegge esattamente come `fetchTurni()`: solo i turni confermati, nessuna proposta. */
async function leggiTurniSalvati(): Promise<Record<string, string>> { async function leggiTurniSalvati(): Promise<Record<string, string>> {
const res = await rest( const res = await rest(
`turni_palloni?evento_id=like.${PREFISSO}*&select=evento_id,giocatore_id`, `turni_palloni?evento_id=like.${PREFISSO}*&select=evento_id,giocatore_id`,
@@ -103,12 +101,11 @@ if (!locale) {
try { try {
await prova( await prova(
"il badge palloni passa da bronzo ad argento con turni reali, incluse le proposte non confermate", "il badge palloni passa da bronzo ad argento con turni reali, ignorando gli eventi mai confermati",
async () => { async () => {
// m1-m3: turno confermato esplicitamente a pv1 (3 turni -> soglia bronzo). // m1-m3: turno confermato esplicitamente a pv1 (3 turni -> soglia bronzo).
// m4: NESSUN turno salvato -> completaTurni() deve proporlo in automatico a chi ha // m4: NESSUN turno confermato -> non deve contare per nessuno, anche se un algoritmo
// fatto meno turni (pv2, a zero) -> conta comunque per il badge di pv2, pur non // di rotazione (usato altrove per la UI) proporrebbe qualcuno in automatico.
// essendo mai stato confermato da nessuno (comportamento documentato in palloni.md).
// m5-m7: confermati di nuovo a pv1 (6 turni totali -> soglia argento). // m5-m7: confermati di nuovo a pv1 (6 turni totali -> soglia argento).
const eventi = [ const eventi = [
[`${PREFISSO}-m1`, "2020-01-01", "pv1"], [`${PREFISSO}-m1`, "2020-01-01", "pv1"],
@@ -129,36 +126,28 @@ if (!locale) {
const salvati = await leggiTurniSalvati(); const salvati = await leggiTurniSalvati();
assert.equal(Object.keys(salvati).length, 6, "6 turni confermati esplicitamente, m4 no"); assert.equal(Object.keys(salvati).length, 6, "6 turni confermati esplicitamente, m4 no");
const turniCompleti = completaTurni(salvati, eventiLetti, ROSA); const conteggio = conteggioTurni(salvati, eventiLetti, OGGI);
assert.equal(
turniCompleti[`${PREFISSO}-m4`],
"pv2",
"m4 senza turno salvato: la proposta automatica sceglie pv2 (meno turni)",
);
const conteggio = conteggioTurni(turniCompleti, eventiLetti, OGGI);
assert.equal(conteggio["pv1"], 6, "6 turni confermati per pv1"); assert.equal(conteggio["pv1"], 6, "6 turni confermati per pv1");
assert.equal( assert.equal(
conteggio["pv2"], conteggio["pv2"] ?? 0,
1, 0,
"pv2 non ha mai confermato nulla, ma la proposta per m4 conta comunque", "pv2 non ha mai confermato nulla: m4 senza conferma non conta per nessuno",
); );
const badgePv1 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv1"]!)); const badgePv1 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv1"]!));
assert.equal(badgePv1.grado, "argento", "6 turni: soglia argento raggiunta"); assert.equal(badgePv1.grado, "argento", "6 turni: soglia argento raggiunta");
const badgePv2 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv2"]!)); const badgePv2 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv2"] ?? 0));
assert.equal(badgePv2.grado, null, "1 turno (solo proposto): sotto la soglia bronzo (3)"); assert.equal(badgePv2.grado, null, "zero turni confermati: nessun badge");
}, },
); );
await prova("un evento futuro non riceve conteggio, anche se già assegnato", async () => { await prova("un evento futuro non riceve conteggio, anche se già confermato", async () => {
// Stesso scenario di sopra ma con "oggi" prima di tutti gli eventi: nessuno dei turni, // Stesso scenario di sopra ma con "oggi" prima di tutti gli eventi: nessun turno
// confermati o proposti, deve ancora contare per il badge. // confermato deve ancora contare per il badge.
const eventiLetti = await leggiEventi(); const eventiLetti = await leggiEventi();
const salvati = await leggiTurniSalvati(); const salvati = await leggiTurniSalvati();
const turniCompleti = completaTurni(salvati, eventiLetti, ROSA); const conteggio = conteggioTurni(salvati, eventiLetti, "2019-01-01");
const conteggio = conteggioTurni(turniCompleti, eventiLetti, "2019-01-01");
assert.deepEqual(conteggio, {}, "tutti gli eventi sono nel futuro rispetto a 'oggi'"); assert.deepEqual(conteggio, {}, "tutti gli eventi sono nel futuro rispetto a 'oggi'");
}); });
} finally { } finally {