Files
gridpilot.gg/core/identity/application/queries/GetUserRatingsSummaryQuery.test.ts
2026-01-16 19:46:49 +01:00

177 lines
7.3 KiB
TypeScript

/**
* Tests for GetUserRatingsSummaryQuery
*/
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import { ExternalGameRatingProfile } from '../../domain/entities/ExternalGameRatingProfile';
import { RatingEvent } from '../../domain/entities/RatingEvent';
import { ExternalGameRatingRepository } from '../../domain/repositories/ExternalGameRatingRepository';
import { RatingEventRepository } from '../../domain/repositories/RatingEventRepository';
import { UserRatingRepository } from '../../domain/repositories/UserRatingRepository';
import { ExternalRating } from '../../domain/value-objects/ExternalRating';
import { ExternalRatingProvenance } from '../../domain/value-objects/ExternalRatingProvenance';
import { GameKey } from '../../domain/value-objects/GameKey';
import { RatingDelta } from '../../domain/value-objects/RatingDelta';
import { RatingDimensionKey } from '../../domain/value-objects/RatingDimensionKey';
import { RatingEventId } from '../../domain/value-objects/RatingEventId';
import { UserRating } from '../../domain/value-objects/UserRating';
import { GetUserRatingsSummaryQuery, GetUserRatingsSummaryQueryHandler } from './GetUserRatingsSummaryQuery';
import { UserId } from '../../domain/value-objects/UserId';
describe('GetUserRatingsSummaryQuery', () => {
let mockUserRatingRepo: { findByUserId: Mock };
let mockExternalRatingRepo: { findByUserId: Mock };
let mockRatingEventRepo: { getAllByUserId: Mock };
let handler: GetUserRatingsSummaryQueryHandler;
beforeEach(() => {
mockUserRatingRepo = {
findByUserId: vi.fn(),
};
mockExternalRatingRepo = {
findByUserId: vi.fn(),
};
mockRatingEventRepo = {
getAllByUserId: vi.fn(),
};
handler = new GetUserRatingsSummaryQueryHandler(
mockUserRatingRepo as unknown as UserRatingRepository,
mockExternalRatingRepo as unknown as ExternalGameRatingRepository,
mockRatingEventRepo as unknown as RatingEventRepository
);
});
describe('execute', () => {
it('should return summary with platform and external ratings', async () => {
const userId = 'user-123';
// Mock user rating
const userRating = UserRating.create(userId);
mockUserRatingRepo.findByUserId.mockResolvedValue(userRating);
// Mock external ratings
const gameKey = GameKey.create('iracing');
const profile = ExternalGameRatingProfile.create({
userId: UserId.fromString(userId),
gameKey,
ratings: new Map([
['iRating', ExternalRating.create(gameKey, 'iRating', 2200)],
['safetyRating', ExternalRating.create(gameKey, 'safetyRating', 4.5)],
]),
provenance: ExternalRatingProvenance.create({ source: 'iRacing API', lastSyncedAt: new Date() }),
});
mockExternalRatingRepo.findByUserId.mockResolvedValue([profile]);
// Mock rating events
const event = RatingEvent.create({
id: RatingEventId.generate(),
userId,
dimension: RatingDimensionKey.create('driving'),
delta: RatingDelta.create(5),
occurredAt: new Date('2024-01-01'),
createdAt: new Date('2024-01-01'),
source: { type: 'race', id: 'race-123' },
reason: { code: 'RACE_FINISH', summary: 'Good race', details: {} },
visibility: { public: true, redactedFields: [] },
version: 1,
});
mockRatingEventRepo.getAllByUserId.mockResolvedValue([event]);
const query: GetUserRatingsSummaryQuery = { userId };
const result = await handler.execute(query);
expect(result.userId).toBe(userId);
expect(result.platform.driving.value).toBe(50); // Default
expect(result.platform.overallReputation).toBe(50);
expect(result.external.iracing?.iRating).toBe(2200);
expect(result.external.iracing?.safetyRating).toBe(4.5);
expect(result.lastRatingEventAt).toBe('2024-01-01T00:00:00.000Z');
});
it('should handle missing user rating gracefully', async () => {
const userId = 'user-123';
mockUserRatingRepo.findByUserId.mockResolvedValue(null);
mockExternalRatingRepo.findByUserId.mockResolvedValue([]);
mockRatingEventRepo.getAllByUserId.mockResolvedValue([]);
const query: GetUserRatingsSummaryQuery = { userId };
const result = await handler.execute(query);
expect(result.userId).toBe(userId);
expect(result.platform.driving.value).toBe(0);
expect(result.platform.overallReputation).toBe(0);
expect(result.external).toEqual({});
expect(result.lastRatingEventAt).toBeUndefined();
});
it('should handle multiple external game profiles', async () => {
const userId = 'user-123';
mockUserRatingRepo.findByUserId.mockResolvedValue(UserRating.create(userId));
// Multiple game profiles
const iracingProfile = ExternalGameRatingProfile.create({
userId: UserId.fromString(userId),
gameKey: GameKey.create('iracing'),
ratings: new Map([
['iRating', ExternalRating.create(GameKey.create('iracing'), 'iRating', 2200)],
]),
provenance: ExternalRatingProvenance.create({ source: 'iRacing API', lastSyncedAt: new Date() }),
});
const assettoProfile = ExternalGameRatingProfile.create({
userId: UserId.fromString(userId),
gameKey: GameKey.create('assetto'),
ratings: new Map([
['rating', ExternalRating.create(GameKey.create('assetto'), 'rating', 85)],
]),
provenance: ExternalRatingProvenance.create({ source: 'Assetto API', lastSyncedAt: new Date() }),
});
mockExternalRatingRepo.findByUserId.mockResolvedValue([iracingProfile, assettoProfile]);
mockRatingEventRepo.getAllByUserId.mockResolvedValue([]);
const query: GetUserRatingsSummaryQuery = { userId };
const result = await handler.execute(query);
expect(result.external.iracing.iRating).toBe(2200);
expect(result.external.assetto.rating).toBe(85);
});
it('should handle empty external ratings', async () => {
const userId = 'user-123';
mockUserRatingRepo.findByUserId.mockResolvedValue(UserRating.create(userId));
mockExternalRatingRepo.findByUserId.mockResolvedValue([]);
mockRatingEventRepo.getAllByUserId.mockResolvedValue([]);
const query: GetUserRatingsSummaryQuery = { userId };
const result = await handler.execute(query);
expect(result.external).toEqual({});
});
it('should use current date for timestamps when no user rating exists', async () => {
const userId = 'user-123';
mockUserRatingRepo.findByUserId.mockResolvedValue(null);
mockExternalRatingRepo.findByUserId.mockResolvedValue([]);
mockRatingEventRepo.getAllByUserId.mockResolvedValue([]);
const beforeQuery = new Date();
const query: GetUserRatingsSummaryQuery = { userId };
const result = await handler.execute(query);
const afterQuery = new Date();
// Should have valid ISO date strings
expect(new Date(result.createdAt).getTime()).toBeGreaterThanOrEqual(beforeQuery.getTime());
expect(new Date(result.createdAt).getTime()).toBeLessThanOrEqual(afterQuery.getTime());
expect(new Date(result.updatedAt).getTime()).toBeGreaterThanOrEqual(beforeQuery.getTime());
expect(new Date(result.updatedAt).getTime()).toBeLessThanOrEqual(afterQuery.getTime());
});
});
});