Files
InsanityLab-web/apps/sito/tests/stress-index-analytics.test.ts
T
AdrianoDev 510d7ca4ec Struttura: il sito esistente si sposta sotto apps/sito
Primo passo della separazione sito / piattaforme decisa da Adriano il 03/09:
due applicazioni autosufficienti, senza workspace di root, cosi' che ognuna
resti un progetto Astro completo ed estraibile.

Qui non cambia niente del codice: solo la radice. I pattern del .gitignore
che avevano una barra erano ancorati alla radice e dopo lo spostamento non
avrebbero piu' coperto niente (data/*.db*, uploads/*): resi validi a
qualunque profondita'.

Suite: 45 file, 347 test verdi prima e dopo lo spostamento.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EndnceRA5WnA6rvA5iV9WL
2026-09-03 11:05:54 +00:00

103 lines
4.1 KiB
TypeScript

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<string, Measurement[]> = {
// 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 },
]);
});
});