import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { PlaywrightAutomationAdapter, } from 'packages/automation/infrastructure/adapters/automation'; import { IRACING_SELECTORS, IRACING_TIMEOUTS, } from 'packages/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { PinoLogAdapter } from 'packages/automation/infrastructure/adapters/logging/PinoLogAdapter'; const shouldRun = process.env.HOSTED_REAL_E2E === '1'; const describeMaybe = shouldRun ? describe : describe.skip; describeMaybe('Real-site hosted session – Cars flow (members.iracing.com)', () => { let adapter: PlaywrightAutomationAdapter; beforeAll(async () => { const logger = new PinoLogAdapter(); adapter = new PlaywrightAutomationAdapter( { headless: true, timeout: IRACING_TIMEOUTS.navigation, mode: 'real', baseUrl: '', userDataDir: '', }, logger, ); const result = await adapter.connect(false); expect(result.success).toBe(true); expect(adapter.isConnected()).toBe(true); const step1Result = await adapter.executeStep(StepId.create(1), {}); expect(step1Result.success).toBe(true); const step2Result = await adapter.executeStep(StepId.create(2), {}); expect(step2Result.success).toBe(true); const page = adapter.getPage(); expect(page).not.toBeNull(); const createRaceButton = page! .locator(IRACING_SELECTORS.hostedRacing.createRaceButton) .first(); await expect( createRaceButton.count(), 'Create Race button should exist on Hosted Racing page', ).resolves.toBeGreaterThan(0); await createRaceButton.click({ timeout: IRACING_TIMEOUTS.elementWait }); const raceInfoContainer = page! .locator(IRACING_SELECTORS.wizard.stepContainers.raceInformation) .first(); await raceInfoContainer.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); expect(await raceInfoContainer.count()).toBeGreaterThan(0); const sessionConfig = { sessionName: 'GridPilot Real – Cars flow', password: 'cars-flow-secret', description: 'Real-site cars flow short path', }; const step3Result = await adapter.executeStep(StepId.create(3), sessionConfig); expect(step3Result.success).toBe(true); const carsSidebarLink = page! .locator(IRACING_SELECTORS.wizard.sidebarLinks.cars) .first(); await carsSidebarLink.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); await carsSidebarLink.click({ timeout: IRACING_TIMEOUTS.elementWait }); const carsContainer = page! .locator(IRACING_SELECTORS.wizard.stepContainers.cars) .first(); await carsContainer.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); expect(await carsContainer.count()).toBeGreaterThan(0); }, 300_000); afterAll(async () => { if (adapter) { await adapter.disconnect(); } }); it( 'opens Add Car UI on real site and lists at least one car', async () => { const page = adapter.getPage(); expect(page).not.toBeNull(); const carsContainer = page! .locator(IRACING_SELECTORS.wizard.stepContainers.cars) .first(); await carsContainer.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); expect(await carsContainer.count()).toBeGreaterThan(0); const addCarButton = page! .locator(IRACING_SELECTORS.steps.addCarButton) .first(); await addCarButton.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); expect(await addCarButton.count()).toBeGreaterThan(0); await addCarButton.click({ timeout: IRACING_TIMEOUTS.elementWait }); const addCarModal = page! .locator(IRACING_SELECTORS.steps.addCarModal) .first(); await addCarModal.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); expect(await addCarModal.count()).toBeGreaterThan(0); const carsTable = addCarModal .locator('table.table.table-striped tbody tr') .first(); await carsTable.waitFor({ state: 'attached', timeout: IRACING_TIMEOUTS.elementWait, }); const rowCount = await addCarModal .locator('table.table.table-striped tbody tr') .count(); expect(rowCount).toBeGreaterThan(0); }, 300_000, ); });