rating
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Tests for GetUserRatingsSummaryQuery
|
||||
*/
|
||||
|
||||
import { GetUserRatingsSummaryQuery, GetUserRatingsSummaryQueryHandler } from './GetUserRatingsSummaryQuery';
|
||||
import { UserRating } from '../../domain/value-objects/UserRating';
|
||||
import { ExternalGameRatingProfile } from '../../domain/entities/ExternalGameRatingProfile';
|
||||
import { GameKey } from '../../domain/value-objects/GameKey';
|
||||
import { ExternalRating } from '../../domain/value-objects/ExternalRating';
|
||||
import { ExternalRatingProvenance } from '../../domain/value-objects/ExternalRatingProvenance';
|
||||
import { RatingEvent } from '../../domain/entities/RatingEvent';
|
||||
import { RatingEventId } from '../../domain/value-objects/RatingEventId';
|
||||
import { RatingDimensionKey } from '../../domain/value-objects/RatingDimensionKey';
|
||||
import { RatingDelta } from '../../domain/value-objects/RatingDelta';
|
||||
|
||||
describe('GetUserRatingsSummaryQuery', () => {
|
||||
let mockUserRatingRepo: any;
|
||||
let mockExternalRatingRepo: any;
|
||||
let mockRatingEventRepo: any;
|
||||
let handler: GetUserRatingsSummaryQueryHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
mockUserRatingRepo = {
|
||||
findByUserId: jest.fn(),
|
||||
};
|
||||
mockExternalRatingRepo = {
|
||||
findByUserId: jest.fn(),
|
||||
};
|
||||
mockRatingEventRepo = {
|
||||
getAllByUserId: jest.fn(),
|
||||
};
|
||||
|
||||
handler = new GetUserRatingsSummaryQueryHandler(
|
||||
mockUserRatingRepo,
|
||||
mockExternalRatingRepo,
|
||||
mockRatingEventRepo
|
||||
);
|
||||
});
|
||||
|
||||
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: { toString: () => userId } as any,
|
||||
gameKey,
|
||||
ratings: new Map([
|
||||
['iRating', ExternalRating.create(gameKey, 'iRating', 2200)],
|
||||
['safetyRating', ExternalRating.create(gameKey, 'safetyRating', 4.5)],
|
||||
]),
|
||||
provenance: ExternalRatingProvenance.create('iRacing API', new Date()),
|
||||
});
|
||||
mockExternalRatingRepo.findByUserId.mockResolvedValue([profile]);
|
||||
|
||||
// Mock rating events
|
||||
const event = RatingEvent.create({
|
||||
id: RatingEventId.create(),
|
||||
userId,
|
||||
dimension: RatingDimensionKey.create('driver'),
|
||||
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: { toString: () => userId } as any,
|
||||
gameKey: GameKey.create('iracing'),
|
||||
ratings: new Map([
|
||||
['iRating', ExternalRating.create(GameKey.create('iracing'), 'iRating', 2200)],
|
||||
]),
|
||||
provenance: ExternalRatingProvenance.create('iRacing API', new Date()),
|
||||
});
|
||||
|
||||
const assettoProfile = ExternalGameRatingProfile.create({
|
||||
userId: { toString: () => userId } as any,
|
||||
gameKey: GameKey.create('assetto'),
|
||||
ratings: new Map([
|
||||
['rating', ExternalRating.create(GameKey.create('assetto'), 'rating', 85)],
|
||||
]),
|
||||
provenance: ExternalRatingProvenance.create('Assetto API', 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());
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user