Files
InsanityLab-web/tests/longevity/export.test.ts
T
Adriano 763e5611e6 longevity: revisione finale - codice cliente non riusabile, ruoli allineati, middleware verificato
- creaCliente: il codice si deduce dal massimo fra identity E longevity (non piu' solo
  identity), cosi' un client_code cancellato dall'anagrafica non torna mai disponibile
  e non si attribuiscono le misure di un vecchio cliente a uno nuovo. Compensazione se
  la scrittura su longevity fallisce dopo quella su identity.
- ROLES unica fonte in auth.ts (Role e isRole derivati); users.astro e users/new.astro
  usano quella lista invece di array scritti a mano che dimenticavano cliente/trainer.
- Commento falso su cosa protegge il middleware, riscritto: rimanda a isProtectedPath.
- vitest.config.ts: alias per astro:middleware (stesso bersaglio della pipeline vite di
  Astro), cosi' src/middleware.ts e' finalmente importabile e testabile in isolamento -
  prima nessun test lo caricava davvero.
- export.test.ts: asserzione posizionale per colonna, non piu' solo intestazioni scritte
  a mano; intercetta un riordino della SELECT che disallinea etichette e valori.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 20:30:23 +02:00

86 lines
3.7 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { createLongevityDb } from '../../src/lib/longevity/db';
import { seedRegistro } from '../../src/lib/longevity/registro';
import { salvaCompilazione } from '../../src/lib/longevity/questionario';
import { esportaMisure, esportaCsv } from '../../src/lib/longevity/export';
function dbConDati() {
const db = createLongevityDb(':memory:');
seedRegistro(db);
db.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'F')`).run();
salvaCompilazione(db, {
client_code: 'ISL-0001', data: '2026-08-21', eta: 35,
risposte: { q_ore_sonno: 7, q_riposato: 8 },
liberi: { farmaci: 'nessuno' },
});
return db;
}
describe('export per le statistiche', () => {
it('esporta una riga per misura con codice, non con nome', () => {
const db = dbConDati();
const out = esportaMisure(db);
expect(out.intestazioni).toEqual(
['client_code', 'sesso', 'eta', 'data', 'tipo_sessione', 'quest_version', 'test_id', 'valore', 'unita', 'fonte', 'fuori_range']
);
expect(out.righe.length).toBe(2);
expect(out.righe[0][0]).toBe('ISL-0001');
});
it('l export non contiene campi identificativi', () => {
const db = dbConDati();
const testo = JSON.stringify(esportaMisure(db));
for (const vietato of ['nome', 'cognome', 'email', 'telefono', 'data_nascita']) {
expect(testo).not.toContain(vietato);
}
});
it('i campi liberi restano fuori dall export statistico', () => {
const db = dbConDati();
expect(JSON.stringify(esportaMisure(db))).not.toContain('nessuno');
});
it('produce un CSV con intestazione e una riga per misura', () => {
const db = dbConDati();
const righe = esportaCsv(db).trim().split('\n');
expect(righe.length).toBe(3); // intestazione + 2 misure
expect(righe[0]).toBe('client_code,sesso,eta,data,tipo_sessione,quest_version,test_id,valore,unita,fonte,fuori_range');
});
it('ogni valore sta sotto l intestazione giusta, colonna per colonna (asserzione posizionale)', () => {
// Non un indice scritto a mano: l'indice si cerca per NOME nell'intestazione prodotta.
// Se un domani la SELECT in export.ts viene riordinata senza riallineare INTESTAZIONI,
// il valore letto a quell'indice smette di corrispondere e l'asserzione fallisce -
// invece di restare verde con l'età etichettata come sesso.
const db = dbConDati();
const { intestazioni, righe } = esportaMisure(db);
const idx = (col: string) => {
const i = intestazioni.indexOf(col);
if (i < 0) throw new Error(`intestazione mancante: ${col}`);
return i;
};
const rigaSonno = righe.find((r) => r[idx('test_id')] === 'q_ore_sonno')!;
expect(rigaSonno).toBeDefined();
expect(rigaSonno[idx('client_code')]).toBe('ISL-0001');
expect(rigaSonno[idx('sesso')]).toBe('F');
expect(rigaSonno[idx('eta')]).toBe(35);
expect(rigaSonno[idx('data')]).toBe('2026-08-21');
expect(rigaSonno[idx('tipo_sessione')]).toBe('questionario');
expect(rigaSonno[idx('quest_version')]).toBe('v1.0');
expect(rigaSonno[idx('valore')]).toBe(7);
// salvaCompilazione non passa 'unita' per le risposte del questionario: resta null.
expect(rigaSonno[idx('unita')]).toBeNull();
expect(rigaSonno[idx('fonte')]).toBe('questionario');
expect(rigaSonno[idx('fuori_range')]).toBe(0);
const rigaRiposato = righe.find((r) => r[idx('test_id')] === 'q_riposato')!;
expect(rigaRiposato).toBeDefined();
expect(rigaRiposato[idx('client_code')]).toBe('ISL-0001');
expect(rigaRiposato[idx('sesso')]).toBe('F');
expect(rigaRiposato[idx('eta')]).toBe(35);
expect(rigaRiposato[idx('valore')]).toBe(8);
expect(rigaRiposato[idx('unita')]).toBeNull();
});
});