Files
CRAPP/test/unit/scout-store.test.ts
T
davideandClaude Sonnet 5.5 51b7a10c99 Scout live: valutazioni − / + per fondamentale e per set
Per ogni convocato un − o un + su battuta, ricezione, attacco e muro, separato per set e
fuori dal punteggio (DD-053, migration m39: colonna scout_partite.valutazioni). Lo stato in
corso le salva in scout_live.stato; il CSV admin ha la tabella per set.

Nella pagina dello scout tolti il blocco avversario/campo, i tasti delle azioni e il
tabellone del punteggio; il titolo della sezione mostra cognome e numero del giocatore.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 08:16:39 +01:00

142 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Check dello scout: `bun test/unit/scout-store.test.ts`. */
import assert from "node:assert/strict";
import { giocatori } from "@/lib/crapp-data";
import {
azioniMeta,
contaValutazioni,
fondamentali,
giocatoriConScout,
totaliPerGiocatore,
totaliSquadra,
type Azione,
type Valutazione,
type ScoutMatch,
} from "@/lib/scout-store";
const a = (tipo: Azione["tipo"], giocatoreId?: string, set = 1): Azione => ({
id: `${tipo}-${giocatoreId ?? "team"}-${set}-${Math.random()}`,
tipo,
...(giocatoreId ? { giocatoreId } : {}),
set,
ts: 0,
});
const match = (
id: string,
setNostri: number,
setLoro: number,
azioni: Azione[] = [],
): ScoutMatch => ({
id,
data: "2026-09-01",
avversario: "Avversari",
casa: true,
setNostri,
setLoro,
parziali: [],
azioni,
valutazioni: [],
});
// --- totaliPerGiocatore: ace e muri valgono anche come punto ------------------
const azioni = [
a("attacco", "g1"),
a("ace", "g1"),
a("muro", "g1"),
a("errore", "g1"),
a("attacco", "g2"),
a("punto_avv"),
a("errore_avv"),
];
const totali = totaliPerGiocatore(azioni);
assert.deepEqual(totali.get("g1"), { punti: 3, ace: 1, muri: 1, errori: 1 });
assert.deepEqual(totali.get("g2"), { punti: 1, ace: 0, muri: 0, errori: 0 });
assert.equal(totali.size, 2, "le azioni senza giocatore non creano righe");
assert.equal(totaliPerGiocatore([]).size, 0);
// --- totaliSquadra -----------------------------------------------------------
assert.deepEqual(totaliSquadra([match("m1", 3, 0, azioni), match("m2", 3, 1, azioni)]), {
punti: 8,
ace: 2,
muri: 2,
errori: 2,
});
assert.deepEqual(totaliSquadra([]), { punti: 0, ace: 0, muri: 0, errori: 0 });
// --- giocatoriConScout: solo MVP da scout, presenze separate -----------------
const base = giocatori.find((g) => g.id === "g1")!;
const conScout = giocatoriConScout([match("m1", 3, 0, azioni)], { m1: base.nome });
const dopo = conScout.find((g) => g.id === "g1")!;
assert.equal(dopo.presenze, 0, "le azioni scout non alimentano le presenze personali");
assert.equal(dopo.mvp, 1, "l'MVP eletto viene contato");
assert.equal(dopo.totaliEventi, 0, "totaliEventi arriva dagli eventi CrAPP, non dallo scout");
const assente = conScout.find((g) => g.id === "g3")!;
assert.equal(assente.presenze, 0, "senza risposte presenze resta a zero");
assert.equal(assente.mvp, 0);
assert.equal(assente.totaliEventi, 0);
const senzaPartite = giocatoriConScout([]);
assert.ok(
senzaPartite.every((g) => g.presenze === 0 && g.mvp === 0 && g.totaliEventi === 0),
"senza partite scout le statistiche restano a zero",
);
// --- metadati azioni ---------------------------------------------------------
for (const [tipo, meta] of Object.entries(azioniMeta)) {
assert.ok(meta.label && meta.short, `${tipo}: etichette presenti`);
}
console.log("scout-store: ok");
// --- valutazioni − / +: per giocatore, fondamentale e set; fuori dal punteggio -------
const v = (
giocatoreId: string,
fondamentale: Valutazione["fondamentale"],
segno: Valutazione["segno"],
set = 1,
): Valutazione => ({
id: `${giocatoreId}-${fondamentale}-${segno}-${set}-${Math.random()}`,
giocatoreId,
fondamentale,
segno,
set,
ts: 0,
});
assert.deepEqual(
fondamentali.map((f) => f.id),
["battuta", "ricezione", "attacco", "muro"],
);
const val = [
v("g1", "battuta", "+"),
v("g1", "battuta", "+"),
v("g1", "battuta", "-"),
v("g1", "ricezione", "-", 2),
v("g1", "muro", "+", 2),
v("g2", "attacco", "+"),
];
assert.deepEqual(contaValutazioni(val, "g1", 1), {
battuta: { piu: 2, meno: 1 },
ricezione: { piu: 0, meno: 0 },
attacco: { piu: 0, meno: 0 },
muro: { piu: 0, meno: 0 },
});
assert.deepEqual(
contaValutazioni(val, "g1", 2).ricezione,
{ piu: 0, meno: 1 },
"il set 2 è separato",
);
assert.deepEqual(
contaValutazioni(val, "g1").battuta,
{ piu: 2, meno: 1 },
"senza set: tutta la partita",
);
assert.deepEqual(contaValutazioni(val, "g1").ricezione, { piu: 0, meno: 1 });
assert.deepEqual(
contaValutazioni(val, "g3", 1).battuta,
{ piu: 0, meno: 0 },
"giocatore senza valutazioni",
);
assert.equal(totaliPerGiocatore([]).size, 0, "le valutazioni non sono azioni: nessun punto");