/** * Data Factory for Integration Tests * Uses TypeORM repositories to create test data */ import { DataSource } from 'typeorm'; import { LeagueOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/LeagueOrmEntity'; import { SeasonOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/SeasonOrmEntity'; import { DriverOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/DriverOrmEntity'; import { RaceOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/RaceOrmEntity'; import { ResultOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/ResultOrmEntity'; import { LeagueOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/LeagueOrmMapper'; import { SeasonOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/SeasonOrmMapper'; import { RaceOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/RaceOrmMapper'; import { ResultOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/ResultOrmMapper'; import { TypeOrmLeagueRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmLeagueRepository'; import { TypeOrmSeasonRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmSeasonRepository'; import { TypeOrmRaceRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmRaceRepository'; import { TypeOrmResultRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmResultRepository'; import { TypeOrmDriverRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmDriverRepository'; import { League } from '../../../core/racing/domain/entities/League'; import { Season } from '../../../core/racing/domain/entities/season/Season'; import { Driver } from '../../../core/racing/domain/entities/Driver'; import { Race } from '../../../core/racing/domain/entities/Race'; import { Result } from '../../../core/racing/domain/entities/result/Result'; import { v4 as uuidv4 } from 'uuid'; export class DataFactory { private dataSource: DataSource; private leagueRepo: TypeOrmLeagueRepository; private seasonRepo: TypeOrmSeasonRepository; private driverRepo: TypeOrmDriverRepository; private raceRepo: TypeOrmRaceRepository; private resultRepo: TypeOrmResultRepository; constructor(private dbUrl: string) { this.dataSource = new DataSource({ type: 'postgres', url: dbUrl, entities: [ LeagueOrmEntity, SeasonOrmEntity, DriverOrmEntity, RaceOrmEntity, ResultOrmEntity, ], synchronize: false, // Don't sync, use existing schema }); } async initialize(): Promise { if (!this.dataSource.isInitialized) { await this.dataSource.initialize(); } const leagueMapper = new LeagueOrmMapper(); const seasonMapper = new SeasonOrmMapper(); const raceMapper = new RaceOrmMapper(); const resultMapper = new ResultOrmMapper(); this.leagueRepo = new TypeOrmLeagueRepository(this.dataSource, leagueMapper); this.seasonRepo = new TypeOrmSeasonRepository(this.dataSource, seasonMapper); this.driverRepo = new TypeOrmDriverRepository(this.dataSource, leagueMapper); // Reuse mapper this.raceRepo = new TypeOrmRaceRepository(this.dataSource, raceMapper); this.resultRepo = new TypeOrmResultRepository(this.dataSource, resultMapper); } async cleanup(): Promise { if (this.dataSource.isInitialized) { await this.dataSource.destroy(); } } /** * Create a test league */ async createLeague(overrides: Partial<{ id: string; name: string; description: string; ownerId: string; }> = {}) { const league = League.create({ id: overrides.id || uuidv4(), name: overrides.name || 'Test League', description: overrides.description || 'Integration Test League', ownerId: overrides.ownerId || uuidv4(), settings: { enableDriverChampionship: true, enableTeamChampionship: false, enableNationsChampionship: false, enableTrophyChampionship: false, visibility: 'unranked', maxDrivers: 32, }, participantCount: 0, }); await this.leagueRepo.create(league); return league; } /** * Create a test season */ async createSeason(leagueId: string, overrides: Partial<{ id: string; name: string; year: number; status: string; }> = {}) { const season = Season.create({ id: overrides.id || uuidv4(), leagueId, gameId: 'iracing', name: overrides.name || 'Test Season', year: overrides.year || 2024, order: 1, status: overrides.status || 'active', startDate: new Date(), endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), schedulePublished: false, }); await this.seasonRepo.create(season); return season; } /** * Create a test driver */ async createDriver(overrides: Partial<{ id: string; name: string; iracingId: string; country: string; }> = {}) { const driver = Driver.create({ id: overrides.id || uuidv4(), iracingId: overrides.iracingId || `iracing-${uuidv4()}`, name: overrides.name || 'Test Driver', country: overrides.country || 'US', }); // Need to insert directly since driver repo might not exist or be different await this.dataSource.getRepository(DriverOrmEntity).save({ id: driver.id.toString(), iracingId: driver.iracingId, name: driver.name.toString(), country: driver.country, joinedAt: new Date(), bio: null, category: null, avatarRef: null, }); return driver; } /** * Create a test race */ async createRace(overrides: Partial<{ id: string; leagueId: string; scheduledAt: Date; status: string; track: string; car: string; }> = {}) { const race = Race.create({ id: overrides.id || uuidv4(), leagueId: overrides.leagueId || uuidv4(), scheduledAt: overrides.scheduledAt || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), track: overrides.track || 'Laguna Seca', car: overrides.car || 'Formula Ford', status: overrides.status || 'scheduled', }); await this.raceRepo.create(race); return race; } /** * Create a test result */ async createResult(raceId: string, driverId: string, overrides: Partial<{ id: string; position: number; fastestLap: number; incidents: number; startPosition: number; }> = {}) { const result = Result.create({ id: overrides.id || uuidv4(), raceId, driverId, position: overrides.position || 1, fastestLap: overrides.fastestLap || 0, incidents: overrides.incidents || 0, startPosition: overrides.startPosition || 1, }); await this.resultRepo.create(result); return result; } /** * Create complete test scenario: league, season, drivers, races */ async createTestScenario() { const league = await this.createLeague(); const season = await this.createSeason(league.id.toString()); const drivers = await Promise.all([ this.createDriver({ name: 'Driver 1' }), this.createDriver({ name: 'Driver 2' }), this.createDriver({ name: 'Driver 3' }), ]); const races = await Promise.all([ this.createRace({ leagueId: league.id.toString(), name: 'Race 1', scheduledAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) }), this.createRace({ leagueId: league.id.toString(), name: 'Race 2', scheduledAt: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) }), ]); return { league, season, drivers, races }; } /** * Clean up specific entities */ async deleteEntities(entities: { id: string | number }[], entityType: string) { const repository = this.dataSource.getRepository(entityType); for (const entity of entities) { await repository.delete(entity.id); } } }