Files
gridpilot.gg/tests/integration/harness/data-factory.ts
2026-01-08 16:52:37 +01:00

244 lines
7.9 KiB
TypeScript

/**
* 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<void> {
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<void> {
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: any }[], entityType: string) {
const repository = this.dataSource.getRepository(entityType);
for (const entity of entities) {
await repository.delete(entity.id);
}
}
}