Compare commits
5 Commits
main
...
cfc30c79a8
| Author | SHA1 | Date | |
|---|---|---|---|
| cfc30c79a8 | |||
| f877f821ef | |||
| afef777961 | |||
| bf2c0fdb0c | |||
| 49cc91e046 |
@@ -521,7 +521,9 @@
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2022,
|
||||
"sourceType": "module"
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.eslint.json",
|
||||
"tsconfigRootDir": "."
|
||||
},
|
||||
"settings": {
|
||||
"boundaries/elements": [
|
||||
|
||||
@@ -231,9 +231,9 @@ describe('TypeOrmPersistenceSchemaAdapter', () => {
|
||||
});
|
||||
|
||||
// When
|
||||
(error as any).entityName = 'NewEntity';
|
||||
(error as any).fieldName = 'newField';
|
||||
(error as any).reason = 'new_reason';
|
||||
(error as { entityName: string }).entityName = 'NewEntity';
|
||||
(error as { fieldName: string }).fieldName = 'newField';
|
||||
(error as { reason: string }).reason = 'new_reason';
|
||||
|
||||
// Then
|
||||
expect(error.entityName).toBe('NewEntity');
|
||||
|
||||
@@ -226,7 +226,7 @@ describe('AchievementOrmMapper', () => {
|
||||
// Given
|
||||
const entity = new AchievementOrmEntity();
|
||||
entity.id = 'ach-123';
|
||||
entity.name = 123 as any;
|
||||
(entity as unknown as { name: unknown }).name = 123;
|
||||
entity.description = 'Complete your first race';
|
||||
entity.category = 'driver';
|
||||
entity.rarity = 'common';
|
||||
@@ -257,7 +257,7 @@ describe('AchievementOrmMapper', () => {
|
||||
entity.id = 'ach-123';
|
||||
entity.name = 'First Race';
|
||||
entity.description = 'Complete your first race';
|
||||
entity.category = 'invalid_category' as any;
|
||||
(entity as unknown as { category: unknown }).category = 'invalid_category';
|
||||
entity.rarity = 'common';
|
||||
entity.points = 10;
|
||||
entity.requirements = [
|
||||
@@ -318,7 +318,7 @@ describe('AchievementOrmMapper', () => {
|
||||
entity.category = 'driver';
|
||||
entity.rarity = 'common';
|
||||
entity.points = 10;
|
||||
entity.requirements = 'not_an_array' as any;
|
||||
(entity as unknown as { requirements: unknown }).requirements = 'not_an_array';
|
||||
entity.isSecret = false;
|
||||
entity.createdAt = new Date('2024-01-01');
|
||||
|
||||
@@ -345,7 +345,7 @@ describe('AchievementOrmMapper', () => {
|
||||
entity.category = 'driver';
|
||||
entity.rarity = 'common';
|
||||
entity.points = 10;
|
||||
entity.requirements = [null as any];
|
||||
(entity as unknown as { requirements: unknown[] }).requirements = [null];
|
||||
entity.isSecret = false;
|
||||
entity.createdAt = new Date('2024-01-01');
|
||||
|
||||
@@ -372,7 +372,7 @@ describe('AchievementOrmMapper', () => {
|
||||
entity.category = 'driver';
|
||||
entity.rarity = 'common';
|
||||
entity.points = 10;
|
||||
entity.requirements = [{ type: 123, value: 1, operator: '>=' } as any];
|
||||
(entity as unknown as { requirements: unknown[] }).requirements = [{ type: 123, value: 1, operator: '>=' }];
|
||||
entity.isSecret = false;
|
||||
entity.createdAt = new Date('2024-01-01');
|
||||
|
||||
@@ -399,7 +399,7 @@ describe('AchievementOrmMapper', () => {
|
||||
entity.category = 'driver';
|
||||
entity.rarity = 'common';
|
||||
entity.points = 10;
|
||||
entity.requirements = [{ type: 'races_completed', value: 1, operator: 'invalid' } as any];
|
||||
(entity as unknown as { requirements: unknown[] }).requirements = [{ type: 'races_completed', value: 1, operator: 'invalid' }];
|
||||
entity.isSecret = false;
|
||||
entity.createdAt = new Date('2024-01-01');
|
||||
|
||||
@@ -430,7 +430,7 @@ describe('AchievementOrmMapper', () => {
|
||||
{ type: 'races_completed', value: 1, operator: '>=' },
|
||||
];
|
||||
entity.isSecret = false;
|
||||
entity.createdAt = 'not_a_date' as any;
|
||||
(entity as unknown as { createdAt: unknown }).createdAt = 'not_a_date';
|
||||
|
||||
// When & Then
|
||||
expect(() => mapper.toDomain(entity)).toThrow(TypeOrmPersistenceSchemaAdapter);
|
||||
@@ -571,7 +571,7 @@ describe('AchievementOrmMapper', () => {
|
||||
// Given
|
||||
const entity = new UserAchievementOrmEntity();
|
||||
entity.id = 'ua-123';
|
||||
entity.userId = 123 as any;
|
||||
(entity as unknown as { userId: unknown }).userId = 123;
|
||||
entity.achievementId = 'ach-789';
|
||||
entity.earnedAt = new Date('2024-01-01');
|
||||
entity.progress = 50;
|
||||
@@ -621,7 +621,7 @@ describe('AchievementOrmMapper', () => {
|
||||
entity.id = 'ua-123';
|
||||
entity.userId = 'user-456';
|
||||
entity.achievementId = 'ach-789';
|
||||
entity.earnedAt = 'not_a_date' as any;
|
||||
(entity as unknown as { earnedAt: unknown }).earnedAt = 'not_a_date';
|
||||
entity.progress = 50;
|
||||
entity.notifiedAt = null;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { vi } from 'vitest';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import type { AchievementOrmMapper } from '../mappers/AchievementOrmMapper';
|
||||
import { Achievement } from '@core/identity/domain/entities/Achievement';
|
||||
import { UserAchievement } from '@core/identity/domain/entities/UserAchievement';
|
||||
import { AchievementOrmEntity } from '../entities/AchievementOrmEntity';
|
||||
import { UserAchievementOrmEntity } from '../entities/UserAchievementOrmEntity';
|
||||
import { AchievementOrmMapper } from '../mappers/AchievementOrmMapper';
|
||||
import { TypeOrmAchievementRepository } from './TypeOrmAchievementRepository';
|
||||
|
||||
describe('TypeOrmAchievementRepository', () => {
|
||||
@@ -48,7 +48,7 @@ describe('TypeOrmAchievementRepository', () => {
|
||||
};
|
||||
|
||||
// When: repository is instantiated with mocked dependencies
|
||||
repository = new TypeOrmAchievementRepository(mockDataSource as any, mockMapper as any);
|
||||
repository = new TypeOrmAchievementRepository(mockDataSource as unknown as DataSource, mockMapper as unknown as AchievementOrmMapper);
|
||||
});
|
||||
|
||||
describe('DI Boundary - Constructor', () => {
|
||||
@@ -65,8 +65,8 @@ describe('TypeOrmAchievementRepository', () => {
|
||||
// Then: it should have injected dependencies
|
||||
it('should have injected dependencies', () => {
|
||||
// Given & When & Then
|
||||
expect((repository as any).dataSource).toBe(mockDataSource);
|
||||
expect((repository as any).mapper).toBe(mockMapper);
|
||||
expect((repository as unknown as { dataSource: unknown }).dataSource).toBe(mockDataSource);
|
||||
expect((repository as unknown as { mapper: unknown }).mapper).toBe(mockMapper);
|
||||
});
|
||||
|
||||
// Given: repository instance
|
||||
|
||||
@@ -571,8 +571,8 @@ describe('AdminUserOrmEntity', () => {
|
||||
const entity = new AdminUserOrmEntity();
|
||||
|
||||
// Act
|
||||
entity.primaryDriverId = null as any;
|
||||
entity.lastLoginAt = null as any;
|
||||
(entity as unknown as { primaryDriverId: unknown }).primaryDriverId = null;
|
||||
(entity as unknown as { lastLoginAt: unknown }).lastLoginAt = null;
|
||||
|
||||
// Assert
|
||||
expect(entity.primaryDriverId).toBeNull();
|
||||
|
||||
@@ -55,12 +55,12 @@ describe('AnalyticsSnapshotOrmMapper', () => {
|
||||
// Given
|
||||
const orm = new AnalyticsSnapshotOrmEntity();
|
||||
orm.id = ''; // Invalid: empty
|
||||
orm.entityType = 'league' as any;
|
||||
(orm as unknown as { entityType: unknown }).entityType = 'league';
|
||||
orm.entityId = 'league-1';
|
||||
orm.period = 'daily' as any;
|
||||
(orm as unknown as { period: unknown }).period = 'daily';
|
||||
orm.startDate = new Date();
|
||||
orm.endDate = new Date();
|
||||
orm.metrics = {} as any; // Invalid: missing fields
|
||||
(orm as unknown as { metrics: unknown }).metrics = {}; // Invalid: missing fields
|
||||
orm.createdAt = new Date();
|
||||
|
||||
// When / Then
|
||||
@@ -71,20 +71,24 @@ describe('AnalyticsSnapshotOrmMapper', () => {
|
||||
// Given
|
||||
const orm = new AnalyticsSnapshotOrmEntity();
|
||||
orm.id = 'snap_1';
|
||||
orm.entityType = 'league' as any;
|
||||
(orm as unknown as { entityType: unknown }).entityType = 'league';
|
||||
orm.entityId = 'league-1';
|
||||
orm.period = 'daily' as any;
|
||||
(orm as unknown as { period: unknown }).period = 'daily';
|
||||
orm.startDate = new Date();
|
||||
orm.endDate = new Date();
|
||||
orm.metrics = { pageViews: 100 } as any; // Missing other metrics
|
||||
(orm as unknown as { metrics: unknown }).metrics = { pageViews: 100 }; // Missing other metrics
|
||||
orm.createdAt = new Date();
|
||||
|
||||
// When / Then
|
||||
expect(() => mapper.toDomain(orm)).toThrow(TypeOrmAnalyticsSchemaError);
|
||||
try {
|
||||
mapper.toDomain(orm);
|
||||
} catch (e: any) {
|
||||
expect(e.fieldName).toContain('metrics.');
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof TypeOrmAnalyticsSchemaError) {
|
||||
expect(e.fieldName).toContain('metrics.');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,10 +68,10 @@ describe('EngagementEventOrmMapper', () => {
|
||||
// Given
|
||||
const orm = new EngagementEventOrmEntity();
|
||||
orm.id = ''; // Invalid
|
||||
orm.action = 'invalid_action' as any;
|
||||
orm.entityType = 'league' as any;
|
||||
(orm as unknown as { action: unknown }).action = 'invalid_action';
|
||||
(orm as unknown as { entityType: unknown }).entityType = 'league';
|
||||
orm.entityId = 'league-1';
|
||||
orm.actorType = 'anonymous' as any;
|
||||
(orm as unknown as { actorType: unknown }).actorType = 'anonymous';
|
||||
orm.sessionId = 'sess-1';
|
||||
orm.timestamp = new Date();
|
||||
|
||||
@@ -83,21 +83,25 @@ describe('EngagementEventOrmMapper', () => {
|
||||
// Given
|
||||
const orm = new EngagementEventOrmEntity();
|
||||
orm.id = 'eng_1';
|
||||
orm.action = 'click_sponsor_logo' as any;
|
||||
orm.entityType = 'sponsor' as any;
|
||||
(orm as unknown as { action: unknown }).action = 'click_sponsor_logo';
|
||||
(orm as unknown as { entityType: unknown }).entityType = 'sponsor';
|
||||
orm.entityId = 'sponsor-1';
|
||||
orm.actorType = 'driver' as any;
|
||||
(orm as unknown as { actorType: unknown }).actorType = 'driver';
|
||||
orm.sessionId = 'sess-1';
|
||||
orm.timestamp = new Date();
|
||||
orm.metadata = { invalid: { nested: 'object' } } as any;
|
||||
(orm as unknown as { metadata: unknown }).metadata = { invalid: { nested: 'object' } };
|
||||
|
||||
// When / Then
|
||||
expect(() => mapper.toDomain(orm)).toThrow(TypeOrmAnalyticsSchemaError);
|
||||
try {
|
||||
mapper.toDomain(orm);
|
||||
} catch (e: any) {
|
||||
expect(e.reason).toBe('invalid_shape');
|
||||
expect(e.fieldName).toBe('metadata');
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof TypeOrmAnalyticsSchemaError) {
|
||||
expect(e.reason).toBe('invalid_shape');
|
||||
expect(e.fieldName).toBe('metadata');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('TypeOrmAnalyticsSnapshotRepository', () => {
|
||||
period: 'daily',
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
metrics: {} as any,
|
||||
metrics: {} as unknown as any,
|
||||
createdAt: new Date(),
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('TypeOrmAnalyticsSnapshotRepository', () => {
|
||||
period: 'daily',
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
metrics: {} as any,
|
||||
metrics: {} as unknown as any,
|
||||
createdAt: new Date(),
|
||||
});
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ describe('TypeOrmEngagementRepository', () => {
|
||||
// Given
|
||||
const repo: Repository<EngagementEventOrmEntity> = {
|
||||
count: vi.fn().mockResolvedValue(5),
|
||||
} as any;
|
||||
const sut = new TypeOrmEngagementRepository(repo, {} as any);
|
||||
} as unknown as Repository<EngagementEventOrmEntity>;
|
||||
const sut = new TypeOrmEngagementRepository(repo, {} as unknown as EngagementEventOrmMapper);
|
||||
const since = new Date();
|
||||
|
||||
// When
|
||||
|
||||
@@ -79,16 +79,16 @@ describe('SeedDemoUsers', () => {
|
||||
];
|
||||
|
||||
// Mock repositories to return null (users don't exist)
|
||||
(authRepository.findByEmail as any).mockResolvedValue(null);
|
||||
(adminUserRepository.findByEmail as any).mockResolvedValue(null);
|
||||
(adminUserRepository.create as any).mockImplementation((user: AdminUser) => user);
|
||||
(authRepository.save as any).mockResolvedValue(undefined);
|
||||
vi.mocked(authRepository.findByEmail).mockResolvedValue(null);
|
||||
vi.mocked(adminUserRepository.findByEmail).mockResolvedValue(null);
|
||||
vi.mocked(adminUserRepository.create).mockImplementation(async (user: AdminUser) => user);
|
||||
vi.mocked(authRepository.save).mockResolvedValue(undefined);
|
||||
|
||||
await seed.execute();
|
||||
|
||||
// Verify that findByEmail was called for each expected email
|
||||
const calls = (authRepository.findByEmail as any).mock.calls;
|
||||
const emailsCalled = calls.map((call: any) => call[0].value);
|
||||
const calls = vi.mocked(authRepository.findByEmail).mock.calls;
|
||||
const emailsCalled = calls.map((call) => call[0].value);
|
||||
|
||||
expect(emailsCalled).toEqual(expect.arrayContaining(expectedEmails));
|
||||
expect(emailsCalled.length).toBeGreaterThanOrEqual(7);
|
||||
@@ -98,10 +98,10 @@ describe('SeedDemoUsers', () => {
|
||||
const seed = new SeedDemoUsers(logger, authRepository, passwordHashingService, adminUserRepository);
|
||||
|
||||
// Mock repositories to return null (users don't exist)
|
||||
(authRepository.findByEmail as any).mockResolvedValue(null);
|
||||
(adminUserRepository.findByEmail as any).mockResolvedValue(null);
|
||||
(adminUserRepository.create as any).mockImplementation((user: AdminUser) => user);
|
||||
(authRepository.save as any).mockResolvedValue(undefined);
|
||||
vi.mocked(authRepository.findByEmail).mockResolvedValue(null);
|
||||
vi.mocked(adminUserRepository.findByEmail).mockResolvedValue(null);
|
||||
vi.mocked(adminUserRepository.create).mockImplementation(async (user: AdminUser) => user);
|
||||
vi.mocked(authRepository.save).mockResolvedValue(undefined);
|
||||
|
||||
await seed.execute();
|
||||
|
||||
@@ -118,15 +118,15 @@ describe('SeedDemoUsers', () => {
|
||||
const seed = new SeedDemoUsers(logger, authRepository, passwordHashingService, adminUserRepository);
|
||||
|
||||
// Mock repositories to return null (users don't exist)
|
||||
(authRepository.findByEmail as any).mockResolvedValue(null);
|
||||
(adminUserRepository.findByEmail as any).mockResolvedValue(null);
|
||||
(adminUserRepository.create as any).mockImplementation((user: AdminUser) => user);
|
||||
(authRepository.save as any).mockResolvedValue(undefined);
|
||||
vi.mocked(authRepository.findByEmail).mockResolvedValue(null);
|
||||
vi.mocked(adminUserRepository.findByEmail).mockResolvedValue(null);
|
||||
vi.mocked(adminUserRepository.create).mockImplementation(async (user: AdminUser) => user);
|
||||
vi.mocked(authRepository.save).mockResolvedValue(undefined);
|
||||
|
||||
await seed.execute();
|
||||
|
||||
// Verify that users were saved with UUIDs
|
||||
const saveCalls = (authRepository.save as any).mock.calls;
|
||||
const saveCalls = vi.mocked(authRepository.save).mock.calls;
|
||||
expect(saveCalls.length).toBeGreaterThanOrEqual(7);
|
||||
|
||||
// Check that IDs are UUIDs (deterministic from seed keys)
|
||||
@@ -173,9 +173,6 @@ describe('SeedDemoUsers', () => {
|
||||
|
||||
await seed.execute();
|
||||
|
||||
const firstSaveCount = (authRepository.save as any).mock.calls.length;
|
||||
const firstAdminCreateCount = (adminUserRepository.create as any).mock.calls.length;
|
||||
|
||||
// Reset mocks
|
||||
vi.clearAllMocks();
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ export class SeedRacingData {
|
||||
// ignore duplicates
|
||||
}
|
||||
|
||||
const seedableFeed = this.seedDeps.feedRepository as unknown as { seed?: (input: any) => void };
|
||||
const seedableFeed = this.seedDeps.feedRepository as unknown as { seed?: (input: unknown) => void };
|
||||
if (typeof seedableFeed.seed === 'function') {
|
||||
seedableFeed.seed({
|
||||
drivers: seed.drivers,
|
||||
@@ -319,7 +319,7 @@ export class SeedRacingData {
|
||||
});
|
||||
}
|
||||
|
||||
const seedableSocial = this.seedDeps.socialGraphRepository as unknown as { seed?: (input: any) => void };
|
||||
const seedableSocial = this.seedDeps.socialGraphRepository as unknown as { seed?: (input: unknown) => void };
|
||||
if (typeof seedableSocial.seed === 'function') {
|
||||
seedableSocial.seed({
|
||||
drivers: seed.drivers,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
DisconnectedEvent,
|
||||
DegradedEvent,
|
||||
CheckingEvent,
|
||||
} from '../../../core/health/ports/HealthEventPublisher';
|
||||
} from '../../core/health/ports/HealthEventPublisher';
|
||||
|
||||
export interface HealthCheckCompletedEventWithType {
|
||||
type: 'HealthCheckCompleted';
|
||||
|
||||
@@ -69,7 +69,7 @@ export class InMemoryHealthCheckAdapter implements HealthCheckQuery {
|
||||
await new Promise(resolve => setTimeout(resolve, this.responseTime));
|
||||
|
||||
if (this.shouldFail) {
|
||||
this.recordFailure(this.failError);
|
||||
this.recordFailure();
|
||||
return {
|
||||
healthy: false,
|
||||
responseTime: this.responseTime,
|
||||
@@ -141,7 +141,7 @@ export class InMemoryHealthCheckAdapter implements HealthCheckQuery {
|
||||
/**
|
||||
* Record a failed health check
|
||||
*/
|
||||
private recordFailure(error: string): void {
|
||||
private recordFailure(): void {
|
||||
this.health.totalRequests++;
|
||||
this.health.failedRequests++;
|
||||
this.health.consecutiveFailures++;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { InMemoryMagicLinkRepository } from './InMemoryMagicLinkRepository';
|
||||
import type { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
const mockLogger = {
|
||||
const mockLogger: Logger = {
|
||||
debug: () => {},
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
@@ -12,7 +13,7 @@ describe('InMemoryMagicLinkRepository', () => {
|
||||
let repository: InMemoryMagicLinkRepository;
|
||||
|
||||
beforeEach(() => {
|
||||
repository = new InMemoryMagicLinkRepository(mockLogger as any);
|
||||
repository = new InMemoryMagicLinkRepository(mockLogger);
|
||||
});
|
||||
|
||||
describe('createPasswordResetRequest', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RatingEvent } from '@core/identity/domain/entities/RatingEvent';
|
||||
import { RatingEvent, RatingEventProps } from '@core/identity/domain/entities/RatingEvent';
|
||||
import { RatingDelta } from '@core/identity/domain/value-objects/RatingDelta';
|
||||
import { RatingDimensionKey } from '@core/identity/domain/value-objects/RatingDimensionKey';
|
||||
import { RatingEventId } from '@core/identity/domain/value-objects/RatingEventId';
|
||||
@@ -14,7 +14,7 @@ export class RatingEventOrmMapper {
|
||||
* Convert ORM entity to domain entity
|
||||
*/
|
||||
static toDomain(entity: RatingEventOrmEntity): RatingEvent {
|
||||
const props: any = {
|
||||
const props: RatingEventProps = {
|
||||
id: RatingEventId.create(entity.id),
|
||||
userId: entity.userId,
|
||||
dimension: RatingDimensionKey.create(entity.dimension),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UserRating } from '@core/identity/domain/value-objects/UserRating';
|
||||
import { UserRating, UserRatingProps } from '@core/identity/domain/value-objects/UserRating';
|
||||
import { UserRatingOrmEntity } from '../entities/UserRatingOrmEntity';
|
||||
|
||||
/**
|
||||
@@ -11,7 +11,7 @@ export class UserRatingOrmMapper {
|
||||
* Convert ORM entity to domain value object
|
||||
*/
|
||||
static toDomain(entity: UserRatingOrmEntity): UserRating {
|
||||
const props: any = {
|
||||
const props: UserRatingProps = {
|
||||
userId: entity.userId,
|
||||
driver: entity.driver,
|
||||
admin: entity.admin,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { RatingEvent } from '@core/identity/domain/entities/RatingEvent';
|
||||
|
||||
import { TypeOrmRatingEventRepository } from './TypeOrmRatingEventRepository';
|
||||
|
||||
@@ -30,7 +31,7 @@ describe('TypeOrmRatingEventRepository', () => {
|
||||
reason: { code: 'TEST', summary: 'Test', details: {} },
|
||||
visibility: { public: true, redactedFields: [] },
|
||||
version: 1,
|
||||
} as any;
|
||||
} as unknown as RatingEvent;
|
||||
|
||||
// Mock the mapper
|
||||
vi.doMock('../mappers/RatingEventOrmMapper', () => ({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { UserRating } from '@core/identity/domain/value-objects/UserRating';
|
||||
|
||||
import { TypeOrmUserRatingRepository } from './TypeOrmUserRatingRepository';
|
||||
|
||||
@@ -41,7 +42,7 @@ describe('TypeOrmUserRatingRepository', () => {
|
||||
overallReputation: 50,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as any;
|
||||
} as unknown as UserRating;
|
||||
|
||||
const result = await repo.save(mockRating);
|
||||
expect(result).toBe(mockRating);
|
||||
|
||||
@@ -47,9 +47,10 @@ function buildSetCookieHeader(options: {
|
||||
return parts.join('; ');
|
||||
}
|
||||
|
||||
function appendSetCookieHeader(existing: string | string[] | undefined, next: string): string[] {
|
||||
function appendSetCookieHeader(existing: string | number | string[] | undefined, next: string): string[] {
|
||||
if (!existing) return [next];
|
||||
if (Array.isArray(existing)) return [...existing, next];
|
||||
if (typeof existing === 'number') return [existing.toString(), next];
|
||||
return [existing, next];
|
||||
}
|
||||
|
||||
@@ -111,7 +112,7 @@ export class CookieIdentitySessionAdapter implements IdentitySessionPort {
|
||||
});
|
||||
|
||||
const existing = ctx.res.getHeader('Set-Cookie');
|
||||
ctx.res.setHeader('Set-Cookie', appendSetCookieHeader(existing as any, setCookie));
|
||||
ctx.res.setHeader('Set-Cookie', appendSetCookieHeader(existing, setCookie));
|
||||
}
|
||||
|
||||
return session;
|
||||
@@ -137,7 +138,7 @@ export class CookieIdentitySessionAdapter implements IdentitySessionPort {
|
||||
});
|
||||
|
||||
const existing = ctx.res.getHeader('Set-Cookie');
|
||||
ctx.res.setHeader('Set-Cookie', appendSetCookieHeader(existing as any, setCookie));
|
||||
ctx.res.setHeader('Set-Cookie', appendSetCookieHeader(existing, setCookie));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
import { InMemoryMediaRepository } from './InMemoryMediaRepository';
|
||||
import { runMediaRepositoryContract } from '../../../../tests/contracts/media/MediaRepository.contract';
|
||||
import type { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
describe('InMemoryMediaRepository Contract Compliance', () => {
|
||||
runMediaRepositoryContract(async () => {
|
||||
const logger = {
|
||||
const logger: Logger = {
|
||||
info: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
|
||||
const repository = new InMemoryMediaRepository(logger as any);
|
||||
const repository = new InMemoryMediaRepository(logger);
|
||||
|
||||
return {
|
||||
repository,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AvatarGenerationRequest } from '@core/media/domain/entities/AvatarGenerationRequest';
|
||||
import { AvatarGenerationRequestProps } from '@core/media/domain/types/AvatarGenerationRequest';
|
||||
import { AvatarGenerationRequestOrmEntity } from '../entities/AvatarGenerationRequestOrmEntity';
|
||||
import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError';
|
||||
import {
|
||||
@@ -37,7 +38,7 @@ export class AvatarGenerationRequestOrmMapper {
|
||||
}
|
||||
|
||||
try {
|
||||
const props: any = {
|
||||
const props: AvatarGenerationRequestProps = {
|
||||
id: entity.id,
|
||||
userId: entity.userId,
|
||||
facePhotoUrl: entity.facePhotoUrl,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Media } from '@core/media/domain/entities/Media';
|
||||
import { Media, MediaProps } from '@core/media/domain/entities/Media';
|
||||
import { MediaOrmEntity } from '../entities/MediaOrmEntity';
|
||||
import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError';
|
||||
import {
|
||||
@@ -31,7 +31,7 @@ export class MediaOrmMapper {
|
||||
}
|
||||
|
||||
try {
|
||||
const domainProps: any = {
|
||||
const domainProps: MediaProps = {
|
||||
id: entity.id,
|
||||
filename: entity.filename,
|
||||
originalName: entity.originalName,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { AvatarGenerationRequest } from '@core/media/domain/entities/AvatarGenerationRequest';
|
||||
import type { AvatarGenerationRequestOrmMapper } from '../mappers/AvatarGenerationRequestOrmMapper';
|
||||
|
||||
import { TypeOrmAvatarGenerationRepository } from './TypeOrmAvatarGenerationRepository';
|
||||
|
||||
@@ -35,7 +38,7 @@ describe('TypeOrmAvatarGenerationRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-request-1' }),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmAvatarGenerationRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmAvatarGenerationRepository(dataSource as unknown as DataSource, mapper as unknown as AvatarGenerationRequestOrmMapper);
|
||||
|
||||
// Test findById
|
||||
const request = await repo.findById('request-1');
|
||||
@@ -61,8 +64,8 @@ describe('TypeOrmAvatarGenerationRepository', () => {
|
||||
});
|
||||
|
||||
// Test save
|
||||
const domainRequest = { id: 'new-request', toProps: () => ({ id: 'new-request' }) };
|
||||
await repo.save(domainRequest as any);
|
||||
const domainRequest = { id: 'new-request', toProps: () => ({ id: 'new-request' }) } as unknown as AvatarGenerationRequest;
|
||||
await repo.save(domainRequest);
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainRequest);
|
||||
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-request-1' });
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { Avatar } from '@core/media/domain/entities/Avatar';
|
||||
import type { AvatarOrmMapper } from '../mappers/AvatarOrmMapper';
|
||||
|
||||
import { TypeOrmAvatarRepository } from './TypeOrmAvatarRepository';
|
||||
|
||||
@@ -35,7 +38,7 @@ describe('TypeOrmAvatarRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-avatar-1' }),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmAvatarRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmAvatarRepository(dataSource as unknown as DataSource, mapper as unknown as AvatarOrmMapper);
|
||||
|
||||
// Test findById
|
||||
const avatar = await repo.findById('avatar-1');
|
||||
@@ -61,8 +64,8 @@ describe('TypeOrmAvatarRepository', () => {
|
||||
expect(avatars).toHaveLength(2);
|
||||
|
||||
// Test save
|
||||
const domainAvatar = { id: 'new-avatar', toProps: () => ({ id: 'new-avatar' }) };
|
||||
await repo.save(domainAvatar as any);
|
||||
const domainAvatar = { id: 'new-avatar', toProps: () => ({ id: 'new-avatar' }) } as unknown as Avatar;
|
||||
await repo.save(domainAvatar);
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainAvatar);
|
||||
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-avatar-1' });
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { TypeOrmMediaRepository } from './TypeOrmMediaRepository';
|
||||
import { MediaOrmMapper } from '../mappers/MediaOrmMapper';
|
||||
import { runMediaRepositoryContract } from '../../../../../tests/contracts/media/MediaRepository.contract';
|
||||
import type { MediaOrmEntity } from '../entities/MediaOrmEntity';
|
||||
|
||||
describe('TypeOrmMediaRepository Contract Compliance', () => {
|
||||
runMediaRepositoryContract(async () => {
|
||||
// Mocking TypeORM DataSource and Repository for a DB-free contract test
|
||||
// In a real scenario, this might use an in-memory SQLite database
|
||||
const ormEntities = new Map<string, any>();
|
||||
const ormEntities = new Map<string, MediaOrmEntity>();
|
||||
|
||||
const ormRepo = {
|
||||
save: vi.fn().mockImplementation(async (entity) => {
|
||||
@@ -30,7 +32,7 @@ describe('TypeOrmMediaRepository Contract Compliance', () => {
|
||||
};
|
||||
|
||||
const mapper = new MediaOrmMapper();
|
||||
const repository = new TypeOrmMediaRepository(dataSource as any, mapper);
|
||||
const repository = new TypeOrmMediaRepository(dataSource as unknown as DataSource, mapper);
|
||||
|
||||
return {
|
||||
repository,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { Media } from '@core/media/domain/entities/Media';
|
||||
import type { MediaOrmMapper } from '../mappers/MediaOrmMapper';
|
||||
|
||||
import { TypeOrmMediaRepository } from './TypeOrmMediaRepository';
|
||||
|
||||
@@ -35,7 +38,7 @@ describe('TypeOrmMediaRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-media-1' }),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmMediaRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmMediaRepository(dataSource as unknown as DataSource, mapper as unknown as MediaOrmMapper);
|
||||
|
||||
// Test findById
|
||||
const media = await repo.findById('media-1');
|
||||
|
||||
@@ -86,7 +86,7 @@ export class FileSystemMediaStorageAdapter implements MediaStoragePort {
|
||||
await fs.unlink(filePath);
|
||||
} catch (error) {
|
||||
// Ignore if file doesn't exist
|
||||
if (error instanceof Error && 'code' in error && (error as any).code === 'ENOENT') {
|
||||
if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface GeneratedMediaResolverConfig {
|
||||
* Format: "{type}-{id}" (e.g., "team-123", "league-456")
|
||||
*/
|
||||
export class GeneratedMediaResolverAdapter implements MediaResolverPort {
|
||||
constructor(_config: GeneratedMediaResolverConfig = {}) {
|
||||
constructor() {
|
||||
// basePath is not used since we return path-only URLs
|
||||
// config.basePath is ignored for backward compatibility
|
||||
}
|
||||
@@ -85,8 +85,6 @@ export class GeneratedMediaResolverAdapter implements MediaResolverPort {
|
||||
/**
|
||||
* Factory function for creating GeneratedMediaResolverAdapter instances
|
||||
*/
|
||||
export function createGeneratedMediaResolver(
|
||||
config: GeneratedMediaResolverConfig = {}
|
||||
): GeneratedMediaResolverAdapter {
|
||||
return new GeneratedMediaResolverAdapter(config);
|
||||
export function createGeneratedMediaResolver(): GeneratedMediaResolverAdapter {
|
||||
return new GeneratedMediaResolverAdapter();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { DiscordNotificationAdapter } from './DiscordNotificationGateway';
|
||||
import { Notification } from '@core/notifications/domain/entities/Notification';
|
||||
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
|
||||
|
||||
describe('DiscordNotificationAdapter', () => {
|
||||
const webhookUrl = 'https://discord.com/api/webhooks/123/abc';
|
||||
@@ -11,7 +12,7 @@ describe('DiscordNotificationAdapter', () => {
|
||||
vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
const createNotification = (overrides: any = {}) => {
|
||||
const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
|
||||
return Notification.create({
|
||||
id: 'notif-123',
|
||||
recipientId: 'driver-456',
|
||||
@@ -58,7 +59,7 @@ describe('DiscordNotificationAdapter', () => {
|
||||
});
|
||||
|
||||
it('should return false for other channels', () => {
|
||||
expect(adapter.supportsChannel('email' as any)).toBe(false);
|
||||
expect(adapter.supportsChannel('email' as unknown as NotificationChannel)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { EmailNotificationAdapter } from './EmailNotificationGateway';
|
||||
import { Notification } from '@core/notifications/domain/entities/Notification';
|
||||
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
|
||||
|
||||
describe('EmailNotificationAdapter', () => {
|
||||
const config = {
|
||||
@@ -14,7 +15,7 @@ describe('EmailNotificationAdapter', () => {
|
||||
vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
const createNotification = (overrides: any = {}) => {
|
||||
const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
|
||||
return Notification.create({
|
||||
id: 'notif-123',
|
||||
recipientId: 'driver-456',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { InAppNotificationAdapter } from './InAppNotificationGateway';
|
||||
import { Notification } from '@core/notifications/domain/entities/Notification';
|
||||
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
|
||||
|
||||
describe('InAppNotificationAdapter', () => {
|
||||
let adapter: InAppNotificationAdapter;
|
||||
@@ -10,7 +11,7 @@ describe('InAppNotificationAdapter', () => {
|
||||
vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
const createNotification = (overrides: any = {}) => {
|
||||
const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
|
||||
return Notification.create({
|
||||
id: 'notif-123',
|
||||
recipientId: 'driver-456',
|
||||
|
||||
@@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { NotificationGatewayRegistry } from './NotificationGatewayRegistry';
|
||||
import { Notification } from '@core/notifications/domain/entities/Notification';
|
||||
import type { NotificationGateway, NotificationDeliveryResult } from '@core/notifications/application/ports/NotificationGateway';
|
||||
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
|
||||
|
||||
describe('NotificationGatewayRegistry', () => {
|
||||
let registry: NotificationGatewayRegistry;
|
||||
@@ -18,7 +17,7 @@ describe('NotificationGatewayRegistry', () => {
|
||||
registry = new NotificationGatewayRegistry([mockGateway]);
|
||||
});
|
||||
|
||||
const createNotification = (overrides: any = {}) => {
|
||||
const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
|
||||
return Notification.create({
|
||||
id: 'notif-123',
|
||||
recipientId: 'driver-456',
|
||||
@@ -35,7 +34,7 @@ describe('NotificationGatewayRegistry', () => {
|
||||
const discordGateway = {
|
||||
...mockGateway,
|
||||
getChannel: vi.fn().mockReturnValue('discord'),
|
||||
} as any;
|
||||
} as unknown as NotificationGateway;
|
||||
|
||||
registry.register(discordGateway);
|
||||
expect(registry.getGateway('discord')).toBe(discordGateway);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Notification } from '@core/notifications/domain/entities/Notification';
|
||||
import { Notification, type NotificationStatus, type NotificationUrgency } from '@core/notifications/domain/entities/Notification';
|
||||
import type { NotificationChannel, NotificationType } from '@core/notifications/domain/types/NotificationTypes';
|
||||
import { NotificationOrmEntity } from '../entities/NotificationOrmEntity';
|
||||
import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';
|
||||
import {
|
||||
@@ -44,40 +45,40 @@ export class NotificationOrmMapper {
|
||||
}
|
||||
|
||||
try {
|
||||
const domainProps: any = {
|
||||
const domainProps = {
|
||||
id: entity.id,
|
||||
recipientId: entity.recipientId,
|
||||
type: entity.type,
|
||||
type: entity.type as NotificationType,
|
||||
title: entity.title,
|
||||
body: entity.body,
|
||||
channel: entity.channel,
|
||||
status: entity.status,
|
||||
urgency: entity.urgency,
|
||||
channel: entity.channel as NotificationChannel,
|
||||
status: entity.status as NotificationStatus,
|
||||
urgency: entity.urgency as NotificationUrgency,
|
||||
createdAt: entity.createdAt,
|
||||
requiresResponse: entity.requiresResponse,
|
||||
};
|
||||
|
||||
if (entity.data !== null && entity.data !== undefined) {
|
||||
domainProps.data = entity.data as Record<string, unknown>;
|
||||
(domainProps as any).data = entity.data;
|
||||
}
|
||||
|
||||
if (entity.actionUrl !== null && entity.actionUrl !== undefined) {
|
||||
domainProps.actionUrl = entity.actionUrl;
|
||||
(domainProps as any).actionUrl = entity.actionUrl;
|
||||
}
|
||||
|
||||
if (entity.actions !== null && entity.actions !== undefined) {
|
||||
domainProps.actions = entity.actions;
|
||||
(domainProps as any).actions = entity.actions;
|
||||
}
|
||||
|
||||
if (entity.readAt !== null && entity.readAt !== undefined) {
|
||||
domainProps.readAt = entity.readAt;
|
||||
(domainProps as any).readAt = entity.readAt;
|
||||
}
|
||||
|
||||
if (entity.respondedAt !== null && entity.respondedAt !== undefined) {
|
||||
domainProps.respondedAt = entity.respondedAt;
|
||||
(domainProps as any).respondedAt = entity.respondedAt;
|
||||
}
|
||||
|
||||
return Notification.create(domainProps);
|
||||
return Notification.create(domainProps as any);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Invalid persisted Notification';
|
||||
throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
|
||||
|
||||
@@ -34,7 +34,7 @@ export class NotificationPreferenceOrmMapper {
|
||||
}
|
||||
|
||||
try {
|
||||
const domainProps: any = {
|
||||
const domainProps = {
|
||||
id: entity.id,
|
||||
driverId: entity.driverId,
|
||||
channels: entity.channels,
|
||||
@@ -43,22 +43,22 @@ export class NotificationPreferenceOrmMapper {
|
||||
};
|
||||
|
||||
if (entity.typePreferences !== null && entity.typePreferences !== undefined) {
|
||||
domainProps.typePreferences = entity.typePreferences;
|
||||
(domainProps as unknown as { typePreferences: unknown }).typePreferences = entity.typePreferences;
|
||||
}
|
||||
|
||||
if (entity.digestFrequencyHours !== null && entity.digestFrequencyHours !== undefined) {
|
||||
domainProps.digestFrequencyHours = entity.digestFrequencyHours;
|
||||
(domainProps as unknown as { digestFrequencyHours: unknown }).digestFrequencyHours = entity.digestFrequencyHours;
|
||||
}
|
||||
|
||||
if (entity.quietHoursStart !== null && entity.quietHoursStart !== undefined) {
|
||||
domainProps.quietHoursStart = entity.quietHoursStart;
|
||||
(domainProps as unknown as { quietHoursStart: unknown }).quietHoursStart = entity.quietHoursStart;
|
||||
}
|
||||
|
||||
if (entity.quietHoursEnd !== null && entity.quietHoursEnd !== undefined) {
|
||||
domainProps.quietHoursEnd = entity.quietHoursEnd;
|
||||
(domainProps as unknown as { quietHoursEnd: unknown }).quietHoursEnd = entity.quietHoursEnd;
|
||||
}
|
||||
|
||||
return NotificationPreference.create(domainProps);
|
||||
return NotificationPreference.create(domainProps as unknown as Parameters<typeof NotificationPreference.create>[0]);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Invalid persisted NotificationPreference';
|
||||
throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import type { NotificationPreference } from '@core/notifications/domain/entities/NotificationPreference';
|
||||
import type { NotificationPreferenceOrmMapper } from '../mappers/NotificationPreferenceOrmMapper';
|
||||
|
||||
import { TypeOrmNotificationPreferenceRepository } from './TypeOrmNotificationPreferenceRepository';
|
||||
|
||||
@@ -33,7 +36,7 @@ describe('TypeOrmNotificationPreferenceRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-preference-1' }),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmNotificationPreferenceRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmNotificationPreferenceRepository(dataSource as unknown as DataSource, mapper as unknown as NotificationPreferenceOrmMapper);
|
||||
|
||||
// Test findByDriverId
|
||||
const preference = await repo.findByDriverId('driver-123');
|
||||
@@ -43,8 +46,8 @@ describe('TypeOrmNotificationPreferenceRepository', () => {
|
||||
expect(preference).toEqual({ id: 'domain-preference-1' });
|
||||
|
||||
// Test save
|
||||
const domainPreference = { id: 'driver-123', driverId: 'driver-123', toJSON: () => ({ id: 'driver-123', driverId: 'driver-123' }) };
|
||||
await repo.save(domainPreference as any);
|
||||
const domainPreference = { id: 'driver-123', driverId: 'driver-123', toJSON: () => ({ id: 'driver-123', driverId: 'driver-123' }) } as unknown as NotificationPreference;
|
||||
await repo.save(domainPreference);
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainPreference);
|
||||
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-preference-1' });
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import type { NotificationOrmMapper } from '../mappers/NotificationOrmMapper';
|
||||
|
||||
import { TypeOrmNotificationRepository } from './TypeOrmNotificationRepository';
|
||||
|
||||
@@ -36,7 +38,7 @@ describe('TypeOrmNotificationRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-notification-1' }),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmNotificationRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmNotificationRepository(dataSource as unknown as DataSource, mapper as unknown as NotificationOrmMapper);
|
||||
|
||||
// Test findById
|
||||
const notification = await repo.findById('notification-1');
|
||||
@@ -61,13 +63,13 @@ describe('TypeOrmNotificationRepository', () => {
|
||||
expect(count).toBe(1);
|
||||
|
||||
// Test create
|
||||
const domainNotification = { id: 'new-notification', toJSON: () => ({ id: 'new-notification' }) };
|
||||
await repo.create(domainNotification as any);
|
||||
const domainNotification = { id: 'new-notification', toJSON: () => ({ id: 'new-notification' }) } as unknown as Notification;
|
||||
await repo.create(domainNotification);
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainNotification);
|
||||
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-notification-1' });
|
||||
|
||||
// Test update
|
||||
await repo.update(domainNotification as any);
|
||||
await repo.update(domainNotification);
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainNotification);
|
||||
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-notification-1' });
|
||||
|
||||
|
||||
@@ -2,34 +2,36 @@
|
||||
* In-Memory Implementation: InMemoryWalletRepository
|
||||
*/
|
||||
|
||||
import type { Transaction, Wallet } from '@core/payments/domain/entities/Wallet';
|
||||
import type { WalletRepository, TransactionRepository } from '@core/payments/domain/repositories/WalletRepository';
|
||||
import type { Logger } from '@core/shared/domain/Logger';
|
||||
import type { LeagueWalletRepository } from '@core/racing/domain/repositories/LeagueWalletRepository';
|
||||
import type { Wallet } from '@core/payments/domain/entities/Wallet';
|
||||
import type { LeagueWallet } from '@core/racing/domain/entities/league-wallet/LeagueWallet';
|
||||
import type { Transaction } from '@core/payments/domain/entities/league-wallet/Transaction';
|
||||
|
||||
const wallets: Map<string, any> = new Map();
|
||||
const transactions: Map<string, any> = new Map();
|
||||
const wallets: Map<string, Wallet | LeagueWallet> = new Map();
|
||||
const transactions: Map<string, Transaction> = new Map();
|
||||
|
||||
export class InMemoryWalletRepository implements WalletRepository, LeagueWalletRepository {
|
||||
constructor(private readonly logger: Logger) {}
|
||||
|
||||
async findById(id: string): Promise<any | null> {
|
||||
async findById(id: string): Promise<Wallet | LeagueWallet | null> {
|
||||
this.logger.debug('[InMemoryWalletRepository] findById', { id });
|
||||
return wallets.get(id) || null;
|
||||
}
|
||||
|
||||
async findByLeagueId(leagueId: string): Promise<any | null> {
|
||||
async findByLeagueId(leagueId: string): Promise<LeagueWallet | null> {
|
||||
this.logger.debug('[InMemoryWalletRepository] findByLeagueId', { leagueId });
|
||||
return Array.from(wallets.values()).find(w => w.leagueId.toString() === leagueId) || null;
|
||||
return (Array.from(wallets.values()).find(w => (w as LeagueWallet).leagueId.toString() === leagueId) as LeagueWallet) || null;
|
||||
}
|
||||
|
||||
async create(wallet: any): Promise<any> {
|
||||
async create(wallet: Wallet | LeagueWallet): Promise<Wallet | LeagueWallet> {
|
||||
this.logger.debug('[InMemoryWalletRepository] create', { wallet });
|
||||
wallets.set(wallet.id.toString(), wallet);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
async update(wallet: any): Promise<any> {
|
||||
async update(wallet: Wallet | LeagueWallet): Promise<Wallet | LeagueWallet> {
|
||||
this.logger.debug('[InMemoryWalletRepository] update', { wallet });
|
||||
wallets.set(wallet.id.toString(), wallet);
|
||||
return wallet;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MediaReference } from '@core/domain/media/MediaReference';
|
||||
import { Driver } from '@core/racing/domain/entities/Driver';
|
||||
import { DriverRepository } from '@core/racing/domain/repositories/DriverRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryDriverRepository implements DriverRepository {
|
||||
private drivers: Map<string, Driver> = new Map();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Game } from '@core/racing/domain/entities/Game';
|
||||
import { GameRepository } from '@core/racing/domain/repositories/GameRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryGameRepository implements GameRepository {
|
||||
private games: Map<string, Game> = new Map();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { JoinRequest } from '@core/racing/domain/entities/JoinRequest';
|
||||
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
|
||||
import { LeagueMembershipRepository } from '@core/racing/domain/repositories/LeagueMembershipRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryLeagueMembershipRepository implements LeagueMembershipRepository {
|
||||
private memberships: Map<string, LeagueMembership> = new Map(); // Key: `${leagueId}:${driverId}`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MediaReference } from '@core/domain/media/MediaReference';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
import { LeagueRepository } from '@core/racing/domain/repositories/LeagueRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryLeagueRepository implements LeagueRepository {
|
||||
private leagues: Map<string, League> = new Map();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig';
|
||||
import { LeagueScoringConfigRepository } from '@core/racing/domain/repositories/LeagueScoringConfigRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryLeagueScoringConfigRepository implements LeagueScoringConfigRepository {
|
||||
private configs: Map<string, LeagueScoringConfig> = new Map(); // Key: seasonId
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LeagueStandingsRepository, RawStanding } from '@core/league/application/ports/LeagueStandingsRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryLeagueStandingsRepository implements LeagueStandingsRepository {
|
||||
private standings: Map<string, RawStanding[]> = new Map(); // Key: leagueId
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Protest } from '@core/racing/domain/entities/Protest';
|
||||
import { ProtestRepository } from '@core/racing/domain/repositories/ProtestRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryProtestRepository implements ProtestRepository {
|
||||
private protests: Map<string, Protest> = new Map();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RaceRegistration } from '@core/racing/domain/entities/RaceRegistration';
|
||||
import { RaceRegistrationRepository } from '@core/racing/domain/repositories/RaceRegistrationRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryRaceRegistrationRepository implements RaceRegistrationRepository {
|
||||
private registrations: Map<string, RaceRegistration> = new Map(); // Key: `${raceId}:${driverId}`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Race, type RaceStatusValue } from '@core/racing/domain/entities/Race';
|
||||
import { RaceRepository } from '@core/racing/domain/repositories/RaceRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemoryRaceRepository implements RaceRepository {
|
||||
private races: Map<string, Race> = new Map();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Season } from '@core/racing/domain/entities/season/Season';
|
||||
import { SeasonRepository } from '@core/racing/domain/repositories/SeasonRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemorySeasonRepository implements SeasonRepository {
|
||||
private seasons: Map<string, Season> = new Map(); // Key: seasonId
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
|
||||
import { SponsorRepository } from '@core/racing/domain/repositories/SponsorRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemorySponsorRepository implements SponsorRepository {
|
||||
private sponsors: Map<string, Sponsor> = new Map();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SponsorableEntityType, SponsorshipRequest, SponsorshipRequestStatus } from '@core/racing/domain/entities/SponsorshipRequest';
|
||||
import { SponsorshipRequestRepository } from '@core/racing/domain/repositories/SponsorshipRequestRepository';
|
||||
import { Logger } from '@core/shared/domain';
|
||||
import { Logger } from '@core/shared/domain/Logger';
|
||||
|
||||
export class InMemorySponsorshipRequestRepository implements SponsorshipRequestRepository {
|
||||
private requests: Map<string, SponsorshipRequest> = new Map();
|
||||
|
||||
@@ -22,4 +22,7 @@ export class ResultOrmEntity {
|
||||
|
||||
@Column({ type: 'int' })
|
||||
startPosition!: number;
|
||||
|
||||
@Column({ type: 'int', default: 0 })
|
||||
points!: number;
|
||||
}
|
||||
@@ -29,11 +29,11 @@ describe('LeagueOrmMapper', () => {
|
||||
entity.youtubeUrl = null;
|
||||
entity.websiteUrl = null;
|
||||
|
||||
if (typeof (League as any).rehydrate !== 'function') {
|
||||
if (typeof (League as unknown as { rehydrate: unknown }).rehydrate !== 'function') {
|
||||
throw new Error('rehydrate-missing');
|
||||
}
|
||||
|
||||
const rehydrateSpy = vi.spyOn(League as any, 'rehydrate');
|
||||
const rehydrateSpy = vi.spyOn(League as unknown as { rehydrate: () => void }, 'rehydrate');
|
||||
const createSpy = vi.spyOn(League, 'create').mockImplementation(() => {
|
||||
throw new Error('create-called');
|
||||
});
|
||||
|
||||
@@ -24,11 +24,11 @@ describe('RaceOrmMapper', () => {
|
||||
entity.registeredCount = null;
|
||||
entity.maxParticipants = null;
|
||||
|
||||
if (typeof (Race as any).rehydrate !== 'function') {
|
||||
if (typeof (Race as unknown as { rehydrate: unknown }).rehydrate !== 'function') {
|
||||
throw new Error('rehydrate-missing');
|
||||
}
|
||||
|
||||
const rehydrateSpy = vi.spyOn(Race as any, 'rehydrate');
|
||||
const rehydrateSpy = vi.spyOn(Race as unknown as { rehydrate: () => void }, 'rehydrate');
|
||||
const createSpy = vi.spyOn(Race, 'create').mockImplementation(() => {
|
||||
throw new Error('create-called');
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ export class ResultOrmMapper {
|
||||
entity.fastestLap = domain.fastestLap.toNumber();
|
||||
entity.incidents = domain.incidents.toNumber();
|
||||
entity.startPosition = domain.startPosition.toNumber();
|
||||
entity.points = domain.points;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -29,6 +30,7 @@ export class ResultOrmMapper {
|
||||
assertInteger(entityName, 'fastestLap', entity.fastestLap);
|
||||
assertInteger(entityName, 'incidents', entity.incidents);
|
||||
assertInteger(entityName, 'startPosition', entity.startPosition);
|
||||
assertInteger(entityName, 'points', entity.points);
|
||||
} catch (error) {
|
||||
if (error instanceof TypeOrmPersistenceSchemaError) {
|
||||
throw new InvalidResultSchemaError({
|
||||
@@ -49,6 +51,7 @@ export class ResultOrmMapper {
|
||||
fastestLap: entity.fastestLap,
|
||||
incidents: entity.incidents,
|
||||
startPosition: entity.startPosition,
|
||||
points: entity.points,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Invalid persisted Result';
|
||||
|
||||
@@ -28,11 +28,11 @@ describe('SeasonOrmMapper', () => {
|
||||
entity.maxDrivers = null;
|
||||
entity.participantCount = 3;
|
||||
|
||||
if (typeof (Season as any).rehydrate !== 'function') {
|
||||
if (typeof (Season as unknown as { rehydrate: unknown }).rehydrate !== 'function') {
|
||||
throw new Error('rehydrate-missing');
|
||||
}
|
||||
|
||||
const rehydrateSpy = vi.spyOn(Season as any, 'rehydrate');
|
||||
const rehydrateSpy = vi.spyOn(Season as unknown as { rehydrate: () => void }, 'rehydrate');
|
||||
const createSpy = vi.spyOn(Season, 'create').mockImplementation(() => {
|
||||
throw new Error('create-called');
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('TeamRatingEventOrmMapper', () => {
|
||||
|
||||
it('should handle domain entity without weight', () => {
|
||||
const props = { ...validDomainProps };
|
||||
delete (props as any).weight;
|
||||
delete (props as unknown as { weight: unknown }).weight;
|
||||
const domain = TeamRatingEvent.create(props);
|
||||
const entity = TeamRatingEventOrmMapper.toOrmEntity(domain);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
TypeOrmGameRepository,
|
||||
@@ -6,6 +7,8 @@ import {
|
||||
TypeOrmSponsorRepository,
|
||||
TypeOrmTransactionRepository,
|
||||
} from './CommerceTypeOrmRepositories';
|
||||
import type { GameOrmEntity, LeagueWalletOrmEntity, SponsorOrmEntity, TransactionOrmEntity } from '../entities/CommerceOrmEntities';
|
||||
import type { GameOrmMapper, LeagueWalletOrmMapper, SponsorOrmMapper, TransactionOrmMapper } from '../mappers/CommerceOrmMappers';
|
||||
|
||||
describe('TypeOrmGameRepository', () => {
|
||||
it('findAll maps entities to domain using injected mapper (DB-free)', async () => {
|
||||
@@ -17,10 +20,10 @@ describe('TypeOrmGameRepository', () => {
|
||||
};
|
||||
|
||||
const mapper = {
|
||||
toDomain: vi.fn().mockImplementation((e: any) => ({ id: `domain-${e.id}` })),
|
||||
toDomain: vi.fn().mockImplementation((e: unknown) => ({ id: `domain-${(e as { id: string }).id}` })),
|
||||
};
|
||||
|
||||
const gameRepo = new TypeOrmGameRepository(repo as any, mapper as any);
|
||||
const gameRepo = new TypeOrmGameRepository(repo as unknown as Repository<GameOrmEntity>, mapper as unknown as GameOrmMapper);
|
||||
|
||||
const games = await gameRepo.findAll();
|
||||
|
||||
@@ -44,7 +47,7 @@ describe('TypeOrmLeagueWalletRepository', () => {
|
||||
toOrmEntity: vi.fn(),
|
||||
};
|
||||
|
||||
const walletRepo = new TypeOrmLeagueWalletRepository(repo as any, mapper as any);
|
||||
const walletRepo = new TypeOrmLeagueWalletRepository(repo as unknown as Repository<LeagueWalletOrmEntity>, mapper as unknown as LeagueWalletOrmMapper);
|
||||
|
||||
await expect(walletRepo.exists('w1')).resolves.toBe(true);
|
||||
expect(repo.count).toHaveBeenCalledWith({ where: { id: 'w1' } });
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { Repository } from 'typeorm';
|
||||
|
||||
import { TypeOrmPenaltyRepository, TypeOrmProtestRepository } from './StewardingTypeOrmRepositories';
|
||||
import type { PenaltyOrmEntity, ProtestOrmEntity } from '../entities/MissingRacingOrmEntities';
|
||||
import type { PenaltyOrmMapper, ProtestOrmMapper } from '../mappers/StewardingOrmMappers';
|
||||
import type { Penalty } from '@core/racing/domain/entities/Penalty';
|
||||
|
||||
describe('TypeOrmPenaltyRepository', () => {
|
||||
it('findById returns mapped domain when found (DB-free)', async () => {
|
||||
@@ -19,7 +23,7 @@ describe('TypeOrmPenaltyRepository', () => {
|
||||
toOrmEntity: vi.fn(),
|
||||
};
|
||||
|
||||
const penaltyRepo = new TypeOrmPenaltyRepository(repo as any, mapper as any);
|
||||
const penaltyRepo = new TypeOrmPenaltyRepository(repo as unknown as Repository<PenaltyOrmEntity>, mapper as unknown as PenaltyOrmMapper);
|
||||
|
||||
const result = await penaltyRepo.findById('p1');
|
||||
|
||||
@@ -37,9 +41,9 @@ describe('TypeOrmPenaltyRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'p1-orm' }),
|
||||
};
|
||||
|
||||
const penaltyRepo = new TypeOrmPenaltyRepository(repo as any, mapper as any);
|
||||
const penaltyRepo = new TypeOrmPenaltyRepository(repo as unknown as Repository<PenaltyOrmEntity>, mapper as unknown as PenaltyOrmMapper);
|
||||
|
||||
await penaltyRepo.create({ id: 'p1' } as any);
|
||||
await penaltyRepo.create({ id: 'p1' } as unknown as Penalty);
|
||||
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalled();
|
||||
expect(repo.save).toHaveBeenCalledWith({ id: 'p1-orm' });
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { Repository } from 'typeorm';
|
||||
|
||||
import { TypeOrmTeamMembershipRepository, TypeOrmTeamRepository } from './TeamTypeOrmRepositories';
|
||||
import type { TeamOrmEntity, TeamMembershipOrmEntity, TeamJoinRequestOrmEntity } from '../entities/TeamOrmEntities';
|
||||
import type { TeamOrmMapper, TeamMembershipOrmMapper } from '../mappers/TeamOrmMappers';
|
||||
import type { Team } from '@core/racing/domain/entities/Team';
|
||||
import type { TeamMembership } from '@core/racing/domain/entities/TeamMembership';
|
||||
|
||||
describe('TypeOrmTeamRepository', () => {
|
||||
it('uses injected repo + mapper (DB-free)', async () => {
|
||||
@@ -20,7 +25,7 @@ describe('TypeOrmTeamRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'team-1-orm' }),
|
||||
};
|
||||
|
||||
const teamRepo = new TypeOrmTeamRepository(repo as any, mapper as any);
|
||||
const teamRepo = new TypeOrmTeamRepository(repo as unknown as Repository<TeamOrmEntity>, mapper as unknown as TeamOrmMapper);
|
||||
|
||||
const team = await teamRepo.findById('550e8400-e29b-41d4-a716-446655440000');
|
||||
|
||||
@@ -38,11 +43,11 @@ describe('TypeOrmTeamRepository', () => {
|
||||
toOrmEntity: vi.fn().mockReturnValue({ id: 'team-1-orm' }),
|
||||
};
|
||||
|
||||
const teamRepo = new TypeOrmTeamRepository(repo as any, mapper as any);
|
||||
const teamRepo = new TypeOrmTeamRepository(repo as unknown as Repository<TeamOrmEntity>, mapper as unknown as TeamOrmMapper);
|
||||
|
||||
const domainTeam = { id: 'team-1' };
|
||||
const domainTeam = { id: 'team-1' } as unknown as Team;
|
||||
|
||||
await expect(teamRepo.create(domainTeam as any)).resolves.toBe(domainTeam);
|
||||
await expect(teamRepo.create(domainTeam)).resolves.toBe(domainTeam);
|
||||
|
||||
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainTeam);
|
||||
expect(repo.save).toHaveBeenCalledWith({ id: 'team-1-orm' });
|
||||
|
||||
@@ -47,10 +47,10 @@ describe('TypeOrmDriverRepository', () => {
|
||||
avatarRef: MediaReference.createUploaded('media-abc-123'),
|
||||
});
|
||||
|
||||
const savedEntities: any[] = [];
|
||||
const savedEntities: unknown[] = [];
|
||||
|
||||
const repo = {
|
||||
save: async (entity: any) => {
|
||||
save: async (entity: unknown) => {
|
||||
savedEntities.push(entity);
|
||||
return entity;
|
||||
},
|
||||
@@ -68,7 +68,7 @@ describe('TypeOrmDriverRepository', () => {
|
||||
await typeOrmRepo.create(driver);
|
||||
|
||||
expect(savedEntities).toHaveLength(1);
|
||||
expect(savedEntities[0].avatarRef).toEqual({ type: 'uploaded', mediaId: 'media-abc-123' });
|
||||
expect((savedEntities[0] as { avatarRef: unknown }).avatarRef).toEqual({ type: 'uploaded', mediaId: 'media-abc-123' });
|
||||
|
||||
// Test load
|
||||
const loaded = await typeOrmRepo.findById(driverId);
|
||||
@@ -87,10 +87,10 @@ describe('TypeOrmDriverRepository', () => {
|
||||
avatarRef: MediaReference.createSystemDefault('avatar'),
|
||||
});
|
||||
|
||||
const savedEntities: any[] = [];
|
||||
const savedEntities: unknown[] = [];
|
||||
|
||||
const repo = {
|
||||
save: async (entity: any) => {
|
||||
save: async (entity: unknown) => {
|
||||
savedEntities.push(entity);
|
||||
return entity;
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ export class TypeOrmDriverStatsRepository implements DriverStatsRepository {
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
getDriverStatsSync(_driverId: string): DriverStats | null {
|
||||
getDriverStatsSync(): DriverStats | null {
|
||||
// TypeORM repositories don't support synchronous operations
|
||||
// This method is provided for interface compatibility but should not be used
|
||||
// with TypeORM implementations. Return null to indicate it's not supported.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { LeagueOrmMapper } from '../mappers/LeagueOrmMapper';
|
||||
|
||||
import { TypeOrmLeagueRepository } from './TypeOrmLeagueRepository';
|
||||
|
||||
@@ -31,7 +33,7 @@ describe('TypeOrmLeagueRepository', () => {
|
||||
toOrmEntity: vi.fn(),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmLeagueRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmLeagueRepository(dataSource as unknown as DataSource, mapper as unknown as LeagueOrmMapper);
|
||||
|
||||
const league = await repo.findById('l1');
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { RaceOrmMapper } from '../mappers/RaceOrmMapper';
|
||||
|
||||
import { TypeOrmRaceRepository } from './TypeOrmRaceRepository';
|
||||
|
||||
@@ -31,7 +33,7 @@ describe('TypeOrmRaceRepository', () => {
|
||||
toOrmEntity: vi.fn(),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmRaceRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmRaceRepository(dataSource as unknown as DataSource, mapper as unknown as RaceOrmMapper);
|
||||
|
||||
const race = await repo.findById('r1');
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type { DataSource } from 'typeorm';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { SeasonOrmMapper } from '../mappers/SeasonOrmMapper';
|
||||
|
||||
import { TypeOrmSeasonRepository } from './TypeOrmSeasonRepository';
|
||||
|
||||
@@ -31,7 +33,7 @@ describe('TypeOrmSeasonRepository', () => {
|
||||
toOrmEntity: vi.fn(),
|
||||
};
|
||||
|
||||
const repo = new TypeOrmSeasonRepository(dataSource as any, mapper as any);
|
||||
const repo = new TypeOrmSeasonRepository(dataSource as unknown as DataSource, mapper as unknown as SeasonOrmMapper);
|
||||
|
||||
const season = await repo.findById('s1');
|
||||
|
||||
|
||||
1
artifacts/verify/20260125T220700Z/core.eslint.json
Normal file
1
artifacts/verify/20260125T220700Z/core.eslint.json
Normal file
File diff suppressed because one or more lines are too long
@@ -8,13 +8,13 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import type { Mock } from 'vitest';
|
||||
import { GetDashboardUseCase } from './GetDashboardUseCase';
|
||||
import { ValidationError } from '../../../shared/errors/ValidationError';
|
||||
import { DriverNotFoundError } from '../../domain/errors/DriverNotFoundError';
|
||||
import { DashboardRepository } from '../ports/DashboardRepository';
|
||||
import { DashboardRepository, DriverData, RaceData } from '../ports/DashboardRepository';
|
||||
import { DashboardEventPublisher } from '../ports/DashboardEventPublisher';
|
||||
import { Logger } from '../../../shared/domain/Logger';
|
||||
import { DriverData, RaceData, LeagueStandingData, ActivityData } from '../ports/DashboardRepository';
|
||||
|
||||
describe('GetDashboardUseCase', () => {
|
||||
let mockDriverRepository: DashboardRepository;
|
||||
@@ -120,7 +120,7 @@ describe('GetDashboardUseCase', () => {
|
||||
it('should throw DriverNotFoundError when driverRepository.findDriverById returns null', async () => {
|
||||
// Given
|
||||
const query = { driverId: 'driver-123' };
|
||||
(mockDriverRepository.findDriverById as any).mockResolvedValue(null);
|
||||
(mockDriverRepository.findDriverById as Mock).mockResolvedValue(null);
|
||||
|
||||
// When & Then
|
||||
await expect(useCase.execute(query)).rejects.toThrow(DriverNotFoundError);
|
||||
@@ -143,7 +143,7 @@ describe('GetDashboardUseCase', () => {
|
||||
const query = { driverId: 'driver-123' };
|
||||
|
||||
// Mock driver exists
|
||||
(mockDriverRepository.findDriverById as any).mockResolvedValue({
|
||||
(mockDriverRepository.findDriverById as Mock).mockResolvedValue({
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
rating: 1500,
|
||||
@@ -155,7 +155,7 @@ describe('GetDashboardUseCase', () => {
|
||||
} as DriverData);
|
||||
|
||||
// Mock races with missing trackName
|
||||
(mockRaceRepository.getUpcomingRaces as any).mockResolvedValue([
|
||||
(mockRaceRepository.getUpcomingRaces as Mock).mockResolvedValue([
|
||||
{
|
||||
id: 'race-1',
|
||||
trackName: '', // Missing trackName
|
||||
@@ -170,8 +170,8 @@ describe('GetDashboardUseCase', () => {
|
||||
},
|
||||
] as RaceData[]);
|
||||
|
||||
(mockLeagueRepository.getLeagueStandings as any).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as any).mockResolvedValue([]);
|
||||
(mockLeagueRepository.getLeagueStandings as Mock).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as Mock).mockResolvedValue([]);
|
||||
|
||||
// When
|
||||
const result = await useCase.execute(query);
|
||||
@@ -186,7 +186,7 @@ describe('GetDashboardUseCase', () => {
|
||||
const query = { driverId: 'driver-123' };
|
||||
|
||||
// Mock driver exists
|
||||
(mockDriverRepository.findDriverById as any).mockResolvedValue({
|
||||
(mockDriverRepository.findDriverById as Mock).mockResolvedValue({
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
rating: 1500,
|
||||
@@ -198,7 +198,7 @@ describe('GetDashboardUseCase', () => {
|
||||
} as DriverData);
|
||||
|
||||
// Mock races with past dates
|
||||
(mockRaceRepository.getUpcomingRaces as any).mockResolvedValue([
|
||||
(mockRaceRepository.getUpcomingRaces as Mock).mockResolvedValue([
|
||||
{
|
||||
id: 'race-1',
|
||||
trackName: 'Track A',
|
||||
@@ -213,8 +213,8 @@ describe('GetDashboardUseCase', () => {
|
||||
},
|
||||
] as RaceData[]);
|
||||
|
||||
(mockLeagueRepository.getLeagueStandings as any).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as any).mockResolvedValue([]);
|
||||
(mockLeagueRepository.getLeagueStandings as Mock).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as Mock).mockResolvedValue([]);
|
||||
|
||||
// When
|
||||
const result = await useCase.execute(query);
|
||||
@@ -229,7 +229,7 @@ describe('GetDashboardUseCase', () => {
|
||||
const query = { driverId: 'driver-123' };
|
||||
|
||||
// Mock driver exists
|
||||
(mockDriverRepository.findDriverById as any).mockResolvedValue({
|
||||
(mockDriverRepository.findDriverById as Mock).mockResolvedValue({
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
rating: 1500,
|
||||
@@ -241,7 +241,7 @@ describe('GetDashboardUseCase', () => {
|
||||
} as DriverData);
|
||||
|
||||
// Mock races with various invalid states
|
||||
(mockRaceRepository.getUpcomingRaces as any).mockResolvedValue([
|
||||
(mockRaceRepository.getUpcomingRaces as Mock).mockResolvedValue([
|
||||
{
|
||||
id: 'race-1',
|
||||
trackName: '', // Missing trackName
|
||||
@@ -262,8 +262,8 @@ describe('GetDashboardUseCase', () => {
|
||||
},
|
||||
] as RaceData[]);
|
||||
|
||||
(mockLeagueRepository.getLeagueStandings as any).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as any).mockResolvedValue([]);
|
||||
(mockLeagueRepository.getLeagueStandings as Mock).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as Mock).mockResolvedValue([]);
|
||||
|
||||
// When
|
||||
const result = await useCase.execute(query);
|
||||
@@ -278,7 +278,7 @@ describe('GetDashboardUseCase', () => {
|
||||
const query = { driverId: 'driver-123' };
|
||||
|
||||
// Mock driver exists
|
||||
(mockDriverRepository.findDriverById as any).mockResolvedValue({
|
||||
(mockDriverRepository.findDriverById as Mock).mockResolvedValue({
|
||||
id: 'driver-123',
|
||||
name: 'Test Driver',
|
||||
rating: 1500,
|
||||
@@ -290,7 +290,7 @@ describe('GetDashboardUseCase', () => {
|
||||
} as DriverData);
|
||||
|
||||
// Mock races with valid data
|
||||
(mockRaceRepository.getUpcomingRaces as any).mockResolvedValue([
|
||||
(mockRaceRepository.getUpcomingRaces as Mock).mockResolvedValue([
|
||||
{
|
||||
id: 'race-1',
|
||||
trackName: 'Track A',
|
||||
@@ -305,8 +305,8 @@ describe('GetDashboardUseCase', () => {
|
||||
},
|
||||
] as RaceData[]);
|
||||
|
||||
(mockLeagueRepository.getLeagueStandings as any).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as any).mockResolvedValue([]);
|
||||
(mockLeagueRepository.getLeagueStandings as Mock).mockResolvedValue([]);
|
||||
(mockActivityRepository.getRecentActivity as Mock).mockResolvedValue([]);
|
||||
|
||||
// When
|
||||
const result = await useCase.execute(query);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { CheckApiHealthUseCase, CheckApiHealthUseCasePorts } from './CheckApiHealthUseCase';
|
||||
import { CheckApiHealthUseCase } from './CheckApiHealthUseCase';
|
||||
import { HealthCheckQuery, HealthCheckResult } from '../ports/HealthCheckQuery';
|
||||
import { HealthEventPublisher } from '../ports/HealthEventPublisher';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* This Use Case orchestrates the retrieval of connection status information.
|
||||
*/
|
||||
|
||||
import { HealthCheckQuery, ConnectionHealth, ConnectionStatus } from '../ports/HealthCheckQuery';
|
||||
import { HealthCheckQuery, ConnectionStatus } from '../ports/HealthCheckQuery';
|
||||
|
||||
export interface GetConnectionStatusUseCasePorts {
|
||||
healthCheckAdapter: HealthCheckQuery;
|
||||
|
||||
@@ -72,7 +72,7 @@ describe('GetUserRatingLedgerQueryHandler', () => {
|
||||
hasMore: false,
|
||||
});
|
||||
|
||||
const filter: any = {
|
||||
const filter: unknown = {
|
||||
dimensions: ['trust'],
|
||||
sourceTypes: ['vote'],
|
||||
from: '2026-01-01T00:00:00Z',
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { CastAdminVoteUseCase } from './CastAdminVoteUseCase';
|
||||
import { AdminVoteSessionRepository } from '../../domain/repositories/AdminVoteSessionRepository';
|
||||
import { AdminVoteSession } from '../../domain/entities/AdminVoteSession';
|
||||
|
||||
// Mock repository
|
||||
const createMockRepository = () => ({
|
||||
@@ -55,7 +53,7 @@ describe('CastAdminVoteUseCase', () => {
|
||||
const result = await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
voterId: 'voter-123',
|
||||
positive: 'true' as any,
|
||||
positive: 'true' as unknown as boolean,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* Application Use Case Tests: CloseAdminVoteSessionUseCase
|
||||
*
|
||||
*
|
||||
* Tests for closing admin vote sessions and generating rating events
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { CloseAdminVoteSessionUseCase } from './CloseAdminVoteSessionUseCase';
|
||||
import { RatingEventFactory } from '../../domain/services/RatingEventFactory';
|
||||
import { RatingSnapshotCalculator } from '../../domain/services/RatingSnapshotCalculator';
|
||||
import { AdminVoteSessionRepository } from '../../domain/repositories/AdminVoteSessionRepository';
|
||||
import { RatingEventRepository } from '../../domain/repositories/RatingEventRepository';
|
||||
import { UserRatingRepository } from '../../domain/repositories/UserRatingRepository';
|
||||
import { AdminVoteSession } from '../../domain/entities/AdminVoteSession';
|
||||
import { RatingEventFactory } from '../../domain/services/RatingEventFactory';
|
||||
import { RatingSnapshotCalculator } from '../../domain/services/RatingSnapshotCalculator';
|
||||
import { AdminVoteOutcome } from '../../domain/entities/AdminVoteSession';
|
||||
|
||||
// Mock repositories
|
||||
const createMockRepositories = () => ({
|
||||
@@ -55,14 +55,14 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
beforeEach(() => {
|
||||
mockRepositories = createMockRepositories();
|
||||
useCase = new CloseAdminVoteSessionUseCase(
|
||||
mockRepositories.adminVoteSessionRepository,
|
||||
mockRepositories.ratingEventRepository,
|
||||
mockRepositories.userRatingRepository
|
||||
mockRepositories.adminVoteSessionRepository as unknown as AdminVoteSessionRepository,
|
||||
mockRepositories.ratingEventRepository as unknown as RatingEventRepository,
|
||||
mockRepositories.userRatingRepository as unknown as UserRatingRepository
|
||||
);
|
||||
vi.clearAllMocks();
|
||||
// Default mock for RatingEventFactory.createFromVote to return an empty array
|
||||
// to avoid "events is not iterable" error in tests that don't explicitly mock it
|
||||
(RatingEventFactory.createFromVote as any).mockReturnValue([]);
|
||||
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([]);
|
||||
});
|
||||
|
||||
describe('Input validation', () => {
|
||||
@@ -88,7 +88,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should accept valid input', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -148,7 +157,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should find session by ID when provided', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -190,7 +208,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Admin ownership validation', () => {
|
||||
it('should reject when admin does not own the session', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'different-admin',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -231,7 +258,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should accept when admin owns the session', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -273,7 +309,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Session closure validation', () => {
|
||||
it('should reject when session is already closed', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -314,7 +359,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should accept when session is not closed', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -356,7 +410,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Voting window validation', () => {
|
||||
it('should reject when trying to close outside voting window', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -392,7 +455,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
constructor() {
|
||||
super('2026-02-02');
|
||||
}
|
||||
} as any;
|
||||
} as unknown as typeof Date;
|
||||
|
||||
const result = await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -408,7 +471,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should accept when trying to close within voting window', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -444,7 +516,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
constructor() {
|
||||
super('2026-01-15T12:00:00');
|
||||
}
|
||||
} as any;
|
||||
} as unknown as typeof Date;
|
||||
|
||||
const result = await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -461,7 +533,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Session closure', () => {
|
||||
it('should call close method on session', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -501,7 +582,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should save closed session', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -541,7 +631,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should return outcome in success response', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -589,7 +688,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Rating event creation', () => {
|
||||
it('should create rating events when outcome is positive', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -620,7 +728,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
mockRepositories.adminVoteSessionRepository.findById.mockResolvedValue(mockSession);
|
||||
|
||||
const mockEvent = { id: 'event-123' };
|
||||
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent]);
|
||||
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent]);
|
||||
|
||||
await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -639,7 +747,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should create rating events when outcome is negative', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -670,7 +787,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
mockRepositories.adminVoteSessionRepository.findById.mockResolvedValue(mockSession);
|
||||
|
||||
const mockEvent = { id: 'event-123' };
|
||||
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent]);
|
||||
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent]);
|
||||
|
||||
await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -689,7 +806,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should not create rating events when outcome is tie', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -730,7 +856,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should save created rating events', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -762,7 +897,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
const mockEvent1 = { id: 'event-123' };
|
||||
const mockEvent2 = { id: 'event-124' };
|
||||
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent1, mockEvent2]);
|
||||
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent1, mockEvent2]);
|
||||
|
||||
await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -776,7 +911,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should return eventsCreated count', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -808,7 +952,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
const mockEvent1 = { id: 'event-123' };
|
||||
const mockEvent2 = { id: 'event-124' };
|
||||
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent1, mockEvent2]);
|
||||
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent1, mockEvent2]);
|
||||
|
||||
const result = await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -822,7 +966,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Snapshot recalculation', () => {
|
||||
it('should recalculate snapshot when events are created', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -853,13 +1006,13 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
mockRepositories.adminVoteSessionRepository.findById.mockResolvedValue(mockSession);
|
||||
|
||||
const mockEvent = { id: 'event-123' };
|
||||
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent]);
|
||||
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent]);
|
||||
|
||||
const mockAllEvents = [{ id: 'event-1' }, { id: 'event-2' }];
|
||||
mockRepositories.ratingEventRepository.getAllByUserId.mockResolvedValue(mockAllEvents);
|
||||
|
||||
const mockSnapshot = { userId: 'admin-123', overallReputation: 75 };
|
||||
(RatingSnapshotCalculator.calculate as any).mockReturnValue(mockSnapshot);
|
||||
(RatingSnapshotCalculator.calculate as unknown as Mock).mockReturnValue(mockSnapshot);
|
||||
|
||||
await useCase.execute({
|
||||
voteSessionId: 'session-123',
|
||||
@@ -873,7 +1026,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should not recalculate snapshot when no events are created (tie)', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -941,7 +1103,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
|
||||
it('should handle save errors gracefully', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
@@ -985,7 +1156,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
|
||||
describe('Return values', () => {
|
||||
it('should return voteSessionId in success response', async () => {
|
||||
const futureDate = new Date('2026-02-01');
|
||||
const mockSession: any = {
|
||||
const mockSession: {
|
||||
id: string;
|
||||
adminId: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
_closed: boolean;
|
||||
_outcome?: AdminVoteOutcome;
|
||||
close: Mock;
|
||||
closed: boolean;
|
||||
} = {
|
||||
id: 'session-123',
|
||||
adminId: 'admin-123',
|
||||
startDate: new Date('2026-01-01'),
|
||||
|
||||
@@ -171,7 +171,7 @@ describe('OpenAdminVoteSessionUseCase', () => {
|
||||
|
||||
describe('Business rules', () => {
|
||||
it('should reject when session ID already exists', async () => {
|
||||
mockRepository.findById.mockResolvedValue({ id: 'session-1' } as any);
|
||||
mockRepository.findById.mockResolvedValue({ id: 'session-1' } as unknown as AdminVoteSession);
|
||||
|
||||
const result = await useCase.execute({
|
||||
voteSessionId: 'session-1',
|
||||
@@ -193,7 +193,7 @@ describe('OpenAdminVoteSessionUseCase', () => {
|
||||
startDate: new Date('2026-01-05'),
|
||||
endDate: new Date('2026-01-10'),
|
||||
}
|
||||
] as any);
|
||||
] as unknown as AdminVoteSession[]);
|
||||
|
||||
const result = await useCase.execute({
|
||||
voteSessionId: 'session-1',
|
||||
|
||||
@@ -216,7 +216,7 @@ describe('Company', () => {
|
||||
id: 'comp-123',
|
||||
name: 'Acme Racing Team',
|
||||
ownerUserId: 'user-123',
|
||||
contactEmail: null as any,
|
||||
contactEmail: null,
|
||||
createdAt,
|
||||
});
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ describe('PasswordHashingService', () => {
|
||||
|
||||
it('should reject verification with null hash', async () => {
|
||||
// bcrypt throws an error when hash is null, which is expected behavior
|
||||
await expect(service.verify('password', null as any)).rejects.toThrow();
|
||||
await expect(service.verify('password', null as unknown as string)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('should reject verification with empty hash', async () => {
|
||||
|
||||
@@ -216,17 +216,17 @@ describe('EmailAddress', () => {
|
||||
|
||||
describe('Edge cases', () => {
|
||||
it('should handle null input gracefully', () => {
|
||||
const result = validateEmail(null as any);
|
||||
const result = validateEmail(null as unknown as string);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle undefined input gracefully', () => {
|
||||
const result = validateEmail(undefined as any);
|
||||
const result = validateEmail(undefined as unknown as string);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle non-string input gracefully', () => {
|
||||
const result = validateEmail(123 as any);
|
||||
const result = validateEmail(123 as unknown as string);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -305,13 +305,13 @@ describe('EmailAddress', () => {
|
||||
it('should handle null input', () => {
|
||||
// The current implementation throws an error when given null
|
||||
// This is expected behavior - the function expects a string
|
||||
expect(() => isDisposableEmail(null as any)).toThrow();
|
||||
expect(() => isDisposableEmail(null as unknown as string)).toThrow();
|
||||
});
|
||||
|
||||
it('should handle undefined input', () => {
|
||||
// The current implementation throws an error when given undefined
|
||||
// This is expected behavior - the function expects a string
|
||||
expect(() => isDisposableEmail(undefined as any)).toThrow();
|
||||
expect(() => isDisposableEmail(undefined as unknown as string)).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { GetDriverRankingsUseCase, GetDriverRankingsUseCasePorts } from './GetDriverRankingsUseCase';
|
||||
import { ValidationError } from '../../../shared/errors/ValidationError';
|
||||
import { LeaderboardsRepository, LeaderboardDriverData } from '../ports/LeaderboardsRepository';
|
||||
import { LeaderboardsEventPublisher } from '../ports/LeaderboardsEventPublisher';
|
||||
|
||||
describe('GetDriverRankingsUseCase', () => {
|
||||
let mockLeaderboardsRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeaderboardsRepository: LeaderboardsRepository;
|
||||
let mockEventPublisher: LeaderboardsEventPublisher;
|
||||
let ports: GetDriverRankingsUseCasePorts;
|
||||
let useCase: GetDriverRankingsUseCase;
|
||||
|
||||
const mockDrivers = [
|
||||
const mockDrivers: LeaderboardDriverData[] = [
|
||||
{ id: '1', name: 'Alice', rating: 2000, raceCount: 10, teamId: 't1', teamName: 'Team A' },
|
||||
{ id: '2', name: 'Bob', rating: 1500, raceCount: 5, teamId: 't2', teamName: 'Team B' },
|
||||
{ id: '3', name: 'Charlie', rating: 1800, raceCount: 8 },
|
||||
@@ -17,10 +19,14 @@ describe('GetDriverRankingsUseCase', () => {
|
||||
beforeEach(() => {
|
||||
mockLeaderboardsRepository = {
|
||||
findAllDrivers: vi.fn().mockResolvedValue([...mockDrivers]),
|
||||
findAllTeams: vi.fn(),
|
||||
findDriversByTeamId: vi.fn(),
|
||||
};
|
||||
mockEventPublisher = {
|
||||
publishDriverRankingsAccessed: vi.fn().mockResolvedValue(undefined),
|
||||
publishLeaderboardsError: vi.fn().mockResolvedValue(undefined),
|
||||
publishGlobalLeaderboardsAccessed: vi.fn(),
|
||||
publishTeamRankingsAccessed: vi.fn(),
|
||||
};
|
||||
ports = {
|
||||
leaderboardsRepository: mockLeaderboardsRepository,
|
||||
@@ -92,6 +98,6 @@ describe('GetDriverRankingsUseCase', () => {
|
||||
});
|
||||
|
||||
it('should throw ValidationError for invalid sortBy', async () => {
|
||||
await expect(useCase.execute({ sortBy: 'invalid' as any })).rejects.toThrow(ValidationError);
|
||||
await expect(useCase.execute({ sortBy: 'invalid' as unknown as 'name' })).rejects.toThrow(ValidationError);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
DriverRankingsQuery,
|
||||
DriverRankingsResult,
|
||||
DriverRankingEntry,
|
||||
PaginationMetadata,
|
||||
} from '../ports/DriverRankingsQuery';
|
||||
import { ValidationError } from '../../../shared/errors/ValidationError';
|
||||
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { GetGlobalLeaderboardsUseCase, GetGlobalLeaderboardsUseCasePorts } from './GetGlobalLeaderboardsUseCase';
|
||||
import { LeaderboardsRepository, LeaderboardDriverData, LeaderboardTeamData } from '../ports/LeaderboardsRepository';
|
||||
import { LeaderboardsEventPublisher } from '../ports/LeaderboardsEventPublisher';
|
||||
|
||||
describe('GetGlobalLeaderboardsUseCase', () => {
|
||||
let mockLeaderboardsRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeaderboardsRepository: LeaderboardsRepository;
|
||||
let mockEventPublisher: LeaderboardsEventPublisher;
|
||||
let ports: GetGlobalLeaderboardsUseCasePorts;
|
||||
let useCase: GetGlobalLeaderboardsUseCase;
|
||||
|
||||
const mockDrivers = [
|
||||
const mockDrivers: LeaderboardDriverData[] = [
|
||||
{ id: 'd1', name: 'Alice', rating: 2000, raceCount: 10 },
|
||||
{ id: 'd2', name: 'Bob', rating: 1500, raceCount: 5 },
|
||||
];
|
||||
|
||||
const mockTeams = [
|
||||
const mockTeams: LeaderboardTeamData[] = [
|
||||
{ id: 't1', name: 'Team A', rating: 2500, memberCount: 5, raceCount: 20 },
|
||||
{ id: 't2', name: 'Team B', rating: 2200, memberCount: 3, raceCount: 15 },
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeaderboardsRepository = {
|
||||
findAllDrivers: vi.fn().mockResolvedValue([...mockDrivers]),
|
||||
findAllTeams: vi.fn().mockResolvedValue([...mockTeams]),
|
||||
findAllDrivers: vi.fn().mockResolvedValue([...mockDrivers]) as unknown as Mock,
|
||||
findAllTeams: vi.fn().mockResolvedValue([...mockTeams]) as unknown as Mock,
|
||||
findDriversByTeamId: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockEventPublisher = {
|
||||
publishGlobalLeaderboardsAccessed: vi.fn().mockResolvedValue(undefined),
|
||||
publishLeaderboardsError: vi.fn().mockResolvedValue(undefined),
|
||||
publishGlobalLeaderboardsAccessed: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
publishLeaderboardsError: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
publishDriverRankingsAccessed: vi.fn() as unknown as Mock,
|
||||
publishTeamRankingsAccessed: vi.fn() as unknown as Mock,
|
||||
};
|
||||
ports = {
|
||||
leaderboardsRepository: mockLeaderboardsRepository,
|
||||
@@ -57,7 +62,7 @@ describe('GetGlobalLeaderboardsUseCase', () => {
|
||||
});
|
||||
|
||||
it('should handle errors and publish error event', async () => {
|
||||
mockLeaderboardsRepository.findAllDrivers.mockRejectedValue(new Error('Repo error'));
|
||||
(mockLeaderboardsRepository.findAllDrivers as Mock).mockRejectedValue(new Error('Repo error'));
|
||||
|
||||
await expect(useCase.execute()).rejects.toThrow('Repo error');
|
||||
expect(mockEventPublisher.publishLeaderboardsError).toHaveBeenCalled();
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { GetTeamRankingsUseCase, GetTeamRankingsUseCasePorts } from './GetTeamRankingsUseCase';
|
||||
import { ValidationError } from '../../../shared/errors/ValidationError';
|
||||
import { LeaderboardsRepository, LeaderboardTeamData, LeaderboardDriverData } from '../ports/LeaderboardsRepository';
|
||||
import { LeaderboardsEventPublisher } from '../ports/LeaderboardsEventPublisher';
|
||||
|
||||
describe('GetTeamRankingsUseCase', () => {
|
||||
let mockLeaderboardsRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeaderboardsRepository: LeaderboardsRepository;
|
||||
let mockEventPublisher: LeaderboardsEventPublisher;
|
||||
let ports: GetTeamRankingsUseCasePorts;
|
||||
let useCase: GetTeamRankingsUseCase;
|
||||
|
||||
const mockTeams = [
|
||||
const mockTeams: LeaderboardTeamData[] = [
|
||||
{ id: 't1', name: 'Team A', rating: 2500, memberCount: 0, raceCount: 20 },
|
||||
{ id: 't2', name: 'Team B', rating: 2200, memberCount: 0, raceCount: 15 },
|
||||
];
|
||||
|
||||
const mockDrivers = [
|
||||
const mockDrivers: LeaderboardDriverData[] = [
|
||||
{ id: 'd1', name: 'Alice', rating: 2000, raceCount: 10, teamId: 't1', teamName: 'Team A' },
|
||||
{ id: 'd2', name: 'Bob', rating: 1500, raceCount: 5, teamId: 't1', teamName: 'Team A' },
|
||||
{ id: 'd3', name: 'Charlie', rating: 1800, raceCount: 8, teamId: 't2', teamName: 'Team B' },
|
||||
@@ -22,12 +24,15 @@ describe('GetTeamRankingsUseCase', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeaderboardsRepository = {
|
||||
findAllTeams: vi.fn().mockResolvedValue([...mockTeams]),
|
||||
findAllDrivers: vi.fn().mockResolvedValue([...mockDrivers]),
|
||||
findAllTeams: vi.fn().mockResolvedValue([...mockTeams]) as unknown as Mock,
|
||||
findAllDrivers: vi.fn().mockResolvedValue([...mockDrivers]) as unknown as Mock,
|
||||
findDriversByTeamId: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockEventPublisher = {
|
||||
publishTeamRankingsAccessed: vi.fn().mockResolvedValue(undefined),
|
||||
publishLeaderboardsError: vi.fn().mockResolvedValue(undefined),
|
||||
publishTeamRankingsAccessed: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
publishLeaderboardsError: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
publishGlobalLeaderboardsAccessed: vi.fn() as unknown as Mock,
|
||||
publishDriverRankingsAccessed: vi.fn() as unknown as Mock,
|
||||
};
|
||||
ports = {
|
||||
leaderboardsRepository: mockLeaderboardsRepository,
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
TeamRankingsQuery,
|
||||
TeamRankingsResult,
|
||||
TeamRankingEntry,
|
||||
PaginationMetadata,
|
||||
} from '../ports/TeamRankingsQuery';
|
||||
import { ValidationError } from '../../../shared/errors/ValidationError';
|
||||
|
||||
@@ -20,6 +19,14 @@ export interface GetTeamRankingsUseCasePorts {
|
||||
eventPublisher: LeaderboardsEventPublisher;
|
||||
}
|
||||
|
||||
interface DiscoveredTeam {
|
||||
id: string;
|
||||
name: string;
|
||||
rating: number;
|
||||
memberCount: number;
|
||||
raceCount: number;
|
||||
}
|
||||
|
||||
export class GetTeamRankingsUseCase {
|
||||
constructor(private readonly ports: GetTeamRankingsUseCasePorts) {}
|
||||
|
||||
@@ -57,7 +64,7 @@ export class GetTeamRankingsUseCase {
|
||||
});
|
||||
|
||||
// Discover teams that only exist in the drivers repository
|
||||
const discoveredTeams: any[] = [];
|
||||
const discoveredTeams: DiscoveredTeam[] = [];
|
||||
driverCounts.forEach((count, teamId) => {
|
||||
if (!allTeams.some(t => t.id === teamId)) {
|
||||
const driverWithTeam = allDrivers.find(d => d.teamId === teamId);
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
export interface ScoringSystem {
|
||||
// Define scoring system properties based on your domain
|
||||
// This is a placeholder - adjust based on actual scoring system structure
|
||||
pointsPerPosition?: Record<number, number>;
|
||||
bonusPoints?: {
|
||||
polePosition?: number;
|
||||
fastestLap?: number;
|
||||
cleanRace?: number;
|
||||
};
|
||||
penalties?: {
|
||||
timePenalty?: number;
|
||||
pointsDeduction?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface LeagueCreateCommand {
|
||||
name: string;
|
||||
description?: string;
|
||||
@@ -16,7 +31,7 @@ export interface LeagueCreateCommand {
|
||||
tracks?: string[];
|
||||
|
||||
// Scoring
|
||||
scoringSystem?: any;
|
||||
scoringSystem?: ScoringSystem;
|
||||
bonusPointsEnabled: boolean;
|
||||
penaltiesEnabled: boolean;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ScoringSystem } from './LeagueCreateCommand';
|
||||
|
||||
export interface LeagueCreatedEvent {
|
||||
type: 'LeagueCreatedEvent';
|
||||
leagueId: string;
|
||||
@@ -5,10 +7,33 @@ export interface LeagueCreatedEvent {
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
export interface LeagueUpdates {
|
||||
name?: string;
|
||||
description?: string;
|
||||
visibility?: 'public' | 'private';
|
||||
maxDrivers?: number;
|
||||
approvalRequired?: boolean;
|
||||
lateJoinAllowed?: boolean;
|
||||
raceFrequency?: string;
|
||||
raceDay?: string;
|
||||
raceTime?: string;
|
||||
tracks?: string[];
|
||||
scoringSystem?: ScoringSystem;
|
||||
bonusPointsEnabled?: boolean;
|
||||
penaltiesEnabled?: boolean;
|
||||
protestsEnabled?: boolean;
|
||||
appealsEnabled?: boolean;
|
||||
stewardTeam?: string[];
|
||||
gameType?: string;
|
||||
skillLevel?: string;
|
||||
category?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface LeagueUpdatedEvent {
|
||||
type: 'LeagueUpdatedEvent';
|
||||
leagueId: string;
|
||||
updates: Partial<any>;
|
||||
updates: Partial<LeagueUpdates>;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ScoringSystem } from './LeagueCreateCommand';
|
||||
|
||||
export interface LeagueData {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -20,7 +22,7 @@ export interface LeagueData {
|
||||
tracks: string[] | null;
|
||||
|
||||
// Scoring
|
||||
scoringSystem: any | null;
|
||||
scoringSystem: ScoringSystem | null;
|
||||
bonusPointsEnabled: boolean;
|
||||
penaltiesEnabled: boolean;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
import { ApproveMembershipRequestCommand } from '../ports/ApproveMembershipRequestCommand';
|
||||
|
||||
export class ApproveMembershipRequestUseCase {
|
||||
|
||||
@@ -1,28 +1,63 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { CreateLeagueUseCase } from './CreateLeagueUseCase';
|
||||
import { LeagueCreateCommand } from '../ports/LeagueCreateCommand';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { LeagueEventPublisher } from '../ports/LeagueEventPublisher';
|
||||
|
||||
describe('CreateLeagueUseCase', () => {
|
||||
let mockLeagueRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeagueRepository: LeagueRepository;
|
||||
let mockEventPublisher: LeagueEventPublisher;
|
||||
let useCase: CreateLeagueUseCase;
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeagueRepository = {
|
||||
create: vi.fn().mockImplementation((data) => Promise.resolve(data)),
|
||||
updateStats: vi.fn().mockResolvedValue(undefined),
|
||||
updateFinancials: vi.fn().mockResolvedValue(undefined),
|
||||
updateStewardingMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updatePerformanceMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updateRatingMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updateTrendMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updateSuccessRateMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updateResolutionTimeMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updateComplexSuccessRateMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
updateComplexResolutionTimeMetrics: vi.fn().mockResolvedValue(undefined),
|
||||
create: vi.fn().mockImplementation((data) => Promise.resolve(data)) as unknown as Mock,
|
||||
findById: vi.fn() as unknown as Mock,
|
||||
findByName: vi.fn() as unknown as Mock,
|
||||
findByOwner: vi.fn() as unknown as Mock,
|
||||
search: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
getStats: vi.fn() as unknown as Mock,
|
||||
updateStats: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getFinancials: vi.fn() as unknown as Mock,
|
||||
updateFinancials: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
updateStewardingMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getPerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
updatePerformanceMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getRatingMetrics: vi.fn() as unknown as Mock,
|
||||
updateRatingMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getTrendMetrics: vi.fn() as unknown as Mock,
|
||||
updateTrendMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateSuccessRateMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateResolutionTimeMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexSuccessRateMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexResolutionTimeMetrics: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getLeagueMembers: vi.fn() as unknown as Mock,
|
||||
getPendingRequests: vi.fn() as unknown as Mock,
|
||||
addLeagueMembers: vi.fn() as unknown as Mock,
|
||||
updateLeagueMember: vi.fn() as unknown as Mock,
|
||||
removeLeagueMember: vi.fn() as unknown as Mock,
|
||||
addPendingRequests: vi.fn() as unknown as Mock,
|
||||
removePendingRequest: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockEventPublisher = {
|
||||
emitLeagueCreated: vi.fn().mockResolvedValue(undefined),
|
||||
emitLeagueCreated: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
emitLeagueUpdated: vi.fn() as unknown as Mock,
|
||||
emitLeagueDeleted: vi.fn() as unknown as Mock,
|
||||
emitLeagueAccessed: vi.fn() as unknown as Mock,
|
||||
emitLeagueRosterAccessed: vi.fn() as unknown as Mock,
|
||||
getLeagueCreatedEventCount: vi.fn().mockReturnValue(0) as unknown as Mock,
|
||||
getLeagueUpdatedEventCount: vi.fn().mockReturnValue(0) as unknown as Mock,
|
||||
getLeagueDeletedEventCount: vi.fn().mockReturnValue(0) as unknown as Mock,
|
||||
getLeagueAccessedEventCount: vi.fn().mockReturnValue(0) as unknown as Mock,
|
||||
getLeagueRosterAccessedEventCount: vi.fn().mockReturnValue(0) as unknown as Mock,
|
||||
clear: vi.fn() as unknown as Mock,
|
||||
};
|
||||
useCase = new CreateLeagueUseCase(mockLeagueRepository, mockEventPublisher);
|
||||
});
|
||||
@@ -51,12 +86,12 @@ describe('CreateLeagueUseCase', () => {
|
||||
});
|
||||
|
||||
it('should throw error if name is missing', async () => {
|
||||
const command: any = { ownerId: 'owner-1' };
|
||||
const command = { ownerId: 'owner-1' } as unknown as LeagueCreateCommand;
|
||||
await expect(useCase.execute(command)).rejects.toThrow('League name is required');
|
||||
});
|
||||
|
||||
it('should throw error if ownerId is missing', async () => {
|
||||
const command: any = { name: 'League' };
|
||||
const command = { name: 'League' } as unknown as LeagueCreateCommand;
|
||||
await expect(useCase.execute(command)).rejects.toThrow('Owner ID is required');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,76 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { DemoteAdminUseCase } from './DemoteAdminUseCase';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { LeagueEventPublisher } from '../ports/LeagueEventPublisher';
|
||||
|
||||
describe('DemoteAdminUseCase', () => {
|
||||
let mockLeagueRepository: any;
|
||||
let mockDriverRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeagueRepository: LeagueRepository;
|
||||
let mockDriverRepository: DriverRepository;
|
||||
let mockEventPublisher: LeagueEventPublisher;
|
||||
let useCase: DemoteAdminUseCase;
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeagueRepository = {
|
||||
updateLeagueMember: vi.fn().mockResolvedValue(undefined),
|
||||
updateLeagueMember: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
create: vi.fn() as unknown as Mock,
|
||||
findById: vi.fn() as unknown as Mock,
|
||||
findByName: vi.fn() as unknown as Mock,
|
||||
findByOwner: vi.fn() as unknown as Mock,
|
||||
search: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
getStats: vi.fn() as unknown as Mock,
|
||||
updateStats: vi.fn() as unknown as Mock,
|
||||
getFinancials: vi.fn() as unknown as Mock,
|
||||
updateFinancials: vi.fn() as unknown as Mock,
|
||||
getStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
updateStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
getPerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
updatePerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
getRatingMetrics: vi.fn() as unknown as Mock,
|
||||
updateRatingMetrics: vi.fn() as unknown as Mock,
|
||||
getTrendMetrics: vi.fn() as unknown as Mock,
|
||||
updateTrendMetrics: vi.fn() as unknown as Mock,
|
||||
getSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getLeagueMembers: vi.fn() as unknown as Mock,
|
||||
getPendingRequests: vi.fn() as unknown as Mock,
|
||||
addLeagueMembers: vi.fn() as unknown as Mock,
|
||||
removeLeagueMember: vi.fn() as unknown as Mock,
|
||||
addPendingRequests: vi.fn() as unknown as Mock,
|
||||
removePendingRequest: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockDriverRepository = {};
|
||||
mockEventPublisher = {};
|
||||
useCase = new DemoteAdminUseCase(mockLeagueRepository, mockDriverRepository, mockEventPublisher as any);
|
||||
mockDriverRepository = {
|
||||
findById: vi.fn() as unknown as Mock,
|
||||
findByIRacingId: vi.fn() as unknown as Mock,
|
||||
findAll: vi.fn() as unknown as Mock,
|
||||
create: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
exists: vi.fn() as unknown as Mock,
|
||||
existsByIRacingId: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockEventPublisher = {
|
||||
emitLeagueCreated: vi.fn() as unknown as Mock,
|
||||
emitLeagueUpdated: vi.fn() as unknown as Mock,
|
||||
emitLeagueDeleted: vi.fn() as unknown as Mock,
|
||||
emitLeagueAccessed: vi.fn() as unknown as Mock,
|
||||
emitLeagueRosterAccessed: vi.fn() as unknown as Mock,
|
||||
getLeagueCreatedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueUpdatedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueDeletedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueAccessedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueRosterAccessedEventCount: vi.fn() as unknown as Mock,
|
||||
clear: vi.fn() as unknown as Mock,
|
||||
};
|
||||
useCase = new DemoteAdminUseCase(mockLeagueRepository, mockDriverRepository, mockEventPublisher);
|
||||
});
|
||||
|
||||
it('should update member role to member', async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { LeagueEventPublisher } from '../ports/LeagueEventPublisher';
|
||||
import { DemoteAdminCommand } from '../ports/DemoteAdminCommand';
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { GetLeagueRosterUseCase } from './GetLeagueRosterUseCase';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { LeagueEventPublisher } from '../ports/LeagueEventPublisher';
|
||||
|
||||
describe('GetLeagueRosterUseCase', () => {
|
||||
let mockLeagueRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeagueRepository: LeagueRepository;
|
||||
let mockEventPublisher: LeagueEventPublisher;
|
||||
let useCase: GetLeagueRosterUseCase;
|
||||
|
||||
const mockLeague = { id: 'league-1' };
|
||||
@@ -18,12 +20,53 @@ describe('GetLeagueRosterUseCase', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeagueRepository = {
|
||||
findById: vi.fn().mockResolvedValue(mockLeague),
|
||||
getLeagueMembers: vi.fn().mockResolvedValue(mockMembers),
|
||||
getPendingRequests: vi.fn().mockResolvedValue(mockRequests),
|
||||
create: vi.fn() as unknown as Mock,
|
||||
findById: vi.fn().mockResolvedValue(mockLeague) as unknown as Mock,
|
||||
findByName: vi.fn() as unknown as Mock,
|
||||
findByOwner: vi.fn() as unknown as Mock,
|
||||
search: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
getStats: vi.fn() as unknown as Mock,
|
||||
updateStats: vi.fn() as unknown as Mock,
|
||||
getFinancials: vi.fn() as unknown as Mock,
|
||||
updateFinancials: vi.fn() as unknown as Mock,
|
||||
getStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
updateStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
getPerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
updatePerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
getRatingMetrics: vi.fn() as unknown as Mock,
|
||||
updateRatingMetrics: vi.fn() as unknown as Mock,
|
||||
getTrendMetrics: vi.fn() as unknown as Mock,
|
||||
updateTrendMetrics: vi.fn() as unknown as Mock,
|
||||
getSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getLeagueMembers: vi.fn().mockResolvedValue(mockMembers) as unknown as Mock,
|
||||
getPendingRequests: vi.fn().mockResolvedValue(mockRequests) as unknown as Mock,
|
||||
addLeagueMembers: vi.fn() as unknown as Mock,
|
||||
updateLeagueMember: vi.fn() as unknown as Mock,
|
||||
removeLeagueMember: vi.fn() as unknown as Mock,
|
||||
addPendingRequests: vi.fn() as unknown as Mock,
|
||||
removePendingRequest: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockEventPublisher = {
|
||||
emitLeagueRosterAccessed: vi.fn().mockResolvedValue(undefined),
|
||||
emitLeagueCreated: vi.fn() as unknown as Mock,
|
||||
emitLeagueUpdated: vi.fn() as unknown as Mock,
|
||||
emitLeagueDeleted: vi.fn() as unknown as Mock,
|
||||
emitLeagueAccessed: vi.fn() as unknown as Mock,
|
||||
emitLeagueRosterAccessed: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
getLeagueCreatedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueUpdatedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueDeletedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueAccessedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueRosterAccessedEventCount: vi.fn() as unknown as Mock,
|
||||
clear: vi.fn() as unknown as Mock,
|
||||
};
|
||||
useCase = new GetLeagueRosterUseCase(mockLeagueRepository, mockEventPublisher);
|
||||
});
|
||||
@@ -39,7 +82,7 @@ describe('GetLeagueRosterUseCase', () => {
|
||||
});
|
||||
|
||||
it('should throw error if league not found', async () => {
|
||||
mockLeagueRepository.findById.mockResolvedValue(null);
|
||||
(mockLeagueRepository.findById as Mock).mockResolvedValue(null);
|
||||
await expect(useCase.execute({ leagueId: 'invalid' })).rejects.toThrow('League with id invalid not found');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { GetLeagueUseCase, GetLeagueQuery } from './GetLeagueUseCase';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { LeagueEventPublisher } from '../ports/LeagueEventPublisher';
|
||||
|
||||
describe('GetLeagueUseCase', () => {
|
||||
let mockLeagueRepository: any;
|
||||
let mockEventPublisher: any;
|
||||
let mockLeagueRepository: LeagueRepository;
|
||||
let mockEventPublisher: LeagueEventPublisher;
|
||||
let useCase: GetLeagueUseCase;
|
||||
|
||||
const mockLeague = {
|
||||
@@ -14,10 +16,53 @@ describe('GetLeagueUseCase', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeagueRepository = {
|
||||
findById: vi.fn().mockResolvedValue(mockLeague),
|
||||
create: vi.fn() as unknown as Mock,
|
||||
findById: vi.fn().mockResolvedValue(mockLeague) as unknown as Mock,
|
||||
findByName: vi.fn() as unknown as Mock,
|
||||
findByOwner: vi.fn() as unknown as Mock,
|
||||
search: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
getStats: vi.fn() as unknown as Mock,
|
||||
updateStats: vi.fn() as unknown as Mock,
|
||||
getFinancials: vi.fn() as unknown as Mock,
|
||||
updateFinancials: vi.fn() as unknown as Mock,
|
||||
getStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
updateStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
getPerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
updatePerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
getRatingMetrics: vi.fn() as unknown as Mock,
|
||||
updateRatingMetrics: vi.fn() as unknown as Mock,
|
||||
getTrendMetrics: vi.fn() as unknown as Mock,
|
||||
updateTrendMetrics: vi.fn() as unknown as Mock,
|
||||
getSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getLeagueMembers: vi.fn() as unknown as Mock,
|
||||
getPendingRequests: vi.fn() as unknown as Mock,
|
||||
addLeagueMembers: vi.fn() as unknown as Mock,
|
||||
updateLeagueMember: vi.fn() as unknown as Mock,
|
||||
removeLeagueMember: vi.fn() as unknown as Mock,
|
||||
addPendingRequests: vi.fn() as unknown as Mock,
|
||||
removePendingRequest: vi.fn() as unknown as Mock,
|
||||
};
|
||||
mockEventPublisher = {
|
||||
emitLeagueAccessed: vi.fn().mockResolvedValue(undefined),
|
||||
emitLeagueCreated: vi.fn() as unknown as Mock,
|
||||
emitLeagueUpdated: vi.fn() as unknown as Mock,
|
||||
emitLeagueDeleted: vi.fn() as unknown as Mock,
|
||||
emitLeagueAccessed: vi.fn().mockResolvedValue(undefined) as unknown as Mock,
|
||||
emitLeagueRosterAccessed: vi.fn() as unknown as Mock,
|
||||
getLeagueCreatedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueUpdatedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueDeletedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueAccessedEventCount: vi.fn() as unknown as Mock,
|
||||
getLeagueRosterAccessedEventCount: vi.fn() as unknown as Mock,
|
||||
clear: vi.fn() as unknown as Mock,
|
||||
};
|
||||
useCase = new GetLeagueUseCase(mockLeagueRepository, mockEventPublisher);
|
||||
});
|
||||
@@ -39,14 +84,14 @@ describe('GetLeagueUseCase', () => {
|
||||
});
|
||||
|
||||
it('should throw error if league not found', async () => {
|
||||
mockLeagueRepository.findById.mockResolvedValue(null);
|
||||
(mockLeagueRepository.findById as Mock).mockResolvedValue(null);
|
||||
const query: GetLeagueQuery = { leagueId: 'non-existent' };
|
||||
|
||||
await expect(useCase.execute(query)).rejects.toThrow('League with id non-existent not found');
|
||||
});
|
||||
|
||||
it('should throw error if leagueId is missing', async () => {
|
||||
const query: any = {};
|
||||
const query = {} as unknown as GetLeagueQuery;
|
||||
await expect(useCase.execute(query)).rejects.toThrow('League ID is required');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,22 +1,60 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { JoinLeagueUseCase } from './JoinLeagueUseCase';
|
||||
import type { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import type { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import type { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
import type { JoinLeagueCommand } from '../ports/JoinLeagueCommand';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
|
||||
const mockLeagueRepository = {
|
||||
findById: vi.fn(),
|
||||
addPendingRequests: vi.fn(),
|
||||
addLeagueMembers: vi.fn(),
|
||||
const mockLeagueRepository: LeagueRepository = {
|
||||
create: vi.fn() as unknown as Mock,
|
||||
findById: vi.fn() as unknown as Mock,
|
||||
findByName: vi.fn() as unknown as Mock,
|
||||
findByOwner: vi.fn() as unknown as Mock,
|
||||
search: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
getStats: vi.fn() as unknown as Mock,
|
||||
updateStats: vi.fn() as unknown as Mock,
|
||||
getFinancials: vi.fn() as unknown as Mock,
|
||||
updateFinancials: vi.fn() as unknown as Mock,
|
||||
getStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
updateStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
getPerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
updatePerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
getRatingMetrics: vi.fn() as unknown as Mock,
|
||||
updateRatingMetrics: vi.fn() as unknown as Mock,
|
||||
getTrendMetrics: vi.fn() as unknown as Mock,
|
||||
updateTrendMetrics: vi.fn() as unknown as Mock,
|
||||
getSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getLeagueMembers: vi.fn() as unknown as Mock,
|
||||
getPendingRequests: vi.fn() as unknown as Mock,
|
||||
addLeagueMembers: vi.fn() as unknown as Mock,
|
||||
updateLeagueMember: vi.fn() as unknown as Mock,
|
||||
removeLeagueMember: vi.fn() as unknown as Mock,
|
||||
addPendingRequests: vi.fn() as unknown as Mock,
|
||||
removePendingRequest: vi.fn() as unknown as Mock,
|
||||
};
|
||||
|
||||
const mockDriverRepository = {
|
||||
findDriverById: vi.fn(),
|
||||
const mockDriverRepository: DriverRepository = {
|
||||
findById: vi.fn() as unknown as Mock,
|
||||
findByIRacingId: vi.fn() as unknown as Mock,
|
||||
findAll: vi.fn() as unknown as Mock,
|
||||
create: vi.fn() as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
exists: vi.fn() as unknown as Mock,
|
||||
existsByIRacingId: vi.fn() as unknown as Mock,
|
||||
};
|
||||
|
||||
const mockEventPublisher = {
|
||||
publish: vi.fn(),
|
||||
const mockEventPublisher: EventPublisher = {
|
||||
publish: vi.fn() as unknown as Mock,
|
||||
};
|
||||
|
||||
describe('JoinLeagueUseCase', () => {
|
||||
@@ -27,9 +65,9 @@ describe('JoinLeagueUseCase', () => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
useCase = new JoinLeagueUseCase(
|
||||
mockLeagueRepository as any,
|
||||
mockDriverRepository as any,
|
||||
mockEventPublisher as any
|
||||
mockLeagueRepository,
|
||||
mockDriverRepository,
|
||||
mockEventPublisher
|
||||
);
|
||||
});
|
||||
|
||||
@@ -41,7 +79,7 @@ describe('JoinLeagueUseCase', () => {
|
||||
driverId: 'driver-456',
|
||||
};
|
||||
|
||||
mockLeagueRepository.findById.mockImplementation(() => Promise.resolve(null));
|
||||
(mockLeagueRepository.findById as Mock).mockImplementation(() => Promise.resolve(null));
|
||||
|
||||
// When & Then
|
||||
await expect(useCase.execute(command)).rejects.toThrow('League not found');
|
||||
@@ -85,13 +123,13 @@ describe('JoinLeagueUseCase', () => {
|
||||
tags: null,
|
||||
};
|
||||
|
||||
mockLeagueRepository.findById.mockImplementation(() => Promise.resolve(mockLeague));
|
||||
mockDriverRepository.findDriverById.mockImplementation(() => Promise.resolve(null));
|
||||
(mockLeagueRepository.findById as Mock).mockImplementation(() => Promise.resolve(mockLeague));
|
||||
(mockDriverRepository.findById as Mock).mockImplementation(() => Promise.resolve(null));
|
||||
|
||||
// When & Then
|
||||
await expect(useCase.execute(command)).rejects.toThrow('Driver not found');
|
||||
expect(mockLeagueRepository.findById).toHaveBeenCalledWith('league-123');
|
||||
expect(mockDriverRepository.findDriverById).toHaveBeenCalledWith('driver-456');
|
||||
expect(mockDriverRepository.findById).toHaveBeenCalledWith('driver-456');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -144,8 +182,8 @@ describe('JoinLeagueUseCase', () => {
|
||||
const frozenTime = new Date('2024-01-01T00:00:00.000Z');
|
||||
vi.setSystemTime(frozenTime);
|
||||
|
||||
mockLeagueRepository.findById.mockResolvedValue(mockLeague);
|
||||
mockDriverRepository.findDriverById.mockResolvedValue(mockDriver);
|
||||
(mockLeagueRepository.findById as Mock).mockResolvedValue(mockLeague);
|
||||
(mockDriverRepository.findById as Mock).mockResolvedValue(mockDriver);
|
||||
|
||||
// When
|
||||
await useCase.execute(command);
|
||||
@@ -216,8 +254,8 @@ describe('JoinLeagueUseCase', () => {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
mockLeagueRepository.findById.mockResolvedValue(mockLeague);
|
||||
mockDriverRepository.findDriverById.mockResolvedValue(mockDriver);
|
||||
(mockLeagueRepository.findById as Mock).mockResolvedValue(mockLeague);
|
||||
(mockDriverRepository.findById as Mock).mockResolvedValue(mockDriver);
|
||||
|
||||
// When
|
||||
await useCase.execute(command);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LeagueRepository, LeagueData } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
import { JoinLeagueCommand } from '../ports/JoinLeagueCommand';
|
||||
|
||||
export class JoinLeagueUseCase {
|
||||
@@ -16,7 +16,7 @@ export class JoinLeagueUseCase {
|
||||
throw new Error('League not found');
|
||||
}
|
||||
|
||||
const driver = await this.driverRepository.findDriverById(command.driverId);
|
||||
const driver = await this.driverRepository.findById(command.driverId);
|
||||
if (!driver) {
|
||||
throw new Error('Driver not found');
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export class JoinLeagueUseCase {
|
||||
{
|
||||
id: `request-${Date.now()}`,
|
||||
driverId: command.driverId,
|
||||
name: driver.name,
|
||||
name: driver.name.toString(),
|
||||
requestDate: new Date(),
|
||||
},
|
||||
]);
|
||||
@@ -34,7 +34,7 @@ export class JoinLeagueUseCase {
|
||||
await this.leagueRepository.addLeagueMembers(command.leagueId, [
|
||||
{
|
||||
driverId: command.driverId,
|
||||
name: driver.name,
|
||||
name: driver.name.toString(),
|
||||
role: 'member',
|
||||
joinDate: new Date(),
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
import { LeaveLeagueCommand } from '../ports/LeaveLeagueCommand';
|
||||
|
||||
export class LeaveLeagueUseCase {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
import { PromoteMemberCommand } from '../ports/PromoteMemberCommand';
|
||||
|
||||
export class PromoteMemberUseCase {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { LeagueEventPublisher } from '../ports/LeagueEventPublisher';
|
||||
import { RejectMembershipRequestCommand } from '../ports/RejectMembershipRequestCommand';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { DriverRepository } from '../../../racing/domain/repositories/DriverRepository';
|
||||
import { EventPublisher } from '../../../shared/ports/EventPublisher';
|
||||
import { RemoveMemberCommand } from '../ports/RemoveMemberCommand';
|
||||
|
||||
export class RemoveMemberUseCase {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
||||
import { SearchLeaguesUseCase, SearchLeaguesQuery } from './SearchLeaguesUseCase';
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
|
||||
describe('SearchLeaguesUseCase', () => {
|
||||
let mockLeagueRepository: any;
|
||||
let mockLeagueRepository: LeagueRepository;
|
||||
let useCase: SearchLeaguesUseCase;
|
||||
|
||||
const mockLeagues = [
|
||||
@@ -13,7 +14,40 @@ describe('SearchLeaguesUseCase', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
mockLeagueRepository = {
|
||||
search: vi.fn().mockResolvedValue([...mockLeagues]),
|
||||
create: vi.fn() as unknown as Mock,
|
||||
findById: vi.fn() as unknown as Mock,
|
||||
findByName: vi.fn() as unknown as Mock,
|
||||
findByOwner: vi.fn() as unknown as Mock,
|
||||
search: vi.fn().mockResolvedValue([...mockLeagues]) as unknown as Mock,
|
||||
update: vi.fn() as unknown as Mock,
|
||||
delete: vi.fn() as unknown as Mock,
|
||||
getStats: vi.fn() as unknown as Mock,
|
||||
updateStats: vi.fn() as unknown as Mock,
|
||||
getFinancials: vi.fn() as unknown as Mock,
|
||||
updateFinancials: vi.fn() as unknown as Mock,
|
||||
getStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
updateStewardingMetrics: vi.fn() as unknown as Mock,
|
||||
getPerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
updatePerformanceMetrics: vi.fn() as unknown as Mock,
|
||||
getRatingMetrics: vi.fn() as unknown as Mock,
|
||||
updateRatingMetrics: vi.fn() as unknown as Mock,
|
||||
getTrendMetrics: vi.fn() as unknown as Mock,
|
||||
updateTrendMetrics: vi.fn() as unknown as Mock,
|
||||
getSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexSuccessRateMetrics: vi.fn() as unknown as Mock,
|
||||
getComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
updateComplexResolutionTimeMetrics: vi.fn() as unknown as Mock,
|
||||
getLeagueMembers: vi.fn() as unknown as Mock,
|
||||
getPendingRequests: vi.fn() as unknown as Mock,
|
||||
addLeagueMembers: vi.fn() as unknown as Mock,
|
||||
updateLeagueMember: vi.fn() as unknown as Mock,
|
||||
removeLeagueMember: vi.fn() as unknown as Mock,
|
||||
addPendingRequests: vi.fn() as unknown as Mock,
|
||||
removePendingRequest: vi.fn() as unknown as Mock,
|
||||
};
|
||||
useCase = new SearchLeaguesUseCase(mockLeagueRepository);
|
||||
});
|
||||
@@ -35,7 +69,7 @@ describe('SearchLeaguesUseCase', () => {
|
||||
});
|
||||
|
||||
it('should throw error if query is missing', async () => {
|
||||
const query: any = { query: '' };
|
||||
const query = { query: '' } as unknown as SearchLeaguesQuery;
|
||||
await expect(useCase.execute(query)).rejects.toThrow('Search query is required');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('GetUploadedMediaUseCase', () => {
|
||||
const mockMetadata = { size: 9 };
|
||||
|
||||
mediaStorage.getBytes.mockResolvedValue(mockBytes);
|
||||
mediaStorage.getMetadata.mockResolvedValue(mockMetadata as any);
|
||||
mediaStorage.getMetadata.mockResolvedValue(mockMetadata as unknown as { size: number; contentType?: string });
|
||||
|
||||
const input = { storageKey: 'media-key' };
|
||||
const result = await useCase.execute(input);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Result } from '@core/shared/domain/Result';
|
||||
import { describe, expect, it, vi, type Mock } from 'vitest';
|
||||
import type { MediaResolverPort } from '@core/ports/media/MediaResolverPort';
|
||||
import { ResolveMediaReferenceUseCase } from './ResolveMediaReferenceUseCase';
|
||||
|
||||
@@ -23,11 +23,11 @@ describe('AvatarId', () => {
|
||||
});
|
||||
|
||||
it('throws error when null', () => {
|
||||
expect(() => AvatarId.create(null as any)).toThrow('Avatar ID cannot be empty');
|
||||
expect(() => AvatarId.create(null as unknown as string)).toThrow('Avatar ID cannot be empty');
|
||||
});
|
||||
|
||||
it('throws error when undefined', () => {
|
||||
expect(() => AvatarId.create(undefined as any)).toThrow('Avatar ID cannot be empty');
|
||||
expect(() => AvatarId.create(undefined as unknown as string)).toThrow('Avatar ID cannot be empty');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -19,15 +19,6 @@ describe('NotificationGateway - Interface Contract', () => {
|
||||
getChannel: vi.fn().mockReturnValue('in_app'),
|
||||
};
|
||||
|
||||
const notification = Notification.create({
|
||||
id: 'test-id',
|
||||
recipientId: 'driver-1',
|
||||
type: 'system_announcement',
|
||||
title: 'Test',
|
||||
body: 'Test body',
|
||||
channel: 'in_app',
|
||||
});
|
||||
|
||||
expect(mockGateway.send).toBeDefined();
|
||||
expect(typeof mockGateway.send).toBe('function');
|
||||
});
|
||||
|
||||
@@ -201,17 +201,6 @@ describe('NotificationPreferenceRepository - Integration', () => {
|
||||
it('handles workflow: get or create, then update', async () => {
|
||||
const defaultPreference = NotificationPreference.createDefault('driver-1');
|
||||
|
||||
const updatedPreference = NotificationPreference.create({
|
||||
id: 'driver-1',
|
||||
driverId: 'driver-1',
|
||||
channels: {
|
||||
in_app: { enabled: true },
|
||||
email: { enabled: true },
|
||||
discord: { enabled: false },
|
||||
push: { enabled: false },
|
||||
},
|
||||
});
|
||||
|
||||
const mockRepository: NotificationPreferenceRepository = {
|
||||
findByDriverId: vi.fn().mockResolvedValue(null),
|
||||
save: vi.fn().mockResolvedValue(undefined),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user