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

129 lines
4.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { RatingEvent } from '../../domain/entities/RatingEvent';
import { RatingEventRepository } from '../../domain/repositories/RatingEventRepository';
import { UserRatingRepository } from '../../domain/repositories/UserRatingRepository';
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 { RecomputeUserRatingSnapshotUseCase } from './RecomputeUserRatingSnapshotUseCase';
describe('RecomputeUserRatingSnapshotUseCase', () => {
let mockEventRepo: Partial<RatingEventRepository>;
let mockRatingRepo: Partial<UserRatingRepository>;
beforeEach(() => {
mockEventRepo = {
getAllByUserId: vi.fn().mockResolvedValue([]),
};
mockRatingRepo = {
save: vi.fn(),
};
});
it('should be constructed with repositories', () => {
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
expect(useCase).toBeInstanceOf(RecomputeUserRatingSnapshotUseCase);
});
it('should compute snapshot from empty event list', async () => {
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
expect(result.snapshot.userId).toBe('user-1');
expect(result.snapshot.driver.value).toBe(50); // Default
expect(mockEventRepo.getAllByUserId).toHaveBeenCalledWith('user-1');
expect(mockRatingRepo.save).toHaveBeenCalled();
});
it('should compute snapshot from events', async () => {
const events = [
RatingEvent.create({
id: RatingEventId.generate(),
userId: 'user-1',
dimension: RatingDimensionKey.create('driving'),
delta: RatingDelta.create(5),
occurredAt: new Date('2024-01-01T10:00:00Z'),
createdAt: new Date('2024-01-01T10:00:00Z'),
source: { type: 'race', id: 'race-1' },
reason: { code: 'TEST', summary: 'Test', details: {} },
visibility: { public: true, redactedFields: [] },
version: 1,
}),
];
mockEventRepo.getAllByUserId = vi.fn().mockResolvedValue(events);
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
expect(result.snapshot.userId).toBe('user-1');
expect(result.snapshot.driver.value).toBeGreaterThan(50); // Should have increased
expect(mockEventRepo.getAllByUserId).toHaveBeenCalledWith('user-1');
expect(mockRatingRepo.save).toHaveBeenCalled();
});
it('should return proper DTO format', async () => {
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
// Check DTO structure
expect(result.snapshot).toHaveProperty('userId');
expect(result.snapshot).toHaveProperty('driver');
expect(result.snapshot).toHaveProperty('admin');
expect(result.snapshot).toHaveProperty('steward');
expect(result.snapshot).toHaveProperty('trust');
expect(result.snapshot).toHaveProperty('fairness');
expect(result.snapshot).toHaveProperty('overallReputation');
expect(result.snapshot).toHaveProperty('createdAt');
expect(result.snapshot).toHaveProperty('updatedAt');
// Check dimension structure
expect(result.snapshot.driver).toEqual({
value: expect.any(Number),
confidence: expect.any(Number),
sampleSize: expect.any(Number),
trend: expect.any(String),
lastUpdated: expect.any(String),
});
// Check dates are ISO strings
expect(result.snapshot.createdAt).toMatch(/^\d{4}-\d{2}-\d{2}T/);
expect(result.snapshot.updatedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/);
});
it('should handle calculatorVersion in DTO', async () => {
// Create a rating with calculatorVersion
const rating = UserRating.create('user-1');
const updated = rating.updateDriverRating(75);
mockRatingRepo.save = vi.fn().mockResolvedValue(updated);
const useCase = new RecomputeUserRatingSnapshotUseCase(
mockEventRepo as RatingEventRepository,
mockRatingRepo as UserRatingRepository,
);
const result = await useCase.execute({ userId: 'user-1' });
// Should have calculatorVersion
expect(result.snapshot.calculatorVersion).toBeDefined();
});
});