code quality
Some checks failed
CI / lint-typecheck (pull_request) Failing after 12s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped

This commit is contained in:
2026-01-26 12:52:24 +01:00
parent f877f821ef
commit cfc30c79a8
62 changed files with 227 additions and 173 deletions

View File

@@ -231,9 +231,9 @@ describe('TypeOrmPersistenceSchemaAdapter', () => {
}); });
// When // When
(error as any).entityName = 'NewEntity'; (error as { entityName: string }).entityName = 'NewEntity';
(error as any).fieldName = 'newField'; (error as { fieldName: string }).fieldName = 'newField';
(error as any).reason = 'new_reason'; (error as { reason: string }).reason = 'new_reason';
// Then // Then
expect(error.entityName).toBe('NewEntity'); expect(error.entityName).toBe('NewEntity');

View File

@@ -226,7 +226,7 @@ describe('AchievementOrmMapper', () => {
// Given // Given
const entity = new AchievementOrmEntity(); const entity = new AchievementOrmEntity();
entity.id = 'ach-123'; entity.id = 'ach-123';
entity.name = 123 as any; (entity as unknown as { name: unknown }).name = 123;
entity.description = 'Complete your first race'; entity.description = 'Complete your first race';
entity.category = 'driver'; entity.category = 'driver';
entity.rarity = 'common'; entity.rarity = 'common';
@@ -257,7 +257,7 @@ describe('AchievementOrmMapper', () => {
entity.id = 'ach-123'; entity.id = 'ach-123';
entity.name = 'First Race'; entity.name = 'First Race';
entity.description = 'Complete your 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.rarity = 'common';
entity.points = 10; entity.points = 10;
entity.requirements = [ entity.requirements = [
@@ -318,7 +318,7 @@ describe('AchievementOrmMapper', () => {
entity.category = 'driver'; entity.category = 'driver';
entity.rarity = 'common'; entity.rarity = 'common';
entity.points = 10; entity.points = 10;
entity.requirements = 'not_an_array' as any; (entity as unknown as { requirements: unknown }).requirements = 'not_an_array';
entity.isSecret = false; entity.isSecret = false;
entity.createdAt = new Date('2024-01-01'); entity.createdAt = new Date('2024-01-01');
@@ -345,7 +345,7 @@ describe('AchievementOrmMapper', () => {
entity.category = 'driver'; entity.category = 'driver';
entity.rarity = 'common'; entity.rarity = 'common';
entity.points = 10; entity.points = 10;
entity.requirements = [null as any]; (entity as unknown as { requirements: unknown[] }).requirements = [null];
entity.isSecret = false; entity.isSecret = false;
entity.createdAt = new Date('2024-01-01'); entity.createdAt = new Date('2024-01-01');
@@ -372,7 +372,7 @@ describe('AchievementOrmMapper', () => {
entity.category = 'driver'; entity.category = 'driver';
entity.rarity = 'common'; entity.rarity = 'common';
entity.points = 10; 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.isSecret = false;
entity.createdAt = new Date('2024-01-01'); entity.createdAt = new Date('2024-01-01');
@@ -399,7 +399,7 @@ describe('AchievementOrmMapper', () => {
entity.category = 'driver'; entity.category = 'driver';
entity.rarity = 'common'; entity.rarity = 'common';
entity.points = 10; 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.isSecret = false;
entity.createdAt = new Date('2024-01-01'); entity.createdAt = new Date('2024-01-01');
@@ -430,7 +430,7 @@ describe('AchievementOrmMapper', () => {
{ type: 'races_completed', value: 1, operator: '>=' }, { type: 'races_completed', value: 1, operator: '>=' },
]; ];
entity.isSecret = false; entity.isSecret = false;
entity.createdAt = 'not_a_date' as any; (entity as unknown as { createdAt: unknown }).createdAt = 'not_a_date';
// When & Then // When & Then
expect(() => mapper.toDomain(entity)).toThrow(TypeOrmPersistenceSchemaAdapter); expect(() => mapper.toDomain(entity)).toThrow(TypeOrmPersistenceSchemaAdapter);
@@ -571,7 +571,7 @@ describe('AchievementOrmMapper', () => {
// Given // Given
const entity = new UserAchievementOrmEntity(); const entity = new UserAchievementOrmEntity();
entity.id = 'ua-123'; entity.id = 'ua-123';
entity.userId = 123 as any; (entity as unknown as { userId: unknown }).userId = 123;
entity.achievementId = 'ach-789'; entity.achievementId = 'ach-789';
entity.earnedAt = new Date('2024-01-01'); entity.earnedAt = new Date('2024-01-01');
entity.progress = 50; entity.progress = 50;
@@ -621,7 +621,7 @@ describe('AchievementOrmMapper', () => {
entity.id = 'ua-123'; entity.id = 'ua-123';
entity.userId = 'user-456'; entity.userId = 'user-456';
entity.achievementId = 'ach-789'; 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.progress = 50;
entity.notifiedAt = null; entity.notifiedAt = null;

View File

@@ -1,10 +1,10 @@
import { vi } from 'vitest'; 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 { Achievement } from '@core/identity/domain/entities/Achievement';
import { UserAchievement } from '@core/identity/domain/entities/UserAchievement'; import { UserAchievement } from '@core/identity/domain/entities/UserAchievement';
import { AchievementOrmEntity } from '../entities/AchievementOrmEntity'; import { AchievementOrmEntity } from '../entities/AchievementOrmEntity';
import { UserAchievementOrmEntity } from '../entities/UserAchievementOrmEntity'; import { UserAchievementOrmEntity } from '../entities/UserAchievementOrmEntity';
import { AchievementOrmMapper } from '../mappers/AchievementOrmMapper';
import { TypeOrmAchievementRepository } from './TypeOrmAchievementRepository'; import { TypeOrmAchievementRepository } from './TypeOrmAchievementRepository';
describe('TypeOrmAchievementRepository', () => { describe('TypeOrmAchievementRepository', () => {
@@ -48,7 +48,7 @@ describe('TypeOrmAchievementRepository', () => {
}; };
// When: repository is instantiated with mocked dependencies // 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', () => { describe('DI Boundary - Constructor', () => {
@@ -65,8 +65,8 @@ describe('TypeOrmAchievementRepository', () => {
// Then: it should have injected dependencies // Then: it should have injected dependencies
it('should have injected dependencies', () => { it('should have injected dependencies', () => {
// Given & When & Then // Given & When & Then
expect((repository as any).dataSource).toBe(mockDataSource); expect((repository as unknown as { dataSource: unknown }).dataSource).toBe(mockDataSource);
expect((repository as any).mapper).toBe(mockMapper); expect((repository as unknown as { mapper: unknown }).mapper).toBe(mockMapper);
}); });
// Given: repository instance // Given: repository instance

View File

@@ -571,8 +571,8 @@ describe('AdminUserOrmEntity', () => {
const entity = new AdminUserOrmEntity(); const entity = new AdminUserOrmEntity();
// Act // Act
entity.primaryDriverId = null as any; (entity as unknown as { primaryDriverId: unknown }).primaryDriverId = null;
entity.lastLoginAt = null as any; (entity as unknown as { lastLoginAt: unknown }).lastLoginAt = null;
// Assert // Assert
expect(entity.primaryDriverId).toBeNull(); expect(entity.primaryDriverId).toBeNull();

View File

@@ -55,12 +55,12 @@ describe('AnalyticsSnapshotOrmMapper', () => {
// Given // Given
const orm = new AnalyticsSnapshotOrmEntity(); const orm = new AnalyticsSnapshotOrmEntity();
orm.id = ''; // Invalid: empty orm.id = ''; // Invalid: empty
orm.entityType = 'league' as any; (orm as unknown as { entityType: unknown }).entityType = 'league';
orm.entityId = 'league-1'; orm.entityId = 'league-1';
orm.period = 'daily' as any; (orm as unknown as { period: unknown }).period = 'daily';
orm.startDate = new Date(); orm.startDate = new Date();
orm.endDate = 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(); orm.createdAt = new Date();
// When / Then // When / Then
@@ -71,20 +71,24 @@ describe('AnalyticsSnapshotOrmMapper', () => {
// Given // Given
const orm = new AnalyticsSnapshotOrmEntity(); const orm = new AnalyticsSnapshotOrmEntity();
orm.id = 'snap_1'; orm.id = 'snap_1';
orm.entityType = 'league' as any; (orm as unknown as { entityType: unknown }).entityType = 'league';
orm.entityId = 'league-1'; orm.entityId = 'league-1';
orm.period = 'daily' as any; (orm as unknown as { period: unknown }).period = 'daily';
orm.startDate = new Date(); orm.startDate = new Date();
orm.endDate = 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(); orm.createdAt = new Date();
// When / Then // When / Then
expect(() => mapper.toDomain(orm)).toThrow(TypeOrmAnalyticsSchemaError); expect(() => mapper.toDomain(orm)).toThrow(TypeOrmAnalyticsSchemaError);
try { try {
mapper.toDomain(orm); mapper.toDomain(orm);
} catch (e: any) { } catch (e: unknown) {
expect(e.fieldName).toContain('metrics.'); if (e instanceof TypeOrmAnalyticsSchemaError) {
expect(e.fieldName).toContain('metrics.');
} else {
throw e;
}
} }
}); });
}); });

View File

@@ -68,10 +68,10 @@ describe('EngagementEventOrmMapper', () => {
// Given // Given
const orm = new EngagementEventOrmEntity(); const orm = new EngagementEventOrmEntity();
orm.id = ''; // Invalid orm.id = ''; // Invalid
orm.action = 'invalid_action' as any; (orm as unknown as { action: unknown }).action = 'invalid_action';
orm.entityType = 'league' as any; (orm as unknown as { entityType: unknown }).entityType = 'league';
orm.entityId = 'league-1'; orm.entityId = 'league-1';
orm.actorType = 'anonymous' as any; (orm as unknown as { actorType: unknown }).actorType = 'anonymous';
orm.sessionId = 'sess-1'; orm.sessionId = 'sess-1';
orm.timestamp = new Date(); orm.timestamp = new Date();
@@ -83,21 +83,25 @@ describe('EngagementEventOrmMapper', () => {
// Given // Given
const orm = new EngagementEventOrmEntity(); const orm = new EngagementEventOrmEntity();
orm.id = 'eng_1'; orm.id = 'eng_1';
orm.action = 'click_sponsor_logo' as any; (orm as unknown as { action: unknown }).action = 'click_sponsor_logo';
orm.entityType = 'sponsor' as any; (orm as unknown as { entityType: unknown }).entityType = 'sponsor';
orm.entityId = 'sponsor-1'; orm.entityId = 'sponsor-1';
orm.actorType = 'driver' as any; (orm as unknown as { actorType: unknown }).actorType = 'driver';
orm.sessionId = 'sess-1'; orm.sessionId = 'sess-1';
orm.timestamp = new Date(); orm.timestamp = new Date();
orm.metadata = { invalid: { nested: 'object' } } as any; (orm as unknown as { metadata: unknown }).metadata = { invalid: { nested: 'object' } };
// When / Then // When / Then
expect(() => mapper.toDomain(orm)).toThrow(TypeOrmAnalyticsSchemaError); expect(() => mapper.toDomain(orm)).toThrow(TypeOrmAnalyticsSchemaError);
try { try {
mapper.toDomain(orm); mapper.toDomain(orm);
} catch (e: any) { } catch (e: unknown) {
expect(e.reason).toBe('invalid_shape'); if (e instanceof TypeOrmAnalyticsSchemaError) {
expect(e.fieldName).toBe('metadata'); expect(e.reason).toBe('invalid_shape');
expect(e.fieldName).toBe('metadata');
} else {
throw e;
}
} }
}); });
}); });

View File

@@ -31,7 +31,7 @@ describe('TypeOrmAnalyticsSnapshotRepository', () => {
period: 'daily', period: 'daily',
startDate: new Date(), startDate: new Date(),
endDate: new Date(), endDate: new Date(),
metrics: {} as any, metrics: {} as unknown as any,
createdAt: new Date(), createdAt: new Date(),
}); });
@@ -55,7 +55,7 @@ describe('TypeOrmAnalyticsSnapshotRepository', () => {
period: 'daily', period: 'daily',
startDate: new Date(), startDate: new Date(),
endDate: new Date(), endDate: new Date(),
metrics: {} as any, metrics: {} as unknown as any,
createdAt: new Date(), createdAt: new Date(),
}); });

View File

@@ -81,8 +81,8 @@ describe('TypeOrmEngagementRepository', () => {
// Given // Given
const repo: Repository<EngagementEventOrmEntity> = { const repo: Repository<EngagementEventOrmEntity> = {
count: vi.fn().mockResolvedValue(5), count: vi.fn().mockResolvedValue(5),
} as any; } as unknown as Repository<EngagementEventOrmEntity>;
const sut = new TypeOrmEngagementRepository(repo, {} as any); const sut = new TypeOrmEngagementRepository(repo, {} as unknown as EngagementEventOrmMapper);
const since = new Date(); const since = new Date();
// When // When

View File

@@ -79,16 +79,16 @@ describe('SeedDemoUsers', () => {
]; ];
// Mock repositories to return null (users don't exist) // Mock repositories to return null (users don't exist)
(authRepository.findByEmail as any).mockResolvedValue(null); vi.mocked(authRepository.findByEmail).mockResolvedValue(null);
(adminUserRepository.findByEmail as any).mockResolvedValue(null); vi.mocked(adminUserRepository.findByEmail).mockResolvedValue(null);
(adminUserRepository.create as any).mockImplementation((user: AdminUser) => user); vi.mocked(adminUserRepository.create).mockImplementation(async (user: AdminUser) => user);
(authRepository.save as any).mockResolvedValue(undefined); vi.mocked(authRepository.save).mockResolvedValue(undefined);
await seed.execute(); await seed.execute();
// Verify that findByEmail was called for each expected email // Verify that findByEmail was called for each expected email
const calls = (authRepository.findByEmail as any).mock.calls; const calls = vi.mocked(authRepository.findByEmail).mock.calls;
const emailsCalled = calls.map((call: any) => call[0].value); const emailsCalled = calls.map((call) => call[0].value);
expect(emailsCalled).toEqual(expect.arrayContaining(expectedEmails)); expect(emailsCalled).toEqual(expect.arrayContaining(expectedEmails));
expect(emailsCalled.length).toBeGreaterThanOrEqual(7); expect(emailsCalled.length).toBeGreaterThanOrEqual(7);
@@ -98,10 +98,10 @@ describe('SeedDemoUsers', () => {
const seed = new SeedDemoUsers(logger, authRepository, passwordHashingService, adminUserRepository); const seed = new SeedDemoUsers(logger, authRepository, passwordHashingService, adminUserRepository);
// Mock repositories to return null (users don't exist) // Mock repositories to return null (users don't exist)
(authRepository.findByEmail as any).mockResolvedValue(null); vi.mocked(authRepository.findByEmail).mockResolvedValue(null);
(adminUserRepository.findByEmail as any).mockResolvedValue(null); vi.mocked(adminUserRepository.findByEmail).mockResolvedValue(null);
(adminUserRepository.create as any).mockImplementation((user: AdminUser) => user); vi.mocked(adminUserRepository.create).mockImplementation(async (user: AdminUser) => user);
(authRepository.save as any).mockResolvedValue(undefined); vi.mocked(authRepository.save).mockResolvedValue(undefined);
await seed.execute(); await seed.execute();
@@ -118,15 +118,15 @@ describe('SeedDemoUsers', () => {
const seed = new SeedDemoUsers(logger, authRepository, passwordHashingService, adminUserRepository); const seed = new SeedDemoUsers(logger, authRepository, passwordHashingService, adminUserRepository);
// Mock repositories to return null (users don't exist) // Mock repositories to return null (users don't exist)
(authRepository.findByEmail as any).mockResolvedValue(null); vi.mocked(authRepository.findByEmail).mockResolvedValue(null);
(adminUserRepository.findByEmail as any).mockResolvedValue(null); vi.mocked(adminUserRepository.findByEmail).mockResolvedValue(null);
(adminUserRepository.create as any).mockImplementation((user: AdminUser) => user); vi.mocked(adminUserRepository.create).mockImplementation(async (user: AdminUser) => user);
(authRepository.save as any).mockResolvedValue(undefined); vi.mocked(authRepository.save).mockResolvedValue(undefined);
await seed.execute(); await seed.execute();
// Verify that users were saved with UUIDs // 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); expect(saveCalls.length).toBeGreaterThanOrEqual(7);
// Check that IDs are UUIDs (deterministic from seed keys) // Check that IDs are UUIDs (deterministic from seed keys)
@@ -173,9 +173,6 @@ describe('SeedDemoUsers', () => {
await seed.execute(); await seed.execute();
const firstSaveCount = (authRepository.save as any).mock.calls.length;
const firstAdminCreateCount = (adminUserRepository.create as any).mock.calls.length;
// Reset mocks // Reset mocks
vi.clearAllMocks(); vi.clearAllMocks();

View File

@@ -310,7 +310,7 @@ export class SeedRacingData {
// ignore duplicates // 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') { if (typeof seedableFeed.seed === 'function') {
seedableFeed.seed({ seedableFeed.seed({
drivers: seed.drivers, 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') { if (typeof seedableSocial.seed === 'function') {
seedableSocial.seed({ seedableSocial.seed({
drivers: seed.drivers, drivers: seed.drivers,

View File

@@ -15,7 +15,7 @@ import {
DisconnectedEvent, DisconnectedEvent,
DegradedEvent, DegradedEvent,
CheckingEvent, CheckingEvent,
} from '../../../core/health/ports/HealthEventPublisher'; } from '../../core/health/ports/HealthEventPublisher';
export interface HealthCheckCompletedEventWithType { export interface HealthCheckCompletedEventWithType {
type: 'HealthCheckCompleted'; type: 'HealthCheckCompleted';

View File

@@ -69,7 +69,7 @@ export class InMemoryHealthCheckAdapter implements HealthCheckQuery {
await new Promise(resolve => setTimeout(resolve, this.responseTime)); await new Promise(resolve => setTimeout(resolve, this.responseTime));
if (this.shouldFail) { if (this.shouldFail) {
this.recordFailure(this.failError); this.recordFailure();
return { return {
healthy: false, healthy: false,
responseTime: this.responseTime, responseTime: this.responseTime,
@@ -141,7 +141,7 @@ export class InMemoryHealthCheckAdapter implements HealthCheckQuery {
/** /**
* Record a failed health check * Record a failed health check
*/ */
private recordFailure(error: string): void { private recordFailure(): void {
this.health.totalRequests++; this.health.totalRequests++;
this.health.failedRequests++; this.health.failedRequests++;
this.health.consecutiveFailures++; this.health.consecutiveFailures++;

View File

@@ -1,7 +1,8 @@
import { beforeEach, describe, expect, it } from 'vitest'; import { beforeEach, describe, expect, it } from 'vitest';
import { InMemoryMagicLinkRepository } from './InMemoryMagicLinkRepository'; import { InMemoryMagicLinkRepository } from './InMemoryMagicLinkRepository';
import type { Logger } from '@core/shared/domain/Logger';
const mockLogger = { const mockLogger: Logger = {
debug: () => {}, debug: () => {},
info: () => {}, info: () => {},
warn: () => {}, warn: () => {},
@@ -12,7 +13,7 @@ describe('InMemoryMagicLinkRepository', () => {
let repository: InMemoryMagicLinkRepository; let repository: InMemoryMagicLinkRepository;
beforeEach(() => { beforeEach(() => {
repository = new InMemoryMagicLinkRepository(mockLogger as any); repository = new InMemoryMagicLinkRepository(mockLogger);
}); });
describe('createPasswordResetRequest', () => { describe('createPasswordResetRequest', () => {

View File

@@ -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 { RatingDelta } from '@core/identity/domain/value-objects/RatingDelta';
import { RatingDimensionKey } from '@core/identity/domain/value-objects/RatingDimensionKey'; import { RatingDimensionKey } from '@core/identity/domain/value-objects/RatingDimensionKey';
import { RatingEventId } from '@core/identity/domain/value-objects/RatingEventId'; import { RatingEventId } from '@core/identity/domain/value-objects/RatingEventId';
@@ -14,7 +14,7 @@ export class RatingEventOrmMapper {
* Convert ORM entity to domain entity * Convert ORM entity to domain entity
*/ */
static toDomain(entity: RatingEventOrmEntity): RatingEvent { static toDomain(entity: RatingEventOrmEntity): RatingEvent {
const props: any = { const props: RatingEventProps = {
id: RatingEventId.create(entity.id), id: RatingEventId.create(entity.id),
userId: entity.userId, userId: entity.userId,
dimension: RatingDimensionKey.create(entity.dimension), dimension: RatingDimensionKey.create(entity.dimension),

View File

@@ -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'; import { UserRatingOrmEntity } from '../entities/UserRatingOrmEntity';
/** /**
@@ -11,7 +11,7 @@ export class UserRatingOrmMapper {
* Convert ORM entity to domain value object * Convert ORM entity to domain value object
*/ */
static toDomain(entity: UserRatingOrmEntity): UserRating { static toDomain(entity: UserRatingOrmEntity): UserRating {
const props: any = { const props: UserRatingProps = {
userId: entity.userId, userId: entity.userId,
driver: entity.driver, driver: entity.driver,
admin: entity.admin, admin: entity.admin,

View File

@@ -1,5 +1,6 @@
import type { DataSource } from 'typeorm'; import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { RatingEvent } from '@core/identity/domain/entities/RatingEvent';
import { TypeOrmRatingEventRepository } from './TypeOrmRatingEventRepository'; import { TypeOrmRatingEventRepository } from './TypeOrmRatingEventRepository';
@@ -30,7 +31,7 @@ describe('TypeOrmRatingEventRepository', () => {
reason: { code: 'TEST', summary: 'Test', details: {} }, reason: { code: 'TEST', summary: 'Test', details: {} },
visibility: { public: true, redactedFields: [] }, visibility: { public: true, redactedFields: [] },
version: 1, version: 1,
} as any; } as unknown as RatingEvent;
// Mock the mapper // Mock the mapper
vi.doMock('../mappers/RatingEventOrmMapper', () => ({ vi.doMock('../mappers/RatingEventOrmMapper', () => ({

View File

@@ -1,5 +1,6 @@
import type { DataSource } from 'typeorm'; import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { UserRating } from '@core/identity/domain/value-objects/UserRating';
import { TypeOrmUserRatingRepository } from './TypeOrmUserRatingRepository'; import { TypeOrmUserRatingRepository } from './TypeOrmUserRatingRepository';
@@ -41,7 +42,7 @@ describe('TypeOrmUserRatingRepository', () => {
overallReputation: 50, overallReputation: 50,
createdAt: new Date(), createdAt: new Date(),
updatedAt: new Date(), updatedAt: new Date(),
} as any; } as unknown as UserRating;
const result = await repo.save(mockRating); const result = await repo.save(mockRating);
expect(result).toBe(mockRating); expect(result).toBe(mockRating);

View File

@@ -47,9 +47,10 @@ function buildSetCookieHeader(options: {
return parts.join('; '); 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 (!existing) return [next];
if (Array.isArray(existing)) return [...existing, next]; if (Array.isArray(existing)) return [...existing, next];
if (typeof existing === 'number') return [existing.toString(), next];
return [existing, next]; return [existing, next];
} }
@@ -111,7 +112,7 @@ export class CookieIdentitySessionAdapter implements IdentitySessionPort {
}); });
const existing = ctx.res.getHeader('Set-Cookie'); 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; return session;
@@ -137,7 +138,7 @@ export class CookieIdentitySessionAdapter implements IdentitySessionPort {
}); });
const existing = ctx.res.getHeader('Set-Cookie'); 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; return;
} }

View File

@@ -1,17 +1,18 @@
import { describe, vi } from 'vitest'; import { describe, vi } from 'vitest';
import { InMemoryMediaRepository } from './InMemoryMediaRepository'; import { InMemoryMediaRepository } from './InMemoryMediaRepository';
import { runMediaRepositoryContract } from '../../../../tests/contracts/media/MediaRepository.contract'; import { runMediaRepositoryContract } from '../../../../tests/contracts/media/MediaRepository.contract';
import type { Logger } from '@core/shared/domain/Logger';
describe('InMemoryMediaRepository Contract Compliance', () => { describe('InMemoryMediaRepository Contract Compliance', () => {
runMediaRepositoryContract(async () => { runMediaRepositoryContract(async () => {
const logger = { const logger: Logger = {
info: vi.fn(), info: vi.fn(),
debug: vi.fn(), debug: vi.fn(),
warn: vi.fn(), warn: vi.fn(),
error: vi.fn(), error: vi.fn(),
}; };
const repository = new InMemoryMediaRepository(logger as any); const repository = new InMemoryMediaRepository(logger);
return { return {
repository, repository,

View File

@@ -1,4 +1,5 @@
import { AvatarGenerationRequest } from '@core/media/domain/entities/AvatarGenerationRequest'; import { AvatarGenerationRequest } from '@core/media/domain/entities/AvatarGenerationRequest';
import { AvatarGenerationRequestProps } from '@core/media/domain/types/AvatarGenerationRequest';
import { AvatarGenerationRequestOrmEntity } from '../entities/AvatarGenerationRequestOrmEntity'; import { AvatarGenerationRequestOrmEntity } from '../entities/AvatarGenerationRequestOrmEntity';
import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError'; import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError';
import { import {
@@ -37,7 +38,7 @@ export class AvatarGenerationRequestOrmMapper {
} }
try { try {
const props: any = { const props: AvatarGenerationRequestProps = {
id: entity.id, id: entity.id,
userId: entity.userId, userId: entity.userId,
facePhotoUrl: entity.facePhotoUrl, facePhotoUrl: entity.facePhotoUrl,

View File

@@ -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 { MediaOrmEntity } from '../entities/MediaOrmEntity';
import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError'; import { TypeOrmMediaSchemaError } from '../errors/TypeOrmMediaSchemaError';
import { import {
@@ -31,7 +31,7 @@ export class MediaOrmMapper {
} }
try { try {
const domainProps: any = { const domainProps: MediaProps = {
id: entity.id, id: entity.id,
filename: entity.filename, filename: entity.filename,
originalName: entity.originalName, originalName: entity.originalName,

View File

@@ -1,6 +1,9 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; 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'; import { TypeOrmAvatarGenerationRepository } from './TypeOrmAvatarGenerationRepository';
@@ -35,7 +38,7 @@ describe('TypeOrmAvatarGenerationRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-request-1' }), 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 // Test findById
const request = await repo.findById('request-1'); const request = await repo.findById('request-1');
@@ -61,8 +64,8 @@ describe('TypeOrmAvatarGenerationRepository', () => {
}); });
// Test save // Test save
const domainRequest = { id: 'new-request', toProps: () => ({ id: 'new-request' }) }; const domainRequest = { id: 'new-request', toProps: () => ({ id: 'new-request' }) } as unknown as AvatarGenerationRequest;
await repo.save(domainRequest as any); await repo.save(domainRequest);
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainRequest); expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainRequest);
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-request-1' }); expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-request-1' });

View File

@@ -1,6 +1,9 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; 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'; import { TypeOrmAvatarRepository } from './TypeOrmAvatarRepository';
@@ -35,7 +38,7 @@ describe('TypeOrmAvatarRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-avatar-1' }), 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 // Test findById
const avatar = await repo.findById('avatar-1'); const avatar = await repo.findById('avatar-1');
@@ -61,8 +64,8 @@ describe('TypeOrmAvatarRepository', () => {
expect(avatars).toHaveLength(2); expect(avatars).toHaveLength(2);
// Test save // Test save
const domainAvatar = { id: 'new-avatar', toProps: () => ({ id: 'new-avatar' }) }; const domainAvatar = { id: 'new-avatar', toProps: () => ({ id: 'new-avatar' }) } as unknown as Avatar;
await repo.save(domainAvatar as any); await repo.save(domainAvatar);
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainAvatar); expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainAvatar);
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-avatar-1' }); expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-avatar-1' });

View File

@@ -1,13 +1,15 @@
import { describe, vi } from 'vitest'; import { describe, vi } from 'vitest';
import type { DataSource } from 'typeorm';
import { TypeOrmMediaRepository } from './TypeOrmMediaRepository'; import { TypeOrmMediaRepository } from './TypeOrmMediaRepository';
import { MediaOrmMapper } from '../mappers/MediaOrmMapper'; import { MediaOrmMapper } from '../mappers/MediaOrmMapper';
import { runMediaRepositoryContract } from '../../../../../tests/contracts/media/MediaRepository.contract'; import { runMediaRepositoryContract } from '../../../../../tests/contracts/media/MediaRepository.contract';
import type { MediaOrmEntity } from '../entities/MediaOrmEntity';
describe('TypeOrmMediaRepository Contract Compliance', () => { describe('TypeOrmMediaRepository Contract Compliance', () => {
runMediaRepositoryContract(async () => { runMediaRepositoryContract(async () => {
// Mocking TypeORM DataSource and Repository for a DB-free contract test // Mocking TypeORM DataSource and Repository for a DB-free contract test
// In a real scenario, this might use an in-memory SQLite database // 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 = { const ormRepo = {
save: vi.fn().mockImplementation(async (entity) => { save: vi.fn().mockImplementation(async (entity) => {
@@ -30,7 +32,7 @@ describe('TypeOrmMediaRepository Contract Compliance', () => {
}; };
const mapper = new MediaOrmMapper(); const mapper = new MediaOrmMapper();
const repository = new TypeOrmMediaRepository(dataSource as any, mapper); const repository = new TypeOrmMediaRepository(dataSource as unknown as DataSource, mapper);
return { return {
repository, repository,

View File

@@ -1,6 +1,9 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; 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'; import { TypeOrmMediaRepository } from './TypeOrmMediaRepository';
@@ -35,7 +38,7 @@ describe('TypeOrmMediaRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-media-1' }), 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 // Test findById
const media = await repo.findById('media-1'); const media = await repo.findById('media-1');

View File

@@ -86,7 +86,7 @@ export class FileSystemMediaStorageAdapter implements MediaStoragePort {
await fs.unlink(filePath); await fs.unlink(filePath);
} catch (error) { } catch (error) {
// Ignore if file doesn't exist // 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; return;
} }
throw error; throw error;

View File

@@ -34,7 +34,7 @@ export interface GeneratedMediaResolverConfig {
* Format: "{type}-{id}" (e.g., "team-123", "league-456") * Format: "{type}-{id}" (e.g., "team-123", "league-456")
*/ */
export class GeneratedMediaResolverAdapter implements MediaResolverPort { export class GeneratedMediaResolverAdapter implements MediaResolverPort {
constructor(_config: GeneratedMediaResolverConfig = {}) { constructor() {
// basePath is not used since we return path-only URLs // basePath is not used since we return path-only URLs
// config.basePath is ignored for backward compatibility // config.basePath is ignored for backward compatibility
} }
@@ -85,8 +85,6 @@ export class GeneratedMediaResolverAdapter implements MediaResolverPort {
/** /**
* Factory function for creating GeneratedMediaResolverAdapter instances * Factory function for creating GeneratedMediaResolverAdapter instances
*/ */
export function createGeneratedMediaResolver( export function createGeneratedMediaResolver(): GeneratedMediaResolverAdapter {
config: GeneratedMediaResolverConfig = {} return new GeneratedMediaResolverAdapter();
): GeneratedMediaResolverAdapter {
return new GeneratedMediaResolverAdapter(config);
} }

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, vi } from 'vitest';
import { DiscordNotificationAdapter } from './DiscordNotificationGateway'; import { DiscordNotificationAdapter } from './DiscordNotificationGateway';
import { Notification } from '@core/notifications/domain/entities/Notification'; import { Notification } from '@core/notifications/domain/entities/Notification';
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
describe('DiscordNotificationAdapter', () => { describe('DiscordNotificationAdapter', () => {
const webhookUrl = 'https://discord.com/api/webhooks/123/abc'; const webhookUrl = 'https://discord.com/api/webhooks/123/abc';
@@ -11,7 +12,7 @@ describe('DiscordNotificationAdapter', () => {
vi.spyOn(console, 'log').mockImplementation(() => {}); vi.spyOn(console, 'log').mockImplementation(() => {});
}); });
const createNotification = (overrides: any = {}) => { const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
return Notification.create({ return Notification.create({
id: 'notif-123', id: 'notif-123',
recipientId: 'driver-456', recipientId: 'driver-456',
@@ -58,7 +59,7 @@ describe('DiscordNotificationAdapter', () => {
}); });
it('should return false for other channels', () => { 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);
}); });
}); });

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, vi } from 'vitest';
import { EmailNotificationAdapter } from './EmailNotificationGateway'; import { EmailNotificationAdapter } from './EmailNotificationGateway';
import { Notification } from '@core/notifications/domain/entities/Notification'; import { Notification } from '@core/notifications/domain/entities/Notification';
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
describe('EmailNotificationAdapter', () => { describe('EmailNotificationAdapter', () => {
const config = { const config = {
@@ -14,7 +15,7 @@ describe('EmailNotificationAdapter', () => {
vi.spyOn(console, 'log').mockImplementation(() => {}); vi.spyOn(console, 'log').mockImplementation(() => {});
}); });
const createNotification = (overrides: any = {}) => { const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
return Notification.create({ return Notification.create({
id: 'notif-123', id: 'notif-123',
recipientId: 'driver-456', recipientId: 'driver-456',

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, vi } from 'vitest';
import { InAppNotificationAdapter } from './InAppNotificationGateway'; import { InAppNotificationAdapter } from './InAppNotificationGateway';
import { Notification } from '@core/notifications/domain/entities/Notification'; import { Notification } from '@core/notifications/domain/entities/Notification';
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
describe('InAppNotificationAdapter', () => { describe('InAppNotificationAdapter', () => {
let adapter: InAppNotificationAdapter; let adapter: InAppNotificationAdapter;
@@ -10,7 +11,7 @@ describe('InAppNotificationAdapter', () => {
vi.spyOn(console, 'log').mockImplementation(() => {}); vi.spyOn(console, 'log').mockImplementation(() => {});
}); });
const createNotification = (overrides: any = {}) => { const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
return Notification.create({ return Notification.create({
id: 'notif-123', id: 'notif-123',
recipientId: 'driver-456', recipientId: 'driver-456',

View File

@@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
import { NotificationGatewayRegistry } from './NotificationGatewayRegistry'; import { NotificationGatewayRegistry } from './NotificationGatewayRegistry';
import { Notification } from '@core/notifications/domain/entities/Notification'; import { Notification } from '@core/notifications/domain/entities/Notification';
import type { NotificationGateway, NotificationDeliveryResult } from '@core/notifications/application/ports/NotificationGateway'; import type { NotificationGateway, NotificationDeliveryResult } from '@core/notifications/application/ports/NotificationGateway';
import type { NotificationChannel } from '@core/notifications/domain/types/NotificationTypes';
describe('NotificationGatewayRegistry', () => { describe('NotificationGatewayRegistry', () => {
let registry: NotificationGatewayRegistry; let registry: NotificationGatewayRegistry;
@@ -18,7 +17,7 @@ describe('NotificationGatewayRegistry', () => {
registry = new NotificationGatewayRegistry([mockGateway]); registry = new NotificationGatewayRegistry([mockGateway]);
}); });
const createNotification = (overrides: any = {}) => { const createNotification = (overrides: Partial<Parameters<typeof Notification.create>[0]> = {}) => {
return Notification.create({ return Notification.create({
id: 'notif-123', id: 'notif-123',
recipientId: 'driver-456', recipientId: 'driver-456',
@@ -35,7 +34,7 @@ describe('NotificationGatewayRegistry', () => {
const discordGateway = { const discordGateway = {
...mockGateway, ...mockGateway,
getChannel: vi.fn().mockReturnValue('discord'), getChannel: vi.fn().mockReturnValue('discord'),
} as any; } as unknown as NotificationGateway;
registry.register(discordGateway); registry.register(discordGateway);
expect(registry.getGateway('discord')).toBe(discordGateway); expect(registry.getGateway('discord')).toBe(discordGateway);

View File

@@ -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 { NotificationOrmEntity } from '../entities/NotificationOrmEntity';
import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError'; import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';
import { import {
@@ -44,40 +45,40 @@ export class NotificationOrmMapper {
} }
try { try {
const domainProps: any = { const domainProps = {
id: entity.id, id: entity.id,
recipientId: entity.recipientId, recipientId: entity.recipientId,
type: entity.type, type: entity.type as NotificationType,
title: entity.title, title: entity.title,
body: entity.body, body: entity.body,
channel: entity.channel, channel: entity.channel as NotificationChannel,
status: entity.status, status: entity.status as NotificationStatus,
urgency: entity.urgency, urgency: entity.urgency as NotificationUrgency,
createdAt: entity.createdAt, createdAt: entity.createdAt,
requiresResponse: entity.requiresResponse, requiresResponse: entity.requiresResponse,
}; };
if (entity.data !== null && entity.data !== undefined) { 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) { if (entity.actionUrl !== null && entity.actionUrl !== undefined) {
domainProps.actionUrl = entity.actionUrl; (domainProps as any).actionUrl = entity.actionUrl;
} }
if (entity.actions !== null && entity.actions !== undefined) { if (entity.actions !== null && entity.actions !== undefined) {
domainProps.actions = entity.actions; (domainProps as any).actions = entity.actions;
} }
if (entity.readAt !== null && entity.readAt !== undefined) { if (entity.readAt !== null && entity.readAt !== undefined) {
domainProps.readAt = entity.readAt; (domainProps as any).readAt = entity.readAt;
} }
if (entity.respondedAt !== null && entity.respondedAt !== undefined) { 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) { } catch (error) {
const message = error instanceof Error ? error.message : 'Invalid persisted Notification'; const message = error instanceof Error ? error.message : 'Invalid persisted Notification';
throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message }); throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });

View File

@@ -34,7 +34,7 @@ export class NotificationPreferenceOrmMapper {
} }
try { try {
const domainProps: any = { const domainProps = {
id: entity.id, id: entity.id,
driverId: entity.driverId, driverId: entity.driverId,
channels: entity.channels, channels: entity.channels,
@@ -43,22 +43,22 @@ export class NotificationPreferenceOrmMapper {
}; };
if (entity.typePreferences !== null && entity.typePreferences !== undefined) { 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) { 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) { 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) { 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) { } catch (error) {
const message = error instanceof Error ? error.message : 'Invalid persisted NotificationPreference'; const message = error instanceof Error ? error.message : 'Invalid persisted NotificationPreference';
throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message }); throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });

View File

@@ -1,4 +1,7 @@
import { describe, expect, it, vi } from 'vitest'; 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'; import { TypeOrmNotificationPreferenceRepository } from './TypeOrmNotificationPreferenceRepository';
@@ -33,7 +36,7 @@ describe('TypeOrmNotificationPreferenceRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-preference-1' }), 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 // Test findByDriverId
const preference = await repo.findByDriverId('driver-123'); const preference = await repo.findByDriverId('driver-123');
@@ -43,8 +46,8 @@ describe('TypeOrmNotificationPreferenceRepository', () => {
expect(preference).toEqual({ id: 'domain-preference-1' }); expect(preference).toEqual({ id: 'domain-preference-1' });
// Test save // Test save
const domainPreference = { id: 'driver-123', driverId: 'driver-123', toJSON: () => ({ id: 'driver-123', driverId: 'driver-123' }) }; const domainPreference = { id: 'driver-123', driverId: 'driver-123', toJSON: () => ({ id: 'driver-123', driverId: 'driver-123' }) } as unknown as NotificationPreference;
await repo.save(domainPreference as any); await repo.save(domainPreference);
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainPreference); expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainPreference);
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-preference-1' }); expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-preference-1' });

View File

@@ -1,4 +1,6 @@
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { DataSource } from 'typeorm';
import type { NotificationOrmMapper } from '../mappers/NotificationOrmMapper';
import { TypeOrmNotificationRepository } from './TypeOrmNotificationRepository'; import { TypeOrmNotificationRepository } from './TypeOrmNotificationRepository';
@@ -36,7 +38,7 @@ describe('TypeOrmNotificationRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'orm-notification-1' }), 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 // Test findById
const notification = await repo.findById('notification-1'); const notification = await repo.findById('notification-1');
@@ -61,13 +63,13 @@ describe('TypeOrmNotificationRepository', () => {
expect(count).toBe(1); expect(count).toBe(1);
// Test create // Test create
const domainNotification = { id: 'new-notification', toJSON: () => ({ id: 'new-notification' }) }; const domainNotification = { id: 'new-notification', toJSON: () => ({ id: 'new-notification' }) } as unknown as Notification;
await repo.create(domainNotification as any); await repo.create(domainNotification);
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainNotification); expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainNotification);
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-notification-1' }); expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-notification-1' });
// Test update // Test update
await repo.update(domainNotification as any); await repo.update(domainNotification);
expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainNotification); expect(mapper.toOrmEntity).toHaveBeenCalledWith(domainNotification);
expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-notification-1' }); expect(ormRepo.save).toHaveBeenCalledWith({ id: 'orm-notification-1' });

View File

@@ -2,34 +2,36 @@
* In-Memory Implementation: InMemoryWalletRepository * 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 { WalletRepository, TransactionRepository } from '@core/payments/domain/repositories/WalletRepository';
import type { Logger } from '@core/shared/domain/Logger'; import type { Logger } from '@core/shared/domain/Logger';
import type { LeagueWalletRepository } from '@core/racing/domain/repositories/LeagueWalletRepository'; 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 wallets: Map<string, Wallet | LeagueWallet> = new Map();
const transactions: Map<string, any> = new Map(); const transactions: Map<string, Transaction> = new Map();
export class InMemoryWalletRepository implements WalletRepository, LeagueWalletRepository { export class InMemoryWalletRepository implements WalletRepository, LeagueWalletRepository {
constructor(private readonly logger: Logger) {} 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 }); this.logger.debug('[InMemoryWalletRepository] findById', { id });
return wallets.get(id) || null; 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 }); 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 }); this.logger.debug('[InMemoryWalletRepository] create', { wallet });
wallets.set(wallet.id.toString(), wallet); wallets.set(wallet.id.toString(), wallet);
return wallet; return wallet;
} }
async update(wallet: any): Promise<any> { async update(wallet: Wallet | LeagueWallet): Promise<Wallet | LeagueWallet> {
this.logger.debug('[InMemoryWalletRepository] update', { wallet }); this.logger.debug('[InMemoryWalletRepository] update', { wallet });
wallets.set(wallet.id.toString(), wallet); wallets.set(wallet.id.toString(), wallet);
return wallet; return wallet;

View File

@@ -1,7 +1,7 @@
import { MediaReference } from '@core/domain/media/MediaReference'; import { MediaReference } from '@core/domain/media/MediaReference';
import { Driver } from '@core/racing/domain/entities/Driver'; import { Driver } from '@core/racing/domain/entities/Driver';
import { DriverRepository } from '@core/racing/domain/repositories/DriverRepository'; 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 { export class InMemoryDriverRepository implements DriverRepository {
private drivers: Map<string, Driver> = new Map(); private drivers: Map<string, Driver> = new Map();

View File

@@ -1,6 +1,6 @@
import { Game } from '@core/racing/domain/entities/Game'; import { Game } from '@core/racing/domain/entities/Game';
import { GameRepository } from '@core/racing/domain/repositories/GameRepository'; 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 { export class InMemoryGameRepository implements GameRepository {
private games: Map<string, Game> = new Map(); private games: Map<string, Game> = new Map();

View File

@@ -1,7 +1,7 @@
import { JoinRequest } from '@core/racing/domain/entities/JoinRequest'; import { JoinRequest } from '@core/racing/domain/entities/JoinRequest';
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership'; import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
import { LeagueMembershipRepository } from '@core/racing/domain/repositories/LeagueMembershipRepository'; 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 { export class InMemoryLeagueMembershipRepository implements LeagueMembershipRepository {
private memberships: Map<string, LeagueMembership> = new Map(); // Key: `${leagueId}:${driverId}` private memberships: Map<string, LeagueMembership> = new Map(); // Key: `${leagueId}:${driverId}`

View File

@@ -1,7 +1,7 @@
import { MediaReference } from '@core/domain/media/MediaReference'; import { MediaReference } from '@core/domain/media/MediaReference';
import { League } from '@core/racing/domain/entities/League'; import { League } from '@core/racing/domain/entities/League';
import { LeagueRepository } from '@core/racing/domain/repositories/LeagueRepository'; 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 { export class InMemoryLeagueRepository implements LeagueRepository {
private leagues: Map<string, League> = new Map(); private leagues: Map<string, League> = new Map();

View File

@@ -1,6 +1,6 @@
import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig'; import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig';
import { LeagueScoringConfigRepository } from '@core/racing/domain/repositories/LeagueScoringConfigRepository'; 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 { export class InMemoryLeagueScoringConfigRepository implements LeagueScoringConfigRepository {
private configs: Map<string, LeagueScoringConfig> = new Map(); // Key: seasonId private configs: Map<string, LeagueScoringConfig> = new Map(); // Key: seasonId

View File

@@ -1,5 +1,5 @@
import { LeagueStandingsRepository, RawStanding } from '@core/league/application/ports/LeagueStandingsRepository'; 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 { export class InMemoryLeagueStandingsRepository implements LeagueStandingsRepository {
private standings: Map<string, RawStanding[]> = new Map(); // Key: leagueId private standings: Map<string, RawStanding[]> = new Map(); // Key: leagueId

View File

@@ -1,6 +1,6 @@
import { Protest } from '@core/racing/domain/entities/Protest'; import { Protest } from '@core/racing/domain/entities/Protest';
import { ProtestRepository } from '@core/racing/domain/repositories/ProtestRepository'; 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 { export class InMemoryProtestRepository implements ProtestRepository {
private protests: Map<string, Protest> = new Map(); private protests: Map<string, Protest> = new Map();

View File

@@ -1,6 +1,6 @@
import { RaceRegistration } from '@core/racing/domain/entities/RaceRegistration'; import { RaceRegistration } from '@core/racing/domain/entities/RaceRegistration';
import { RaceRegistrationRepository } from '@core/racing/domain/repositories/RaceRegistrationRepository'; 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 { export class InMemoryRaceRegistrationRepository implements RaceRegistrationRepository {
private registrations: Map<string, RaceRegistration> = new Map(); // Key: `${raceId}:${driverId}` private registrations: Map<string, RaceRegistration> = new Map(); // Key: `${raceId}:${driverId}`

View File

@@ -1,6 +1,6 @@
import { Race, type RaceStatusValue } from '@core/racing/domain/entities/Race'; import { Race, type RaceStatusValue } from '@core/racing/domain/entities/Race';
import { RaceRepository } from '@core/racing/domain/repositories/RaceRepository'; 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 { export class InMemoryRaceRepository implements RaceRepository {
private races: Map<string, Race> = new Map(); private races: Map<string, Race> = new Map();

View File

@@ -1,6 +1,6 @@
import { Season } from '@core/racing/domain/entities/season/Season'; import { Season } from '@core/racing/domain/entities/season/Season';
import { SeasonRepository } from '@core/racing/domain/repositories/SeasonRepository'; 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 { export class InMemorySeasonRepository implements SeasonRepository {
private seasons: Map<string, Season> = new Map(); // Key: seasonId private seasons: Map<string, Season> = new Map(); // Key: seasonId

View File

@@ -1,6 +1,6 @@
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor'; import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
import { SponsorRepository } from '@core/racing/domain/repositories/SponsorRepository'; 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 { export class InMemorySponsorRepository implements SponsorRepository {
private sponsors: Map<string, Sponsor> = new Map(); private sponsors: Map<string, Sponsor> = new Map();

View File

@@ -1,6 +1,6 @@
import { SponsorableEntityType, SponsorshipRequest, SponsorshipRequestStatus } from '@core/racing/domain/entities/SponsorshipRequest'; import { SponsorableEntityType, SponsorshipRequest, SponsorshipRequestStatus } from '@core/racing/domain/entities/SponsorshipRequest';
import { SponsorshipRequestRepository } from '@core/racing/domain/repositories/SponsorshipRequestRepository'; 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 { export class InMemorySponsorshipRequestRepository implements SponsorshipRequestRepository {
private requests: Map<string, SponsorshipRequest> = new Map(); private requests: Map<string, SponsorshipRequest> = new Map();

View File

@@ -22,4 +22,7 @@ export class ResultOrmEntity {
@Column({ type: 'int' }) @Column({ type: 'int' })
startPosition!: number; startPosition!: number;
@Column({ type: 'int', default: 0 })
points!: number;
} }

View File

@@ -29,11 +29,11 @@ describe('LeagueOrmMapper', () => {
entity.youtubeUrl = null; entity.youtubeUrl = null;
entity.websiteUrl = 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'); 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(() => { const createSpy = vi.spyOn(League, 'create').mockImplementation(() => {
throw new Error('create-called'); throw new Error('create-called');
}); });

View File

@@ -24,11 +24,11 @@ describe('RaceOrmMapper', () => {
entity.registeredCount = null; entity.registeredCount = null;
entity.maxParticipants = 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'); 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(() => { const createSpy = vi.spyOn(Race, 'create').mockImplementation(() => {
throw new Error('create-called'); throw new Error('create-called');
}); });

View File

@@ -15,6 +15,7 @@ export class ResultOrmMapper {
entity.fastestLap = domain.fastestLap.toNumber(); entity.fastestLap = domain.fastestLap.toNumber();
entity.incidents = domain.incidents.toNumber(); entity.incidents = domain.incidents.toNumber();
entity.startPosition = domain.startPosition.toNumber(); entity.startPosition = domain.startPosition.toNumber();
entity.points = domain.points;
return entity; return entity;
} }
@@ -29,6 +30,7 @@ export class ResultOrmMapper {
assertInteger(entityName, 'fastestLap', entity.fastestLap); assertInteger(entityName, 'fastestLap', entity.fastestLap);
assertInteger(entityName, 'incidents', entity.incidents); assertInteger(entityName, 'incidents', entity.incidents);
assertInteger(entityName, 'startPosition', entity.startPosition); assertInteger(entityName, 'startPosition', entity.startPosition);
assertInteger(entityName, 'points', entity.points);
} catch (error) { } catch (error) {
if (error instanceof TypeOrmPersistenceSchemaError) { if (error instanceof TypeOrmPersistenceSchemaError) {
throw new InvalidResultSchemaError({ throw new InvalidResultSchemaError({
@@ -49,6 +51,7 @@ export class ResultOrmMapper {
fastestLap: entity.fastestLap, fastestLap: entity.fastestLap,
incidents: entity.incidents, incidents: entity.incidents,
startPosition: entity.startPosition, startPosition: entity.startPosition,
points: entity.points,
}); });
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : 'Invalid persisted Result'; const message = error instanceof Error ? error.message : 'Invalid persisted Result';

View File

@@ -28,11 +28,11 @@ describe('SeasonOrmMapper', () => {
entity.maxDrivers = null; entity.maxDrivers = null;
entity.participantCount = 3; 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'); 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(() => { const createSpy = vi.spyOn(Season, 'create').mockImplementation(() => {
throw new Error('create-called'); throw new Error('create-called');
}); });

View File

@@ -93,7 +93,7 @@ describe('TeamRatingEventOrmMapper', () => {
it('should handle domain entity without weight', () => { it('should handle domain entity without weight', () => {
const props = { ...validDomainProps }; const props = { ...validDomainProps };
delete (props as any).weight; delete (props as unknown as { weight: unknown }).weight;
const domain = TeamRatingEvent.create(props); const domain = TeamRatingEvent.create(props);
const entity = TeamRatingEventOrmMapper.toOrmEntity(domain); const entity = TeamRatingEventOrmMapper.toOrmEntity(domain);

View File

@@ -1,4 +1,5 @@
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { Repository } from 'typeorm';
import { import {
TypeOrmGameRepository, TypeOrmGameRepository,
@@ -6,6 +7,8 @@ import {
TypeOrmSponsorRepository, TypeOrmSponsorRepository,
TypeOrmTransactionRepository, TypeOrmTransactionRepository,
} from './CommerceTypeOrmRepositories'; } from './CommerceTypeOrmRepositories';
import type { GameOrmEntity, LeagueWalletOrmEntity, SponsorOrmEntity, TransactionOrmEntity } from '../entities/CommerceOrmEntities';
import type { GameOrmMapper, LeagueWalletOrmMapper, SponsorOrmMapper, TransactionOrmMapper } from '../mappers/CommerceOrmMappers';
describe('TypeOrmGameRepository', () => { describe('TypeOrmGameRepository', () => {
it('findAll maps entities to domain using injected mapper (DB-free)', async () => { it('findAll maps entities to domain using injected mapper (DB-free)', async () => {
@@ -17,10 +20,10 @@ describe('TypeOrmGameRepository', () => {
}; };
const mapper = { 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(); const games = await gameRepo.findAll();
@@ -44,7 +47,7 @@ describe('TypeOrmLeagueWalletRepository', () => {
toOrmEntity: vi.fn(), 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); await expect(walletRepo.exists('w1')).resolves.toBe(true);
expect(repo.count).toHaveBeenCalledWith({ where: { id: 'w1' } }); expect(repo.count).toHaveBeenCalledWith({ where: { id: 'w1' } });

View File

@@ -1,6 +1,10 @@
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { Repository } from 'typeorm';
import { TypeOrmPenaltyRepository, TypeOrmProtestRepository } from './StewardingTypeOrmRepositories'; 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', () => { describe('TypeOrmPenaltyRepository', () => {
it('findById returns mapped domain when found (DB-free)', async () => { it('findById returns mapped domain when found (DB-free)', async () => {
@@ -19,7 +23,7 @@ describe('TypeOrmPenaltyRepository', () => {
toOrmEntity: vi.fn(), 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'); const result = await penaltyRepo.findById('p1');
@@ -37,9 +41,9 @@ describe('TypeOrmPenaltyRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'p1-orm' }), 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(mapper.toOrmEntity).toHaveBeenCalled();
expect(repo.save).toHaveBeenCalledWith({ id: 'p1-orm' }); expect(repo.save).toHaveBeenCalledWith({ id: 'p1-orm' });

View File

@@ -1,6 +1,11 @@
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { Repository } from 'typeorm';
import { TypeOrmTeamMembershipRepository, TypeOrmTeamRepository } from './TeamTypeOrmRepositories'; 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', () => { describe('TypeOrmTeamRepository', () => {
it('uses injected repo + mapper (DB-free)', async () => { it('uses injected repo + mapper (DB-free)', async () => {
@@ -20,7 +25,7 @@ describe('TypeOrmTeamRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'team-1-orm' }), 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'); const team = await teamRepo.findById('550e8400-e29b-41d4-a716-446655440000');
@@ -38,11 +43,11 @@ describe('TypeOrmTeamRepository', () => {
toOrmEntity: vi.fn().mockReturnValue({ id: 'team-1-orm' }), 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(mapper.toOrmEntity).toHaveBeenCalledWith(domainTeam);
expect(repo.save).toHaveBeenCalledWith({ id: 'team-1-orm' }); expect(repo.save).toHaveBeenCalledWith({ id: 'team-1-orm' });

View File

@@ -47,10 +47,10 @@ describe('TypeOrmDriverRepository', () => {
avatarRef: MediaReference.createUploaded('media-abc-123'), avatarRef: MediaReference.createUploaded('media-abc-123'),
}); });
const savedEntities: any[] = []; const savedEntities: unknown[] = [];
const repo = { const repo = {
save: async (entity: any) => { save: async (entity: unknown) => {
savedEntities.push(entity); savedEntities.push(entity);
return entity; return entity;
}, },
@@ -68,7 +68,7 @@ describe('TypeOrmDriverRepository', () => {
await typeOrmRepo.create(driver); await typeOrmRepo.create(driver);
expect(savedEntities).toHaveLength(1); 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 // Test load
const loaded = await typeOrmRepo.findById(driverId); const loaded = await typeOrmRepo.findById(driverId);
@@ -87,10 +87,10 @@ describe('TypeOrmDriverRepository', () => {
avatarRef: MediaReference.createSystemDefault('avatar'), avatarRef: MediaReference.createSystemDefault('avatar'),
}); });
const savedEntities: any[] = []; const savedEntities: unknown[] = [];
const repo = { const repo = {
save: async (entity: any) => { save: async (entity: unknown) => {
savedEntities.push(entity); savedEntities.push(entity);
return entity; return entity;
}, },

View File

@@ -16,7 +16,7 @@ export class TypeOrmDriverStatsRepository implements DriverStatsRepository {
return entity ? this.mapper.toDomain(entity) : null; return entity ? this.mapper.toDomain(entity) : null;
} }
getDriverStatsSync(_driverId: string): DriverStats | null { getDriverStatsSync(): DriverStats | null {
// TypeORM repositories don't support synchronous operations // TypeORM repositories don't support synchronous operations
// This method is provided for interface compatibility but should not be used // This method is provided for interface compatibility but should not be used
// with TypeORM implementations. Return null to indicate it's not supported. // with TypeORM implementations. Return null to indicate it's not supported.

View File

@@ -1,6 +1,8 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { LeagueOrmMapper } from '../mappers/LeagueOrmMapper';
import { TypeOrmLeagueRepository } from './TypeOrmLeagueRepository'; import { TypeOrmLeagueRepository } from './TypeOrmLeagueRepository';
@@ -31,7 +33,7 @@ describe('TypeOrmLeagueRepository', () => {
toOrmEntity: vi.fn(), 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'); const league = await repo.findById('l1');

View File

@@ -1,6 +1,8 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { RaceOrmMapper } from '../mappers/RaceOrmMapper';
import { TypeOrmRaceRepository } from './TypeOrmRaceRepository'; import { TypeOrmRaceRepository } from './TypeOrmRaceRepository';
@@ -31,7 +33,7 @@ describe('TypeOrmRaceRepository', () => {
toOrmEntity: vi.fn(), 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'); const race = await repo.findById('r1');

View File

@@ -1,6 +1,8 @@
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import type { DataSource } from 'typeorm';
import { describe, expect, it, vi } from 'vitest'; import { describe, expect, it, vi } from 'vitest';
import type { SeasonOrmMapper } from '../mappers/SeasonOrmMapper';
import { TypeOrmSeasonRepository } from './TypeOrmSeasonRepository'; import { TypeOrmSeasonRepository } from './TypeOrmSeasonRepository';
@@ -31,7 +33,7 @@ describe('TypeOrmSeasonRepository', () => {
toOrmEntity: vi.fn(), 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'); const season = await repo.findById('s1');