Files
gridpilot.gg/apps/api/src/domain/analytics/AnalyticsController.test.ts
2025-12-21 22:35:38 +01:00

113 lines
3.8 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { vi } from 'vitest';
import { AnalyticsController } from './AnalyticsController';
import { AnalyticsService } from './AnalyticsService';
import type { Response } from 'express';
import { EntityType, VisitorType } from '@core/analytics/domain/types/PageView';
import { EngagementAction, EngagementEntityType } from '@core/analytics/domain/types/EngagementEvent';
import type { RecordEngagementOutputDTO } from './dtos/RecordEngagementOutputDTO';
import type { RecordPageViewOutputDTO } from './dtos/RecordPageViewOutputDTO';
describe('AnalyticsController', () => {
let controller: AnalyticsController;
let service: ReturnType<typeof vi.mocked<AnalyticsService>>;
beforeEach(() => {
service = {
recordPageView: vi.fn(),
recordEngagement: vi.fn(),
getDashboardData: vi.fn(),
getAnalyticsMetrics: vi.fn(),
} as any;
controller = new AnalyticsController(service);
});
describe('recordPageView', () => {
it('should record a page view and return 201', async () => {
const input = {
entityType: EntityType.RACE,
entityId: 'race-123',
visitorType: VisitorType.ANONYMOUS,
sessionId: 'session-456',
visitorId: 'visitor-789',
referrer: 'https://example.com',
userAgent: 'Mozilla/5.0',
country: 'US',
};
const dto: RecordPageViewOutputDTO = { pageViewId: 'pv-123' };
service.recordPageView.mockResolvedValue(dto);
const mockRes: ReturnType<typeof vi.mocked<Response>> = {
status: vi.fn().mockReturnThis(),
json: vi.fn(),
} as unknown as ReturnType<typeof vi.mocked<Response>>;
await controller.recordPageView(input, mockRes);
expect(service.recordPageView).toHaveBeenCalledWith(input);
expect(mockRes.status).toHaveBeenCalledWith(201);
expect(mockRes.json).toHaveBeenCalledWith(dto);
});
});
describe('recordEngagement', () => {
it('should record an engagement and return 201', async () => {
const input = {
action: EngagementAction.CLICK_SPONSOR_LOGO,
entityType: EngagementEntityType.RACE,
entityId: 'race-123',
actorType: 'driver' as const,
sessionId: 'session-456',
actorId: 'actor-789',
metadata: { key: 'value' },
};
const dto: RecordEngagementOutputDTO = { eventId: 'event-123', engagementWeight: 10 };
service.recordEngagement.mockResolvedValue(dto);
const mockRes: ReturnType<typeof vi.mocked<Response>> = {
status: vi.fn().mockReturnThis(),
json: vi.fn(),
} as unknown as ReturnType<typeof vi.mocked<Response>>;
await controller.recordEngagement(input, mockRes);
expect(service.recordEngagement).toHaveBeenCalledWith(input);
expect(mockRes.status).toHaveBeenCalledWith(201);
expect(mockRes.json).toHaveBeenCalledWith(dto);
});
});
describe('getDashboardData', () => {
it('should return dashboard data', async () => {
const dto = {
totalUsers: 100,
activeUsers: 50,
totalRaces: 20,
totalLeagues: 5,
};
service.getDashboardData.mockResolvedValue(dto);
const result = await controller.getDashboardData();
expect(service.getDashboardData).toHaveBeenCalled();
expect(result).toEqual(dto);
});
});
describe('getAnalyticsMetrics', () => {
it('should return analytics metrics', async () => {
const dto = {
pageViews: 1000,
uniqueVisitors: 500,
averageSessionDuration: 300,
bounceRate: 0.4,
};
service.getAnalyticsMetrics.mockResolvedValue(dto);
const result = await controller.getAnalyticsMetrics();
expect(service.getAnalyticsMetrics).toHaveBeenCalled();
expect(result).toEqual(dto);
});
});
});