import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { FixtureServer, PlaywrightAutomationAdapter, } from 'packages/automation/infrastructure/adapters/automation'; import { IRACING_SELECTORS } from 'packages/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { PinoLogAdapter } from 'packages/automation/infrastructure/adapters/logging/PinoLogAdapter'; describe('Real Playwright hosted-session smoke (fixtures, steps 2–7)', () => { let server: FixtureServer; let adapter: PlaywrightAutomationAdapter; let baseUrl: string; beforeAll(async () => { server = new FixtureServer(); const info = await server.start(); baseUrl = info.url; const logger = new PinoLogAdapter(); adapter = new PlaywrightAutomationAdapter( { headless: true, timeout: 8000, mode: 'real', baseUrl, userDataDir: '', }, logger, ); const result = await adapter.connect(false); expect(result.success).toBe(true); expect(adapter.isConnected()).toBe(true); expect(adapter.getPage()).not.toBeNull(); }); afterAll(async () => { if (adapter) { await adapter.disconnect(); } if (server) { await server.stop(); } }); async function expectContextOpen(stepLabel: string) { const page = adapter.getPage(); expect(page, `${stepLabel}: page should exist`).not.toBeNull(); const closed = await page!.isClosed(); expect(closed, `${stepLabel}: page should be open`).toBe(false); expect(adapter.isConnected(), `${stepLabel}: adapter stays connected`).toBe(true); } async function navigateToFixtureStep( stepNumber: number, label: string, stepKey?: keyof typeof IRACING_SELECTORS.wizard.stepContainers, ) { const page = adapter.getPage(); expect(page).not.toBeNull(); await adapter.navigateToPage(server.getFixtureUrl(stepNumber)); await page!.waitForLoadState('domcontentloaded'); await expectContextOpen(`after navigate step ${stepNumber} (${label})`); if (stepKey) { const selector = IRACING_SELECTORS.wizard.stepContainers[stepKey]; const container = page!.locator(selector).first(); const count = await container.count(); expect( count, `${label}: expected container ${selector} to exist on fixture HTML`, ).toBeGreaterThan(0); } } it( 'keeps browser context open and reaches Time Limits using real adapter against fixtures', async () => { await navigateToFixtureStep(2, 'Create a Race'); const step2Result = await adapter.executeStep( StepId.create(2), {} as Record, ); expect(step2Result.success).toBe(true); await expectContextOpen('after step 2'); await navigateToFixtureStep(3, 'Race Information', 'raceInformation'); const step3Result = await adapter.executeStep( StepId.create(3), { sessionName: 'GridPilot Smoke Session', password: 'smokepw', description: 'Real Playwright smoke path using fixtures', } as Record, ); expect(step3Result.success).toBe(true); await expectContextOpen('after step 3'); await navigateToFixtureStep(4, 'Server Details', 'serverDetails'); const step4Result = await adapter.executeStep( StepId.create(4), { region: 'US', startNow: true, } as Record, ); expect(step4Result.success).toBe(true); await expectContextOpen('after step 4'); await navigateToFixtureStep(5, 'Set Admins', 'admins'); const step5Result = await adapter.executeStep( StepId.create(5), {} as Record, ); expect(step5Result.success).toBe(true); await expectContextOpen('after step 5'); await navigateToFixtureStep(6, 'Admins drawer', 'admins'); const step6Result = await adapter.executeStep( StepId.create(6), { adminSearch: 'Marc', } as Record, ); expect(step6Result.success).toBe(true); await expectContextOpen('after step 6'); await navigateToFixtureStep(7, 'Time Limits', 'timeLimit'); const step7Result = await adapter.executeStep( StepId.create(7), { practice: 10, qualify: 10, race: 20, } as Record, ); expect(step7Result.success).toBe(true); await expectContextOpen('after step 7'); const page = adapter.getPage(); expect(page).not.toBeNull(); const footerText = await page!.textContent('.wizard-footer'); expect(footerText || '').toMatch(/Cars/i); const overlay = await page!.$('#gridpilot-overlay'); expect(overlay, 'overlay should be present in real mode').not.toBeNull(); }, 60000, ); });