From cfbba613dcd42b6778658668d5157e82a149e486 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Sun, 15 Nov 2026 20:02:30 +0100 Subject: [PATCH] Soglie dei badge ricalibrate su ~71 eventi a stagione; obiettivo pagelle a 1000 Presenza fissa 15/35/55, Sempre in palestra 5/10/20, Sherpa dei palloni 3/5/8; obiettivo o13 da 200 a 1000 voti. Test di integrazione ora derivano le soglie dalle definizioni; documenti e CHANGELOG aggiornati. Co-Authored-By: Claude Sonnet 5.5 --- docs/CHANGELOG.md | 12 +++++ docs/modules/badge.md | 6 +-- docs/modules/obiettivi-squadra.md | 4 +- docs/modules/serie-presenze.md | 8 +-- src/lib/badges.ts | 6 +-- src/lib/obiettivi.ts | 4 +- test/integration/palloni-badge.test.ts | 13 +++-- test/integration/presenze-badge.test.ts | 45 +++++++++------- .../serie-allenamenti-badge.test.ts | 43 +++++++-------- test/unit/badges.test.ts | 52 +++++++++---------- test/unit/notifiche-smart.test.ts | 4 +- 11 files changed, 109 insertions(+), 88 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 268c264..129df9b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,18 @@ versioni `0.y.z` erano pre-release. ## [Non rilasciato] +### Modificato + +- Badge: nuove soglie calibrate su circa 71 eventi a stagione. «Presenza fissa» passa a + 15/35/55 presenze, «Sempre in palestra» a 5/10/20 allenamenti di fila, «Sherpa dei palloni» + a 3/5/8 turni. I badge si calcolano a runtime: chi ha già un grado può scendere. +- Obiettivi: «pagelle compilate» passa da 200 a 1000 voti (con 90-150 voti a partita, 200 si + raggiungevano dopo 2-3 partite). +- Nessun cambio di logica: i calcoli di badge e obiettivi sono stati spostati in `src/lib/` + (`percentuale`, `quantiAlGrado`, `mediaPresenzeRosa`, …) e le soglie dei badge segreti sono + costanti usate anche nei testi. Cambia solo il testo della celebrazione di «Aspettate, + arrivo!», che non ripete più la descrizione. + ## [1.6.2] - 2026-11-11 Layout corretto sugli schermi stretti e statistiche tecniche dai + dello scout in Squadra e diff --git a/docs/modules/badge.md b/docs/modules/badge.md index d09a6b8..7ad7931 100644 --- a/docs/modules/badge.md +++ b/docs/modules/badge.md @@ -90,9 +90,9 @@ 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 | | `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 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 | -| `serie-allenamenti` | Sempre in palestra | allenamenti consecutivi presenti (`g.serieAllenamenti`); un infortunio non spezza la serie, un'assenza sì | 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 / 5 / 8 | +| `presenze` | Presenza fissa | totale presenze (presente o ritardo) a eventi/partite di sempre, non solo della stagione in corso (`g.presenze`) | 15 / 35 / 55 | +| `serie-allenamenti` | Sempre in palestra | allenamenti consecutivi presenti (`g.serieAllenamenti`); un infortunio non spezza la serie, un'assenza sì | 5 / 10 / 20 | ### Badge segreti (booleani, nascosti finché non sbloccati) diff --git a/docs/modules/obiettivi-squadra.md b/docs/modules/obiettivi-squadra.md index 3c4c0a5..744f340 100644 --- a/docs/modules/obiettivi-squadra.md +++ b/docs/modules/obiettivi-squadra.md @@ -44,7 +44,7 @@ corrente dinamico (vedi sotto). | `o2` | Tutti rispondono alle convocazioni | risposte totali / eventi possibili (esclusi i compleanni) | 90% | `risposte_presenze` | | `o7` | Presenze collettive | % di presenze (presente/ritardo) su tutti gli allenamenti e le partite definiti, passati e futuri; posti = convocati dell'evento (tutta la rosa se vuoto) | 90 | `eventi_app` + `risposte_presenze` | | `o12` | Media pagelle da 7.5 | media di tutti i voti, arrotondata a una cifra decimale | 7.5 | `pagelle_voti` | -| `o13` | 200 pagelle compilate | conteggio voti | 200 | `pagelle_voti` | +| `o13` | 1000 pagelle compilate | conteggio voti | 1000 | `pagelle_voti` | | `o11` | Continuità di squadra | giocatori con ≥3 allenamenti consecutivi | 12 (min. per un 6vs6) | `serieAllenamenti` | | `o3` | Prima vittoria del campionato | `min(vittorie, 1)` | 1 | JSON partite CSI (vedi sotto) | | `o4` | 5 vittorie in campionato | `min(vittorie, 5)` | 5 | JSON partite CSI | @@ -58,7 +58,7 @@ badge) con stato attuale, come si calcola, cosa conta e cosa no, quando vale, da dati e un esempio con numeri. Per le due percentuali di presenze (`o1`, `o7`) la card distingue «Presenza persa» (assente, forse, infortunato, nessuna risposta: il posto resta vuoto) da «Non entra nel calcolo» (cene, eventi di squadra, compleanni). I testi stanno nel campo `dettaglio` di ogni obiettivo in `obiettivi.ts`: chi cambia il calcolo o il target di un obiettivo aggiorna anche il suo `dettaglio`, altrimenti la card mente. Un obiettivo che supera il 90% genera anche una notifica -smart (`notifiche-smart.ts`). I target fissi (200 pagelle, 7.5 di media, 1/5/10 +smart (`notifiche-smart.ts`). I target fissi (1000 pagelle, 7.5 di media, 1/5/10 vittorie) sono scelte editoriali da rivedere a mano a ogni stagione — nessuna configurazione o UI per farlo, si cambia il numero in `obiettivi.ts`. Fa eccezione "Continuità di squadra" (vedi sotto): il suo target ha un significato specifico, non va scalato come gli altri. diff --git a/docs/modules/serie-presenze.md b/docs/modules/serie-presenze.md index 76c5250..7dcf7d3 100644 --- a/docs/modules/serie-presenze.md +++ b/docs/modules/serie-presenze.md @@ -243,10 +243,10 @@ fastidio, va distinto lì — il calcolo non sa differenziare "mai partito" da " Toccare la regola di calcolo muove anche questi, che non hanno logica propria: -| Dove | Cosa | Soglie | -| ------------------------------- | -------------------------------------------------------------- | --------------------------- | -| `badges.ts` `serie-allenamenti` | "Sempre in palestra", su `serieAllenamenti` | bronzo 3, argento 6, oro 10 | -| `obiettivi.ts` `o11` | "Continuità di squadra": giocatori con `serieAllenamenti >= 3` | target 12 | +| Dove | Cosa | Soglie | +| ------------------------------- | -------------------------------------------------------------- | ---------------------------- | +| `badges.ts` `serie-allenamenti` | "Sempre in palestra", su `serieAllenamenti` | bronzo 5, argento 10, oro 20 | +| `obiettivi.ts` `o11` | "Continuità di squadra": giocatori con `serieAllenamenti >= 3` | target 12 | --- diff --git a/src/lib/badges.ts b/src/lib/badges.ts index 60b2ae2..c10926c 100644 --- a/src/lib/badges.ts +++ b/src/lib/badges.ts @@ -100,7 +100,7 @@ export const badgeDefs: BadgeDef[] = [ "Quante volte ti sei caricato la sacca dei palloni: lavoro oscuro, badge luminoso.", unita: "turni palloni", icon: CircleDot, - soglie: { bronzo: 3, argento: 6, oro: 10 }, + soglie: { bronzo: 3, argento: 5, oro: 8 }, valore: (g) => g.palloni, }, { @@ -109,7 +109,7 @@ export const badgeDefs: BadgeDef[] = [ descrizione: "Per chi è sempre lì, partita dopo partita, senza tirarsi indietro.", unita: "presenze", icon: Repeat, - soglie: { bronzo: 5, argento: 15, oro: 30 }, + soglie: { bronzo: 15, argento: 35, oro: 55 }, valore: (g) => g.presenze, }, { @@ -119,7 +119,7 @@ export const badgeDefs: BadgeDef[] = [ "Allenamenti consecutivi a cui sei stato presente: la costanza paga più del talento.", unita: "allenamenti di fila", icon: Rocket, - soglie: { bronzo: 3, argento: 6, oro: 10 }, + soglie: { bronzo: 5, argento: 10, oro: 20 }, valore: (g) => g.serieAllenamenti, }, ]; diff --git a/src/lib/obiettivi.ts b/src/lib/obiettivi.ts index 6aec795..f4eca9f 100644 --- a/src/lib/obiettivi.ts +++ b/src/lib/obiettivi.ts @@ -284,10 +284,10 @@ export function obiettiviSquadra( }, { id: "o13", - titolo: "200 pagelle compilate", + titolo: "1000 pagelle compilate", descrizione: "Quanti voti la squadra ha dato nel corso della stagione", valore: ctx.pagelle.length, - target: 200, + target: 1000, unita: "voti", emoji: "🗳️", impatto: "Vota i compagni a fine partita: bastano due minuti.", diff --git a/test/integration/palloni-badge.test.ts b/test/integration/palloni-badge.test.ts index 2fab9b7..aa608be 100644 --- a/test/integration/palloni-badge.test.ts +++ b/test/integration/palloni-badge.test.ts @@ -106,7 +106,7 @@ if (!locale) { // m1-m3: turno confermato esplicitamente a pv1 (3 turni -> soglia bronzo). // m4: NESSUN turno confermato -> non deve contare per nessuno, anche se un algoritmo // di rotazione (usato altrove per la UI) proporrebbe qualcuno in automatico. - // m5-m7: confermati di nuovo a pv1 (6 turni totali -> soglia argento). + // m5-m6: confermati di nuovo a pv1 (5 turni totali -> soglia argento). const eventi = [ [`${PREFISSO}-m1`, "2020-01-01", "pv1"], [`${PREFISSO}-m2`, "2020-01-02", "pv1"], @@ -114,7 +114,6 @@ if (!locale) { [`${PREFISSO}-m4`, "2020-01-04", null], [`${PREFISSO}-m5`, "2020-01-05", "pv1"], [`${PREFISSO}-m6`, "2020-01-06", "pv1"], - [`${PREFISSO}-m7`, "2020-01-07", "pv1"], ] as const; for (const [id, data] of eventi.slice(0, 3)) await creaEvento(id, data); @@ -128,7 +127,7 @@ if (!locale) { assert.equal( statoBadge(palloniDef, giocatoreAzzerato(conteggioA3["pv1"]!)).grado, "bronzo", - "3 turni: bronzo, non oltre (soglia argento è 6)", + "3 turni: bronzo, non oltre (soglia argento è 5)", ); for (const [id, data] of eventi.slice(3)) await creaEvento(id, data); @@ -136,13 +135,13 @@ if (!locale) { if (giocatore) await confermaTurno(id, giocatore); const eventiLetti = await leggiEventi(); - assert.equal(eventiLetti.length, 7, "tutti gli eventi scritti si rileggono"); + assert.equal(eventiLetti.length, 6, "tutti gli eventi scritti si rileggono"); const salvati = await leggiTurniSalvati(); - assert.equal(Object.keys(salvati).length, 6, "6 turni confermati esplicitamente, m4 no"); + assert.equal(Object.keys(salvati).length, 5, "5 turni confermati esplicitamente, m4 no"); const conteggio = conteggioTurni(salvati, eventiLetti, OGGI); - assert.equal(conteggio["pv1"], 6, "6 turni confermati per pv1"); + assert.equal(conteggio["pv1"], 5, "5 turni confermati per pv1"); assert.equal( conteggio["pv2"] ?? 0, 0, @@ -150,7 +149,7 @@ if (!locale) { ); const badgePv1 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv1"]!)); - assert.equal(badgePv1.grado, "argento", "6 turni: soglia argento raggiunta"); + assert.equal(badgePv1.grado, "argento", "5 turni: soglia argento raggiunta"); const badgePv2 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv2"] ?? 0)); assert.equal(badgePv2.grado, null, "zero turni confermati: nessun badge"); diff --git a/test/integration/presenze-badge.test.ts b/test/integration/presenze-badge.test.ts index ae86bdb..b5b84bc 100644 --- a/test/integration/presenze-badge.test.ts +++ b/test/integration/presenze-badge.test.ts @@ -122,54 +122,63 @@ if (!locale) { await prova( "il badge presenze passa da bronzo a oro con presenze vere lette dal database", async () => { - // 30 allenamenti passati. "pp1" risponde a tutti e 30 (i primi 5 "presente", un - // "ritardo" nel mezzo per verificare che conti come presenza, il resto "presente"), - // così una sola scrittura basta a verificare le tre soglie 5/15/30. - for (let i = 1; i <= 30; i += 1) { + // Tanti allenamenti passati quanti ne chiede l'oro. "pp1" risponde a tutti (un "ritardo" + // nel mezzo per verificare che conti come presenza), così una sola scrittura basta a + // verificare le tre soglie. + const { bronzo, argento, oro } = presenzeDef.soglie; + for (let i = 1; i <= oro; i += 1) { await creaEvento(`${PREFISSO}-a${String(i).padStart(2, "0")}`, i); } - for (let i = 1; i <= 30; i += 1) { + for (let i = 1; i <= oro; i += 1) { const stato = i === 10 ? "ritardo" : "presente"; await rispondi(`${PREFISSO}-a${String(i).padStart(2, "0")}`, "pp1", stato); } - // "pp2" risponde solo ai primi 5: resta a bronzo, non oltre. - for (let i = 1; i <= 5; i += 1) { + // "pp2" risponde solo ai primi `bronzo`: resta a bronzo, non oltre. + for (let i = 1; i <= bronzo; i += 1) { await rispondi(`${PREFISSO}-a${String(i).padStart(2, "0")}`, "pp2", "presente"); } // "pp2" risponde anche "assente" a un evento: non deve contare. - await rispondi(`${PREFISSO}-a06`, "pp2", "assente"); + await rispondi(`${PREFISSO}-a${String(bronzo + 1).padStart(2, "0")}`, "pp2", "assente"); const eventi = await leggiEventi(); - assert.equal(eventi.length, 30, "tutti gli eventi scritti si rileggono"); + assert.equal(eventi.length, oro, "tutti gli eventi scritti si rileggono"); const presenze = await leggiPresenze(); const contoPp1 = contaPresenzeGiocatore("pp1", eventi, presenze, OGGI); - assert.equal(contoPp1, 30, "30 risposte, incluso un ritardo contato come presenza"); + assert.equal( + contoPp1, + oro, + "una risposta per evento, incluso un ritardo contato come presenza", + ); assert.equal( statoBadge(presenzeDef, giocatoreAzzerato(contoPp1)).grado, "oro", - "30 presenze: soglia oro raggiunta", + `${oro} presenze: soglia oro raggiunta`, ); const contoPp2 = contaPresenzeGiocatore("pp2", eventi, presenze, OGGI); - assert.equal(contoPp2, 5, "5 presenti, l'assente su a06 non conta"); + assert.equal(contoPp2, bronzo, "solo i presenti contano, l'assente su a-extra no"); const badgePp2 = statoBadge(presenzeDef, giocatoreAzzerato(contoPp2)); - assert.equal(badgePp2.grado, "bronzo", "5 presenze: soglia bronzo raggiunta, non oltre"); + assert.equal( + badgePp2.grado, + "bronzo", + `${bronzo} presenze: soglia bronzo raggiunta, non oltre`, + ); assert.equal(badgePp2.prossimo, "argento"); - assert.equal(badgePp2.prossimaSoglia, 15); + assert.equal(badgePp2.prossimaSoglia, argento); - // Un pp2 a metà strada (15 presenze) sblocca l'argento. - for (let i = 7; i <= 16; i += 1) { + // Un pp2 a metà strada (`argento` presenze) sblocca l'argento. + for (let i = bronzo + 2; i <= argento + 1; i += 1) { await rispondi(`${PREFISSO}-a${String(i).padStart(2, "0")}`, "pp2", "presente"); } const eventiDopo = await leggiEventi(); const presenzeDopo = await leggiPresenze(); const contoPp2Dopo = contaPresenzeGiocatore("pp2", eventiDopo, presenzeDopo, OGGI); - assert.equal(contoPp2Dopo, 15, "5 + 10 nuove presenze"); + assert.equal(contoPp2Dopo, argento, "bronzo + nuove presenze fino all'argento"); assert.equal( statoBadge(presenzeDef, giocatoreAzzerato(contoPp2Dopo)).grado, "argento", - "15 presenze: soglia argento raggiunta", + `${argento} presenze: soglia argento raggiunta`, ); }, ); diff --git a/test/integration/serie-allenamenti-badge.test.ts b/test/integration/serie-allenamenti-badge.test.ts index c2abf80..d7d6f1f 100644 --- a/test/integration/serie-allenamenti-badge.test.ts +++ b/test/integration/serie-allenamenti-badge.test.ts @@ -125,39 +125,40 @@ if (!locale) { await prova( "il badge passa da bronzo a oro con presenze consecutive vere, e un buco lo azzera", async () => { - // 10 allenamenti passati, tutti presenti per "sa1": bronzo (3), poi argento (6), poi - // oro (10) man mano che si rileggono i dati. - for (let i = 1; i <= 10; i += 1) { + // Tanti allenamenti passati quanti ne chiede l'oro, tutti presenti per "sa1": le prime + // `bronzo` presenze valgono bronzo, tutte e `oro` valgono oro. + const { bronzo, oro } = serieDef.soglie; + for (let i = 1; i <= oro; i += 1) { await creaAllenamento(`${PREFISSO}-a${String(i).padStart(2, "0")}`, i); await rispondi(`${PREFISSO}-a${String(i).padStart(2, "0")}`, "sa1", "presente"); } - const eventi10 = await leggiEventi(); - const presenze10 = await leggiPresenze(); - const serieA3 = serieConsecutiva( + const eventiOro = await leggiEventi(); + const presenzeOro = await leggiPresenze(); + const serieBronzo = serieConsecutiva( "sa1", - eventi10.slice(0, 3), - presenze10, + eventiOro.slice(0, bronzo), + presenzeOro, "allenamento", OGGI, ); - assert.equal(serieA3, 3); + assert.equal(serieBronzo, bronzo); assert.equal( - statoBadge(serieDef, giocatoreAzzerato(serieA3)).grado, + statoBadge(serieDef, giocatoreAzzerato(serieBronzo)).grado, "bronzo", - "3 allenamenti di fila: soglia bronzo", + `${bronzo} allenamenti di fila: soglia bronzo`, ); - const serieCompleta = serieConsecutiva("sa1", eventi10, presenze10, "allenamento", OGGI); - assert.equal(serieCompleta, 10, "presente a tutti e 10, nessun buco"); + const serieCompleta = serieConsecutiva("sa1", eventiOro, presenzeOro, "allenamento", OGGI); + assert.equal(serieCompleta, oro, `presente a tutti e ${oro}, nessun buco`); assert.equal( statoBadge(serieDef, giocatoreAzzerato(serieCompleta)).grado, "oro", - "10 allenamenti di fila: soglia oro", + `${oro} allenamenti di fila: soglia oro`, ); - // Un undicesimo allenamento con un buco (assente) azzera la serie. - await creaAllenamento(`${PREFISSO}-a11`, 11); - await rispondi(`${PREFISSO}-a11`, "sa1", "assente"); + // Un allenamento in più con un buco (assente) azzera la serie. + await creaAllenamento(`${PREFISSO}-a${oro + 1}`, oro + 1); + await rispondi(`${PREFISSO}-a${oro + 1}`, "sa1", "assente"); const eventiConBuco = await leggiEventi(); const presenzeConBuco = await leggiPresenze(); const serieDopoBuco = serieConsecutiva( @@ -167,7 +168,7 @@ if (!locale) { "allenamento", OGGI, ); - assert.equal(serieDopoBuco, 0, "un'assenza azzera la serie, anche dopo 10 di fila"); + assert.equal(serieDopoBuco, 0, `un'assenza azzera la serie, anche dopo ${oro} di fila`); assert.equal( statoBadge(serieDef, giocatoreAzzerato(serieDopoBuco)).grado, null, @@ -182,7 +183,7 @@ if (!locale) { // ripartire da 1. const eventi = [`${PREFISSO}-b01`, `${PREFISSO}-b02`, `${PREFISSO}-b03`, `${PREFISSO}-b04`]; for (let i = 0; i < eventi.length; i += 1) { - await creaAllenamento(eventi[i]!, 20 + i); + await creaAllenamento(eventi[i]!, serieDef.soglie.oro + 10 + i); } await rispondi(eventi[0]!, "sa2", "presente"); await rispondi(eventi[1]!, "sa2", "presente"); @@ -195,8 +196,8 @@ if (!locale) { assert.equal(serie, 3, "l'infortunio è saltato: 3 presenze restano consecutive"); assert.equal( statoBadge(serieDef, giocatoreAzzerato(serie)).grado, - "bronzo", - "3 di fila (infortunio escluso dal conteggio): soglia bronzo", + null, + "3 di fila: ancora sotto la soglia bronzo, ma la serie non si è azzerata", ); }); } finally { diff --git a/test/unit/badges.test.ts b/test/unit/badges.test.ts index 207aebd..e4e05fd 100644 --- a/test/unit/badges.test.ts +++ b/test/unit/badges.test.ts @@ -111,39 +111,39 @@ assert.equal( "valore azzerato dal gate: progresso azzerato anch'esso, non ingannevole", ); -// --- palloni: soglie 3 / 6 / 10 ----------------------------------------------- +// --- palloni: soglie 3 / 5 / 8 ----------------------------------------------- const palloniDef = badgeDefs.find((b) => b.id === "palloni")!; assert.equal(gradoRaggiunto(palloniDef, 2), null, "sotto la prima soglia nessun grado"); assert.equal(gradoRaggiunto(palloniDef, 3), "bronzo", "la soglia è inclusiva"); -assert.equal(gradoRaggiunto(palloniDef, 5), "bronzo"); -assert.equal(gradoRaggiunto(palloniDef, 6), "argento"); -assert.equal(gradoRaggiunto(palloniDef, 9), "argento"); -assert.equal(gradoRaggiunto(palloniDef, 10), "oro"); +assert.equal(gradoRaggiunto(palloniDef, 4), "bronzo"); +assert.equal(gradoRaggiunto(palloniDef, 5), "argento"); +assert.equal(gradoRaggiunto(palloniDef, 7), "argento"); +assert.equal(gradoRaggiunto(palloniDef, 8), "oro"); assert.equal(gradoRaggiunto(palloniDef, 99), "oro", "oltre l'oro resta oro"); assert.equal( - statoBadge(palloniDef, g({ palloni: 5 })).progresso, - 83, - "5 turni su 6 per l'argento: 83%", + statoBadge(palloniDef, g({ palloni: 4 })).progresso, + 80, + "4 turni su 5 per l'argento: 80%", ); -// --- presenze: soglie 5 / 15 / 30 --------------------------------------------- +// --- presenze: soglie 15 / 35 / 55 --------------------------------------------- const presenzeDef = badgeDefs.find((b) => b.id === "presenze")!; -assert.equal(gradoRaggiunto(presenzeDef, 4), null, "sotto la prima soglia nessun grado"); -assert.equal(gradoRaggiunto(presenzeDef, 5), "bronzo", "la soglia è inclusiva"); -assert.equal(gradoRaggiunto(presenzeDef, 14), "bronzo"); -assert.equal(gradoRaggiunto(presenzeDef, 15), "argento"); -assert.equal(gradoRaggiunto(presenzeDef, 29), "argento"); -assert.equal(gradoRaggiunto(presenzeDef, 30), "oro"); +assert.equal(gradoRaggiunto(presenzeDef, 14), null, "sotto la prima soglia nessun grado"); +assert.equal(gradoRaggiunto(presenzeDef, 15), "bronzo", "la soglia è inclusiva"); +assert.equal(gradoRaggiunto(presenzeDef, 34), "bronzo"); +assert.equal(gradoRaggiunto(presenzeDef, 35), "argento"); +assert.equal(gradoRaggiunto(presenzeDef, 54), "argento"); +assert.equal(gradoRaggiunto(presenzeDef, 55), "oro"); assert.equal(gradoRaggiunto(presenzeDef, 999), "oro", "oltre l'oro resta oro"); -// --- serie-allenamenti: soglie 3 / 6 / 10 ------------------------------------- +// --- serie-allenamenti: soglie 5 / 10 / 20 ------------------------------------- const serieAllenamentiDef = badgeDefs.find((b) => b.id === "serie-allenamenti")!; -assert.equal(gradoRaggiunto(serieAllenamentiDef, 2), null, "sotto la prima soglia nessun grado"); -assert.equal(gradoRaggiunto(serieAllenamentiDef, 3), "bronzo", "la soglia è inclusiva"); -assert.equal(gradoRaggiunto(serieAllenamentiDef, 5), "bronzo"); -assert.equal(gradoRaggiunto(serieAllenamentiDef, 6), "argento"); -assert.equal(gradoRaggiunto(serieAllenamentiDef, 9), "argento"); -assert.equal(gradoRaggiunto(serieAllenamentiDef, 10), "oro"); +assert.equal(gradoRaggiunto(serieAllenamentiDef, 4), null, "sotto la prima soglia nessun grado"); +assert.equal(gradoRaggiunto(serieAllenamentiDef, 5), "bronzo", "la soglia è inclusiva"); +assert.equal(gradoRaggiunto(serieAllenamentiDef, 9), "bronzo"); +assert.equal(gradoRaggiunto(serieAllenamentiDef, 10), "argento"); +assert.equal(gradoRaggiunto(serieAllenamentiDef, 19), "argento"); +assert.equal(gradoRaggiunto(serieAllenamentiDef, 20), "oro"); assert.equal(gradoRaggiunto(serieAllenamentiDef, 50), "oro", "oltre l'oro resta oro"); // --- badgeGiocatore ---------------------------------------------------------- @@ -200,7 +200,7 @@ assert.equal(vuota.inProgresso.length, badgeDefs.length); assert.equal(vuota.nascosti, badgeSegreti.length); const piena = collezioneBadge( - g({ mvp: 5, mediaVoto: 8, votiPagella: 5, presenze: 30, infortuni: 3 }), + g({ mvp: 5, mediaVoto: 8, votiPagella: 5, presenze: 55, infortuni: 3 }), ); assert.equal( piena.ottenuti, @@ -219,9 +219,9 @@ assert.equal( mvp: 5, mediaVoto: 10, votiPagella: 5, - palloni: 10, - presenze: 30, - serieAllenamenti: 10, + palloni: 8, + presenze: 55, + serieAllenamenti: 20, }), ), null, diff --git a/test/unit/notifiche-smart.test.ts b/test/unit/notifiche-smart.test.ts index 764e484..1f75865 100644 --- a/test/unit/notifiche-smart.test.ts +++ b/test/unit/notifiche-smart.test.ts @@ -47,9 +47,9 @@ assert.equal(segreta.emoji, "⏰"); assert.equal(segreta.testo, "Forse è il momento di puntare la sveglia 10 minuti prima! 😄"); // --- "sei a un passo": solo entro due unità dalla soglia --------------------- -assert.ok(ids(g({ presenze: 4 })).some((id) => id.startsWith("quasi:presenze"))); +assert.ok(ids(g({ presenze: 13 })).some((id) => id.startsWith("quasi:presenze"))); assert.ok( - !ids(g({ mvp: 5, presenze: 2 })).some((id) => id.startsWith("quasi:presenze")), + !ids(g({ mvp: 5, presenze: 12 })).some((id) => id.startsWith("quasi:presenze")), "a 3 di distanza non si notifica", );