129 lines
4.8 KiB
TypeScript
129 lines
4.8 KiB
TypeScript
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
|
|
import { RecomputeUserRatingSnapshotUseCase } from './RecomputeUserRatingSnapshotUseCase';
|
|
import { IRatingEventRepository } from '../../domain/repositories/IRatingEventRepository';
|
|
import { IUserRatingRepository } from '../../domain/repositories/IUserRatingRepository';
|
|
import { UserRating } from '../../domain/value-objects/UserRating';
|
|
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('RecomputeUserRatingSnapshotUseCase', () => {
|
|
let mockEventRepo: Partial<IRatingEventRepository>;
|
|
let mockRatingRepo: Partial<IUserRatingRepository>;
|
|
|
|
beforeEach(() => {
|
|
mockEventRepo = {
|
|
getAllByUserId: vi.fn().mockResolvedValue([]),
|
|
};
|
|
|
|
mockRatingRepo = {
|
|
save: vi.fn(),
|
|
};
|
|
});
|
|
|
|
it('should be constructed with repositories', () => {
|
|
const useCase = new RecomputeUserRatingSnapshotUseCase(
|
|
mockEventRepo as IRatingEventRepository,
|
|
mockRatingRepo as IUserRatingRepository,
|
|
);
|
|
expect(useCase).toBeInstanceOf(RecomputeUserRatingSnapshotUseCase);
|
|
});
|
|
|
|
it('should compute snapshot from empty event list', async () => {
|
|
const useCase = new RecomputeUserRatingSnapshotUseCase(
|
|
mockEventRepo as IRatingEventRepository,
|
|
mockRatingRepo as IUserRatingRepository,
|
|
);
|
|
|
|
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 IRatingEventRepository,
|
|
mockRatingRepo as IUserRatingRepository,
|
|
);
|
|
|
|
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 IRatingEventRepository,
|
|
mockRatingRepo as IUserRatingRepository,
|
|
);
|
|
|
|
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 IRatingEventRepository,
|
|
mockRatingRepo as IUserRatingRepository,
|
|
);
|
|
|
|
const result = await useCase.execute({ userId: 'user-1' });
|
|
|
|
// Should have calculatorVersion
|
|
expect(result.snapshot.calculatorVersion).toBeDefined();
|
|
});
|
|
}); |