// Il blocco scoperto nella revisione finale del 22/08: il salvataggio del questionario e la // lettura dei punteggi esistono entrambi, ma fra i due non calcolava niente nessuno. // I test esistenti (referto.test.ts) chiamavano calcolaSessione/salvaScore dentro la propria // fixture — cioè facevano a mano ciò che in produzione non fa nessuno — quindi restavano // verdi anche con l'endpoint reale del tutto scollegato dal motore. // // Questo file parte dal modulo compilato (salvaDalForm, la stessa funzione che chiama // l'endpoint POST /api/longevity/questionario) e arriva al referto (refertoDi): NON chiama // mai calcolaSessione o salvaScore a mano. Se un domani qualcuno stacca di nuovo il // calcolo dal salvataggio, questo è il test che deve diventare rosso. import { describe, it, expect } from 'vitest'; import { createLongevityDb } from '../../src/lib/longevity/db'; import { seedRegistro, seedPesi, MODEL_VERSION } from '../../src/lib/longevity/registro'; import { salvaDalForm, refertoDi } from '../../src/lib/longevity/vista'; function dbPronto() { const db = createLongevityDb(':memory:'); seedRegistro(db); seedPesi(db, MODEL_VERSION); db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001','F')`).run(); return db; } describe('salvaDalForm calcola e congela i punteggi da solo', () => { it('venti risposte compilate producono un referto con assi e macro-score valorizzati, senza ricalcolo a mano', () => { const db = dbPronto(); const esito = salvaDalForm(db, { client_code: 'ISL-0001', data: '2026-08-22', eta: 35, risposte: { q_ore_sonno: 7.5, q_min_addorm: 15, q_risvegli: 0, q_riposato: 8, q_caffeina: 1, q_sonnolenza_diurna: 1, q_energia_media: 7, q_esaurimento: 0, q_calo_pomeridiano: 3, q_sopraffatto: 1, q_controllo: 8, q_sicurezza_gestione: 8, q_tensione: 1, q_pensieri_lavoro: 0.5, q_attivita: 5, q_alimentazione: 8, q_sigarette: 0, q_alcol_life: 2, q_luce: 2, q_schermi: 10, }, consensoSanitario: 'Si', liberi: {}, }); expect(esito.ok).toBe(true); if (!esito.ok) throw new Error(esito.errore); // Riprova diretta sulla tabella score: prima di questa correzione restava vuota, // perché nessuno chiamava calcolaSessione/salvaScore fra salvataggio e lettura. const righeScore = db.prepare(`SELECT COUNT(*) n FROM score WHERE sessione_id = ?`).get(esito.sessioneId) as { n: number }; expect(righeScore.n).toBeGreaterThan(0); const referto = refertoDi(db, esito.sessioneId); // 'Stile di Vita & Sonno' ha UN solo sotto-dominio (questionario_lifestyle, peso 1.00): // con tutte le risposte compilate la copertura è piena. const stile = referto.assi.find((a) => a.nome === 'Stile di Vita & Sonno')!; expect(stile.valore).not.toBeNull(); // 'Energia & Regolazione Stress' pesa hrv 0.50 + questionario_energia_stress 0.50: con // solo il questionario la copertura vera è 0.50, sopra la soglia del 40%. const energia = referto.assi.find((a) => a.nome === 'Energia & Regolazione Stress')!; expect(energia.valore).not.toBeNull(); const almenoUnMacro = referto.macro.some((m) => m.valore !== null); expect(almenoUnMacro).toBe(true); }); });