import { describe, it, expect } from 'vitest'; import { fascia, misurazioniNelPeriodo, kpis, distribuzione, classificaRecupero, confrontoSegmenti, } from '../src/lib/stress-index/analytics'; import type { Alert, Client, Measurement } from '../src/lib/stress-index/data'; const PERIODO = { from: '2026-07-01', to: '2026-07-31' }; const misura = (date: string, stress: number, recovery: number): Measurement => ({ date, stress, recovery, balance: 50, energy: 50, type: 'Riposo', durationMin: 20 }); const cliente = (id: string, name: string, sex: 'M' | 'F', age: number): Client => ({ id, name, initials: 'XX', age, sex, tags: ['test'], email: `${id}@esempio.it`, since: '2024-01-01', lastMeasurement: '2026-07-10', stress: 50, alerts: 0 }); const clients = [cliente('a', 'A. Uno', 'M', 30), cliente('b', 'B. Due', 'F', 55), cliente('c', 'C. Tre', 'F', 40)]; const byClient: Record = { // dentro il periodo a: [misura('2026-07-05', 10, 90), misura('2026-07-12', 30, 70)], // una dentro, una fuori b: [misura('2026-06-20', 80, 20), misura('2026-07-20', 90, 30)], // tutte fuori periodo c: [misura('2026-05-01', 50, 50)], }; const alerts: Alert[] = [ { clientId: 'a', clientName: 'A. Uno', text: 'x', severity: 'warn', when: '2026-07-03' }, { clientId: 'b', clientName: 'B. Due', text: 'y', severity: 'error', when: '2026-06-01' }, ]; describe('fasce di score', () => { it('assegna gli estremi alla fascia giusta', () => { expect(fascia(0)).toBe('0-20'); expect(fascia(20)).toBe('0-20'); expect(fascia(21)).toBe('21-40'); expect(fascia(60)).toBe('41-60'); expect(fascia(81)).toBe('81-100'); expect(fascia(100)).toBe('81-100'); }); }); describe('filtro sul periodo', () => { it('tiene solo le misurazioni comprese fra le due date, estremi inclusi', () => { const dentro = misurazioniNelPeriodo(byClient, PERIODO); expect(dentro.a.map((m) => m.date)).toEqual(['2026-07-05', '2026-07-12']); expect(dentro.b.map((m) => m.date)).toEqual(['2026-07-20']); expect(dentro.c).toEqual([]); }); }); describe('kpi', () => { it('conta clienti attivi, misurazioni, alert del periodo e aderenza', () => { expect(kpis(clients, byClient, alerts, PERIODO)).toEqual([ { label: 'Clienti attivi', value: 2, note: '/ 3 totali' }, { label: 'Misurazioni', value: 3, note: 'nel periodo' }, { label: 'Alert attivi', value: 1, note: 'nel periodo' }, { label: 'Aderenza', value: '67%', note: 'hanno misurato' }, ]); }); }); describe('distribuzione per fascia', () => { it('conta ogni metrica nella propria fascia', () => { const righe = distribuzione(byClient, PERIODO); const perFascia = Object.fromEntries(righe.map((r) => [r.range, r])); // stress: 10 → 0-20, 30 → 21-40, 90 → 81-100 expect(perFascia['0-20'].stress).toBe(1); expect(perFascia['21-40'].stress).toBe(1); expect(perFascia['81-100'].stress).toBe(1); // recovery: 90 → 81-100, 70 → 61-80, 30 → 21-40 expect(perFascia['81-100'].recovery).toBe(1); expect(perFascia['61-80'].recovery).toBe(1); expect(perFascia['21-40'].recovery).toBe(1); // le tre misurazioni hanno tutte balance ed energy a 50 expect(perFascia['41-60'].balance).toBe(3); expect(perFascia['41-60'].energy).toBe(3); }); }); describe('classifica per recupero', () => { it('ordina dal recupero medio più alto e ignora chi non ha misurato', () => { expect(classificaRecupero(clients, byClient, PERIODO)).toEqual([ { clientId: 'a', name: 'A. Uno', recovery: 80, count: 2 }, { clientId: 'b', name: 'B. Due', recovery: 30, count: 1 }, ]); }); }); describe('confronto segmenti', () => { it('media stress e recupero per sesso', () => { expect(confrontoSegmenti(clients, byClient, PERIODO, 'sesso')).toEqual([ { gruppo: 'Uomini', stress: 20, recovery: 80 }, { gruppo: 'Donne', stress: 90, recovery: 30 }, ]); }); it('raggruppa per fascia di età', () => { expect(confrontoSegmenti(clients, byClient, PERIODO, 'eta')).toEqual([ { gruppo: 'Fino a 34', stress: 20, recovery: 80 }, { gruppo: '50 e oltre', stress: 90, recovery: 30 }, ]); }); });