import { AnalyticsSnapshot, type SnapshotEntityType, type SnapshotPeriod } from '@core/analytics/domain/entities/AnalyticsSnapshot'; describe('AnalyticsSnapshot', () => { const startDate = new Date('2025-01-01T12:00:00.000Z'); const endDate = new Date('2025-01-02T12:00:00.000Z'); const validMetrics = { pageViews: 10, uniqueVisitors: 3, avgSessionDuration: 180_000, bounceRate: 25, engagementScore: 60, sponsorClicks: 2, sponsorUrlClicks: 1, socialShares: 4, leagueJoins: 0, raceRegistrations: 0, exposureValue: 0, }; const createValid = (overrides?: Partial[0]>) => { return AnalyticsSnapshot.create({ id: 'snapshot-1', entityType: 'league', entityId: 'entity_123', period: 'monthly', startDate, endDate, metrics: validMetrics, ...overrides, }); }; it('creates a snapshot with trimmed entityId', () => { const snapshot = createValid({ entityId: ' entity_456 ' }); expect(snapshot.entityId).toBe('entity_456'); }); it('throws if id is missing', () => { expect(() => createValid({ id: '' })).toThrow(Error); expect(() => createValid({ id: ' ' })).toThrow(Error); }); it('throws if entityType is missing', () => { expect(() => createValid({ entityType: undefined as unknown as SnapshotEntityType })).toThrow(Error); }); it('throws if entityId is missing', () => { expect(() => createValid({ entityId: '' })).toThrow(Error); expect(() => createValid({ entityId: ' ' })).toThrow(Error); }); it('throws if period is missing', () => { expect(() => createValid({ period: undefined as unknown as SnapshotPeriod })).toThrow(Error); }); it('throws if endDate is before startDate', () => { expect(() => createValid({ startDate: endDate, endDate: startDate })).toThrow(Error); }); it('createEmpty initializes metrics to zero', () => { const snapshot = AnalyticsSnapshot.createEmpty( 'snapshot-empty', 'league', 'entity_1', 'weekly', startDate, endDate, ); expect(snapshot.metrics.pageViews).toBe(0); expect(snapshot.metrics.uniqueVisitors).toBe(0); expect(snapshot.metrics.sponsorClicks).toBe(0); expect(snapshot.metrics.sponsorUrlClicks).toBe(0); expect(snapshot.metrics.socialShares).toBe(0); }); it('calculates exposure score using weighted metrics', () => { const snapshot = createValid({ metrics: { ...validMetrics, pageViews: 10, uniqueVisitors: 3, sponsorClicks: 2, sponsorUrlClicks: 1, socialShares: 4, }, }); expect(snapshot.calculateExposureScore()).toBe(81); }); it('returns trust indicator high/medium/low based on thresholds', () => { expect( createValid({ metrics: { ...validMetrics, bounceRate: 25, avgSessionDuration: 180_000, engagementScore: 60 }, }).getTrustIndicator(), ).toBe('high'); expect( createValid({ metrics: { ...validMetrics, bounceRate: 50, avgSessionDuration: 60_000, engagementScore: 30 }, }).getTrustIndicator(), ).toBe('medium'); expect( createValid({ metrics: { ...validMetrics, bounceRate: 90, avgSessionDuration: 10_000, engagementScore: 0 }, }).getTrustIndicator(), ).toBe('low'); }); it('formats period labels (monthly includes year)', () => { expect(createValid({ period: 'monthly' }).getPeriodLabel()).toBe('Jan 1, 2025 - Jan 2, 2025'); expect(createValid({ period: 'weekly' }).getPeriodLabel()).toBe('Jan 1 - Jan 2'); }); });