// Issue #12: la correzione di un check-up passa dalla stessa API di salvaCheckup, distinta // da un sessione_id nel form. File separato da gestionale.test.ts apposta: l'endpoint usa il // singleton getLongevityDb() (db.ts), e gestionale.test.ts ha già un test (apriFascicolo) // che lo inizializza — nello stesso file la variabile d'ambiente impostata qui arriverebbe // troppo tardi. Stesso trucco di questionario-pagina.test.ts: LONGEVITY_DB_PATH va impostata // PRIMA che il singleton apra il suo longevity.db. Il setup usa lo STESSO getLongevityDb() // che poi chiamerà POST (una sola connessione, non due sullo stesso file): così si può // chiuderla nel finally, altrimenti rmSync fallisce con EPERM su Windows a handle aperto. import { describe, it, expect } from 'vitest'; import { mkdtempSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { getLongevityDb } from '../../src/lib/longevity/db'; import { seedRegistro, seedPesi, MODEL_VERSION } from '../../src/lib/longevity/registro'; import { salvaCheckup } from '../../src/lib/longevity/gestionale'; describe('API checkup.ts, correzione (#12): il client_code del redirect e delle validazioni viene sempre dalla sessione', () => { it('un sessione_id di un altro cliente rispetto al client_code del form: errore, niente scritto', async () => { const dir = mkdtempSync(join(tmpdir(), 'lg-api-checkup-test-')); const lgPath = join(dir, 'longevity.db'); const primaLg = process.env.LONGEVITY_DB_PATH; let lg: ReturnType | undefined; try { process.env.LONGEVITY_DB_PATH = lgPath; lg = getLongevityDb(); seedRegistro(lg); seedPesi(lg, MODEL_VERSION); lg.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0001', 'F')`).run(); lg.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES ('ISL-0002', 'M')`).run(); const esito = salvaCheckup(lg, { client_code: 'ISL-0001', data: '2026-09-26', eta: 38, operatore: 'nicola', misure: [{ test_id: 'f_peso_kg', valore_num: 80 }], }); expect(esito.ok).toBe(true); if (!esito.ok) throw new Error(esito.errore); const { POST } = await import('../../src/pages/api/longevity/gestionale/checkup'); const form = new FormData(); form.set('sessione_id', String(esito.sessioneId)); form.set('client_code', 'ISL-0002'); // la sessione è di ISL-0001: incoerente form.set('data', '2026-09-26'); form.set('f_peso_kg', '999'); // se scrivesse, sarebbe questo il valore const richiesta = new Request('http://localhost/api/longevity/gestionale/checkup', { method: 'POST', body: form }); const res = await POST({ request: richiesta, locals: { user: { username: 'donata' } } } as any); expect(res.status).toBe(303); expect(res.headers.get('Location')).toMatch(/^\/longevity\/gestionale\/cliente\/ISL-0001\?/); // redirect sul cliente VERO, non su quello del form expect(res.headers.get('Location')).toMatch(/errore=/); const riga = lg.prepare( `SELECT valore_num FROM misure WHERE sessione_id = ? AND test_id = 'f_peso_kg'` ).get(esito.sessioneId) as { valore_num: number }; expect(riga.valore_num).toBe(80); // invariato: nessuna scrittura } finally { lg?.close(); // libera l'handle sul file: senza, rmSync fallisce con EPERM su Windows if (primaLg === undefined) delete process.env.LONGEVITY_DB_PATH; else process.env.LONGEVITY_DB_PATH = primaLg; rmSync(dir, { recursive: true, force: true }); } }); });