import { describe, it, expect, vi, Mocked } from 'vitest'; import { AnalyticsService } from './AnalyticsService'; import { AnalyticsApiClient } from '@/lib/api/analytics/AnalyticsApiClient'; import { RecordPageViewOutputViewModel } from '@/lib/view-models/RecordPageViewOutputViewModel'; import { RecordEngagementOutputViewModel } from '@/lib/view-models/RecordEngagementOutputViewModel'; describe('AnalyticsService', () => { let mockApiClient: Mocked; let service: AnalyticsService; beforeEach(() => { mockApiClient = { recordPageView: vi.fn(), recordEngagement: vi.fn(), } as Mocked; service = new AnalyticsService(mockApiClient); }); describe('recordPageView', () => { it('should call apiClient.recordPageView with correct input', async () => { const input = { path: '/dashboard', userId: 'user-123', }; const expectedOutput = { pageViewId: 'pv-123' }; mockApiClient.recordPageView.mockResolvedValue(expectedOutput); const result = await service.recordPageView(input); expect(mockApiClient.recordPageView).toHaveBeenCalledWith({ entityType: 'page', entityId: '/dashboard', visitorType: 'user', sessionId: 'temp-session', path: '/dashboard', userId: 'user-123', }); expect(result).toBeInstanceOf(RecordPageViewOutputViewModel); expect(result.pageViewId).toEqual('pv-123'); }); it('should call apiClient.recordPageView without userId when not provided', async () => { const input = { path: '/home', }; const expectedOutput = { pageViewId: 'pv-456' }; mockApiClient.recordPageView.mockResolvedValue(expectedOutput); const result = await service.recordPageView(input); expect(mockApiClient.recordPageView).toHaveBeenCalledWith({ entityType: 'page', entityId: '/home', visitorType: 'guest', sessionId: 'temp-session', path: '/home', }); expect(result).toBeInstanceOf(RecordPageViewOutputViewModel); expect(result.pageViewId).toEqual('pv-456'); }); }); describe('recordEngagement', () => { it('should call apiClient.recordEngagement with correct input', async () => { const input = { eventType: 'button_click', userId: 'user-123', metadata: { buttonId: 'submit', page: '/form' }, }; const expectedOutput = { eventId: 'event-123', engagementWeight: 1.5 }; mockApiClient.recordEngagement.mockResolvedValue(expectedOutput); const result = await service.recordEngagement(input); expect(mockApiClient.recordEngagement).toHaveBeenCalledWith({ action: 'button_click', entityType: 'ui_element', entityId: 'unknown', actorType: 'user', sessionId: 'temp-session', eventType: 'button_click', userId: 'user-123', metadata: { buttonId: 'submit', page: '/form' }, }); expect(result).toBeInstanceOf(RecordEngagementOutputViewModel); expect(result.eventId).toEqual('event-123'); expect(result.engagementWeight).toEqual(1.5); }); it('should call apiClient.recordEngagement without optional fields', async () => { const input = { eventType: 'page_load', }; const expectedOutput = { eventId: 'event-456', engagementWeight: 0.5 }; mockApiClient.recordEngagement.mockResolvedValue(expectedOutput); const result = await service.recordEngagement(input); expect(mockApiClient.recordEngagement).toHaveBeenCalledWith({ action: 'page_load', entityType: 'ui_element', entityId: 'unknown', actorType: 'guest', sessionId: 'temp-session', eventType: 'page_load', }); expect(result).toBeInstanceOf(RecordEngagementOutputViewModel); expect(result.eventId).toEqual('event-456'); expect(result.engagementWeight).toEqual(0.5); }); }); });