import {buildMetricInsights} from '../insights/metricInsights'; import type {StoredMeasurement} from '../storage/storageTypes'; import {makeProcessingResult} from './syntheticMeasurements'; const stored = (index: number, bpm: number, rmssd: number): StoredMeasurement => ({ schemaVersion: 1, algorithmVersion: 'test', acquisition: {cameraPosition: 'front', torchUsed: false}, id: `stored-${index}`, measuredAt: new Date(Date.UTC(2026, 6, index + 1, 8)).toISOString(), atRest: true, baselineEligible: true, cameraResult: makeProcessingResult({ bpm: {...makeProcessingResult().bpm, bpm}, prv: {...makeProcessingResult().prv, estimatedRmssdMs: rmssd}, }), potentialStress: { index: null, status: 'baselineBuilding', confidence: 0, bpmContribution: null, prvContribution: null, signalQuality: 0.9, baselineMeasurementCount: 0, healthKitUsedForScore: false, limitations: [], }, healthKitContext: null, selfReport: null, }); describe('buildMetricInsights', () => { it('uses real historical measurements and creates personal ranges after five values', () => { const history = [ stored(0, 70, 40), stored(1, 71, 41), stored(2, 69, 39), stored(3, 72, 42), stored(4, 70, 40), ]; const insights = buildMetricInsights(history[4]!.cameraResult, history); const bpm = insights.find(insight => insight.key === 'bpm'); const rmssd = insights.find(insight => insight.key === 'rmssd'); expect(bpm?.trend).toHaveLength(5); expect(bpm?.referenceRange).not.toBeNull(); expect(bpm?.status).toBe('Dans votre repère habituel'); expect(rmssd?.trend.map(point => point.value)).toEqual([40, 41, 39, 42, 40]); }); it('never publishes PRV insights when the current PRV is unreliable', () => { const current = makeProcessingResult({ prv: {...makeProcessingResult().prv, reliable: false}, }); const insights = buildMetricInsights(current, []); expect(insights.find(insight => insight.key === 'bpm')?.value).toBe(72); expect(insights.find(insight => insight.key === 'rmssd')?.value).toBeNull(); expect(insights.find(insight => insight.key === 'rmssd')?.status).toBe( 'Signal insuffisant', ); }); });