Estende bonifica-evento.test.ts a tutte e 9 le tabelle collegate

Il test copriva solo 3 delle 9 istruzioni DELETE dentro
bonifica_dati_evento_orfani() (risposte_presenze, mvp_voti,
pagelle_voti), lasciando cacche_partita, turni_palloni,
scout_sessioni, scout_live, scout_partite e badge_social_voti senza
verifica automatica. Ora inserisce una riga orfana in tutte e sei le
tabelle evento_id e una riga orfana più due storiche (Scout, CSI) in
tutte e tre le tabelle match_id, verificando la stessa distinzione
delicata su ciascuna, non solo su un sottoinsieme.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 10:37:01 +02:00
co-authored by Claude Sonnet 5
parent bef5542ce3
commit 8dfd81ebe4
+77 -62
View File
@@ -5,11 +5,16 @@
* di M14 (DD-029); M16 ha reso permanente la stessa logica come funzione RPC, così resta * di M14 (DD-029); M16 ha reso permanente la stessa logica come funzione RPC, così resta
* richiamabile e testabile invece che verificata a mano una volta sola. * richiamabile e testabile invece che verificata a mano una volta sola.
* *
* Il punto delicato: per `mvp_voti`/`pagelle_voti`/`badge_social_voti` la funzione deve * Copre tutte e nove le istruzioni dentro la funzione, non solo un sottoinsieme: le sei
* cancellare solo i `match_id` nel formato id evento CrAPP ("e" + timestamp base36) senza * tabelle che usano `evento_id` (`risposte_presenze`, `cacche_partita`, `turni_palloni`,
* corrispondenza in `eventi_app` — mai i vecchi voti storici su id Scout ("s" + timestamp) o * `scout_sessioni`, `scout_live`, `scout_partite`) e le tre che usano `match_id`
* CSI (numerico), che sono dati legittimi mai collegati a un evento CrAPP (`docs/modules/mvp.md`). * (`mvp_voti`, `pagelle_voti`, `badge_social_voti`).
* Questo test copre esattamente quella distinzione. *
* Il punto delicato è sulle tre tabelle `match_id`: la funzione deve cancellare solo i
* `match_id` nel formato id evento CrAPP ("e" + timestamp base36) senza corrispondenza in
* `eventi_app` — mai i vecchi voti storici su id Scout ("s" + timestamp) o CSI (numerico),
* che sono dati legittimi mai collegati a un evento CrAPP (`docs/modules/mvp.md`). Questo
* test verifica la distinzione su tutte e tre, non solo su due delle tre.
* *
* Gira solo sullo stack locale (`npx supabase start`): usa id con il prefisso * Gira solo sullo stack locale (`npx supabase start`): usa id con il prefisso
* `test-bonifica-evento`, che nessun dato vero può avere. * `test-bonifica-evento`, che nessun dato vero può avere.
@@ -32,7 +37,17 @@ if (!locale) {
// verrebbe mai filtrato dalla funzione, quindi non testerebbe la regola che conta. // verrebbe mai filtrato dalla funzione, quindi non testerebbe la regola che conta.
const ORFANO = `etestbonificaevento${Date.now().toString(36)}`; const ORFANO = `etestbonificaevento${Date.now().toString(36)}`;
const STORICO_SCOUT = `s${Date.now()}`; // formato id Scout storico: va preservato const STORICO_SCOUT = `s${Date.now()}`; // formato id Scout storico: va preservato
const STORICO_CSI = "42"; // formato id CSI storico (numerico): va preservato const STORICO_CSI = `${Date.now()}`; // formato id CSI storico (numerico): va preservato
const TABELLE_EVENTO_ID = [
"risposte_presenze",
"cacche_partita",
"turni_palloni",
"scout_sessioni",
"scout_live",
"scout_partite",
];
const TABELLE_MATCH_ID = ["mvp_voti", "pagelle_voti", "badge_social_voti"];
const rest = (percorso: string, init?: RequestInit) => const rest = (percorso: string, init?: RequestInit) =>
fetch(`${URL_BASE}/rest/v1/${percorso}`, { fetch(`${URL_BASE}/rest/v1/${percorso}`, {
@@ -59,51 +74,60 @@ if (!locale) {
} }
async function pulisci() { async function pulisci() {
await rest(`risposte_presenze?evento_id=eq.${ORFANO}`, { method: "DELETE" }); for (const t of TABELLE_EVENTO_ID) {
await rest(`mvp_voti?match_id=eq.${ORFANO}`, { method: "DELETE" }); await rest(`${t}?evento_id=eq.${ORFANO}`, { method: "DELETE" });
await rest(`mvp_voti?match_id=eq.${STORICO_SCOUT}`, { method: "DELETE" }); }
await rest(`pagelle_voti?match_id=eq.${ORFANO}`, { method: "DELETE" }); for (const t of TABELLE_MATCH_ID) {
await rest(`pagelle_voti?match_id=eq.${STORICO_CSI}&votante_id=eq.${PREFISSO}-va`, { await rest(`${t}?match_id=eq.${ORFANO}`, { method: "DELETE" });
method: "DELETE", await rest(`${t}?match_id=eq.${STORICO_SCOUT}`, { method: "DELETE" });
}); await rest(`${t}?match_id=eq.${STORICO_CSI}`, { method: "DELETE" });
}
} }
try { try {
await prova( await prova(
"bonifica_dati_evento_orfani() rimuove solo gli orfani veri, non lo storico Scout/CSI", "bonifica_dati_evento_orfani() rimuove solo gli orfani veri, non lo storico Scout/CSI",
async () => { async () => {
// Riga orfana: id in formato evento CrAPP, nessun evento corrispondente. // Una riga orfana per ciascuna delle sei tabelle evento_id.
await inserisci("risposte_presenze", { await inserisci("risposte_presenze", {
evento_id: ORFANO, evento_id: ORFANO,
giocatore_id: `${PREFISSO}-g1`, giocatore_id: `${PREFISSO}-g1`,
stato: "presente", stato: "presente",
}); });
await inserisci("mvp_voti", { await inserisci("cacche_partita", {
match_id: ORFANO, evento_id: ORFANO,
votante_id: `${PREFISSO}-va`, giocatore_id: `${PREFISSO}-g1`,
votato_id: `${PREFISSO}-vb`, quantita: 1,
votato_nome: "Orfano",
}); });
await inserisci("pagelle_voti", { await inserisci("turni_palloni", { evento_id: ORFANO, giocatore_id: `${PREFISSO}-g1` });
match_id: ORFANO, await inserisci("scout_sessioni", {
votante_id: `${PREFISSO}-va`, evento_id: ORFANO,
votato_id: `${PREFISSO}-vb`, giocatore_id: `${PREFISSO}-g1`,
voto: 6, giocatore_nome: "Uno",
});
await inserisci("scout_live", { evento_id: ORFANO, stato: {} });
await inserisci("scout_partite", {
id: `${ORFANO}-scout`,
evento_id: ORFANO,
data: "2026-09-01",
avversario: "Test",
set_nostri: 3,
set_loro: 0,
}); });
// Voti storici legittimi su id Scout/CSI: nessun evento CrAPP li ha mai referenziati. // Una riga orfana + due storiche (Scout, CSI) per ciascuna delle tre tabelle match_id.
await inserisci("mvp_voti", { for (const t of TABELLE_MATCH_ID) {
match_id: STORICO_SCOUT, const base = { votante_id: `${PREFISSO}-va`, votato_id: `${PREFISSO}-vb` };
votante_id: `${PREFISSO}-va`, const extra =
votato_id: `${PREFISSO}-vb`, t === "pagelle_voti"
votato_nome: "Storico", ? { voto: 7 }
}); : t === "badge_social_voti"
await inserisci("pagelle_voti", { ? { categoria: "top", votato_nome: "Test" }
match_id: STORICO_CSI, : { votato_nome: "Test" };
votante_id: `${PREFISSO}-va`, await inserisci(t, { match_id: ORFANO, ...base, ...extra });
votato_id: `${PREFISSO}-vb`, await inserisci(t, { match_id: STORICO_SCOUT, ...base, ...extra });
voto: 8, await inserisci(t, { match_id: STORICO_CSI, ...base, ...extra });
}); }
const res = await fetch(`${URL_BASE}/rest/v1/rpc/bonifica_dati_evento_orfani`, { const res = await fetch(`${URL_BASE}/rest/v1/rpc/bonifica_dati_evento_orfani`, {
method: "POST", method: "POST",
@@ -117,31 +141,22 @@ if (!locale) {
if (!res.ok) if (!res.ok)
throw new Error(`rpc bonifica_dati_evento_orfani: ${res.status} ${await res.text()}`); throw new Error(`rpc bonifica_dati_evento_orfani: ${res.status} ${await res.text()}`);
assert.equal( for (const t of TABELLE_EVENTO_ID) {
await esiste("risposte_presenze", `evento_id=eq.${ORFANO}`), assert.equal(await esiste(t, `evento_id=eq.${ORFANO}`), false, `${t}: orfano rimosso`);
false, }
"riga orfana rimossa", for (const t of TABELLE_MATCH_ID) {
); assert.equal(await esiste(t, `match_id=eq.${ORFANO}`), false, `${t}: orfano rimosso`);
assert.equal( assert.equal(
await esiste("mvp_voti", `match_id=eq.${ORFANO}`), await esiste(t, `match_id=eq.${STORICO_SCOUT}`),
false, true,
"voto MVP orfano rimosso", `${t}: storico Scout preservato`,
); );
assert.equal( assert.equal(
await esiste("pagelle_voti", `match_id=eq.${ORFANO}`), await esiste(t, `match_id=eq.${STORICO_CSI}`),
false, true,
"voto pagella orfano rimosso", `${t}: storico CSI preservato`,
); );
assert.equal( }
await esiste("mvp_voti", `match_id=eq.${STORICO_SCOUT}`),
true,
"voto MVP storico su id Scout preservato",
);
assert.equal(
await esiste("pagelle_voti", `match_id=eq.${STORICO_CSI}`),
true,
"voto pagella storico su id CSI preservato",
);
}, },
); );
} finally { } finally {