/** Check dei turni palloni: `bun src/lib/palloni-core.test.ts`. */ import assert from "node:assert/strict"; import { formatData, giocatori } from "@/lib/crapp-data"; import type { Evento } from "@/lib/eventi"; import { completaTurni, conteggioTurni, destinatariPromemoriaPalloni, eventiDelGiorno, eventiPalloni, eventoPrecedente, eventoSuccessivo, messaggioPalloniOggi, oggiISO, } from "@/lib/palloni-core"; const rosa = giocatori.map((g) => ({ id: g.id, nome: g.nome })); const evento = (id: string, data: string, tipo: Evento["tipo"] = "allenamento"): Evento => ({ id, tipo, titolo: `Evento ${id}`, luogo: "PalaCRAP", data, ora: "21:00", note: "", convocati: [], campionato: false, casa: true, pagelleChiuse: false, }); const eventi: Evento[] = [ evento("e3", "2026-09-10"), evento("e1", "2026-09-01"), evento("compleanno", "2026-09-05", "compleanno"), evento("e2", "2026-09-05", "partita"), ]; // --- eventiPalloni: ordina per data e scarta i compleanni --------------------- const ordinati = eventiPalloni(eventi); assert.deepEqual( ordinati.map((e) => e.id), ["e1", "e2", "e3"], "compleanni esclusi e ordine cronologico", ); assert.equal(eventi[0]!.id, "e3", "l'array in ingresso non viene modificato"); // --- eventoPrecedente / eventoSuccessivo ------------------------------------- assert.equal(eventoPrecedente(eventi, "e2")?.id, "e1"); assert.equal(eventoPrecedente(eventi, "e1"), undefined, "il primo non ha precedente"); assert.equal(eventoSuccessivo(eventi, "e2")?.id, "e3"); assert.equal(eventoSuccessivo(eventi, "e3"), undefined, "l'ultimo non ha successivo"); assert.equal(eventoPrecedente(eventi, "inesistente"), undefined); // --- eventiDelGiorno --------------------------------------------------------- assert.deepEqual( eventiDelGiorno(eventi, "2026-09-05").map((e) => e.id), ["e2"], "il compleanno dello stesso giorno non richiede palloni", ); // --- completaTurni: niente proposta sugli allenamenti; partite sì ------------ const turni = completaTurni({ e2: "g5" }, eventi, rosa); assert.equal(turni["e2"], "g5", "il turno già assegnato non viene toccato"); assert.equal(turni["e1"], undefined, "allenamento senza salvataggio resta da assegnare"); assert.equal(turni["e3"], undefined, "allenamento futuro resta da assegnare"); assert.equal(Object.keys(turni).length, 1, "solo i turni salvati / partite proposte"); const conAllenamentoSalvato = completaTurni({ e1: "g3", e2: "g5" }, eventi, rosa); assert.equal(conAllenamentoSalvato["e1"], "g3", "un allenamento salvato resta"); assert.equal(conAllenamentoSalvato["e2"], "g5"); const molti = Array.from({ length: giocatori.length + 2 }, (_, i) => evento(`x${i}`, `2026-10-${String(i + 1).padStart(2, "0")}`, "partita"), ); const rotazione = conteggioTurni(completaTurni({}, molti, rosa)); const carichi = Object.values(rotazione); assert.equal( Math.max(...carichi) - Math.min(...carichi), 1, "su un giro completo di partite il carico resta bilanciato", ); assert.equal( Object.keys(rotazione).length, giocatori.length, "nessuno viene saltato prima che tutti abbiano fatto un turno", ); const soloAllenamenti = Array.from({ length: 5 }, (_, i) => evento(`a${i}`, `2026-11-${String(i + 1).padStart(2, "0")}`), ); assert.deepEqual( completaTurni({}, soloAllenamenti, rosa), {}, "solo allenamenti: nessuna proposta automatica", ); // Un turno salvato per un giocatore non più in rosa non deve rompere il conteggio. const conFantasma = completaTurni({ e1: "gXX" }, eventi, rosa); assert.equal(conFantasma["e1"], "gXX", "il turno storico resta com'è"); assert.ok(conFantasma["e2"], "la partita riceve comunque una proposta"); assert.equal(conFantasma["e3"], undefined, "l'allenamento senza salvataggio resta vuoto"); // --- conteggioTurni ---------------------------------------------------------- assert.deepEqual(conteggioTurni({ a: "g1", b: "g1", c: "g2" }), { g1: 2, g2: 1 }); assert.deepEqual(conteggioTurni({}), {}); // --- oggiISO ----------------------------------------------------------------- assert.match(oggiISO(), /^\d{4}-\d{2}-\d{2}$/); assert.equal(oggiISO(), new Date().toLocaleDateString("sv-SE"), "data locale, non UTC"); // --- destinatariPromemoriaPalloni -------------------------------------------- const eventiPush: Evento[] = [ evento("p1", "2026-02-01"), evento("p2", "2026-02-02"), evento("p3", "2026-02-03"), ]; const turniPush = { p1: "g1", p2: "g2", p3: "g3" }; assert.deepEqual( destinatariPromemoriaPalloni(turniPush, eventiPush, "2026-02-02"), ["g2", "g1"], "chi porta oggi e chi li aveva portati alla volta prima", ); assert.deepEqual( destinatariPromemoriaPalloni(turniPush, eventiPush, "2026-02-01"), ["g1"], "il primo evento non ha un precedente da avvisare", ); assert.deepEqual( destinatariPromemoriaPalloni(turniPush, eventiPush, "2026-03-01"), [], "nessun evento in quella data: nessun destinatario", ); assert.deepEqual( destinatariPromemoriaPalloni({ p1: "g1", p2: "g1" }, eventiPush, "2026-02-02"), ["g1"], "stessa persona oggi e alla volta prima: un solo avviso", ); // --- messaggioPalloniOggi ----------------------------------------------------- assert.deepEqual( messaggioPalloniOggi(turniPush, eventiPush, "2026-02-02", "g1", "Mario"), { title: "Porta i palloni oggi", body: "Evento p2 · 21:00. I palloni li hai tu dalla volta scorsa.", }, "chi li aveva alla volta prima deve riportarli oggi", ); assert.deepEqual( messaggioPalloniOggi(turniPush, eventiPush, "2026-02-02", "g2", "Luca"), { title: "Tocca a te prendere i palloni", body: `A fine Evento p2 porta a casa i palloni e riportali il ${formatData("2026-02-03")}.`, }, "l'incaricato di oggi sa quando riportarli, se c'è un evento successivo", ); assert.deepEqual( messaggioPalloniOggi(turniPush, eventiPush, "2026-02-03", "g3", "Anna"), { title: "Tocca a te prendere i palloni", body: "A fine Evento p3 porta a casa i palloni." }, "senza evento successivo il messaggio non promette una data", ); assert.deepEqual( messaggioPalloniOggi(turniPush, eventiPush, "2026-02-02", "g9", "Sara"), { title: "CrAPP · Turno palloni", body: "Sara, controlla il turno palloni nel calendario." }, "chi non è coinvolto oggi riceve il messaggio generico col proprio nome", ); assert.deepEqual( messaggioPalloniOggi(turniPush, eventiPush, "2026-05-01", "g9", ""), { title: "CrAPP · Turno palloni", body: "Controlla il calendario." }, "senza eventi in quella data e senza nome noto, il messaggio resta generico", ); console.log("palloni-core: ok");