import type { AutomationResult } from 'apps/companion/main/automation/application/ports/AutomationResults'; import { StepId } from 'apps/companion/main/automation/domain/value-objects/StepId'; import { PlaywrightAutomationAdapter, FixtureServer, } from 'core/automation/infrastructure//automation'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter'; export interface StepHarness { server: FixtureServer; adapter: PlaywrightAutomationAdapter; baseUrl: string; getFixtureUrl(step: number): string; navigateToFixtureStep(step: number): Promise; executeStep(step: number, config: Record): Promise; executeStepWithAutoNavigation( step: number, config: Record, ): Promise; executeStepWithFixtureMismatch( step: number, config: Record, ): Promise; dispose(): Promise; } async function createRealAdapter(baseUrl: string): Promise { const logger = new PinoLogAdapter(); const adapter = new PlaywrightAutomationAdapter( { headless: true, timeout: 8000, mode: 'real', baseUrl, userDataDir: '', }, logger, ); const result = await adapter.connect(false); if (!result.success) { throw new Error(result.error || 'Failed to connect Playwright adapter'); } return adapter; } async function createMockAdapter(): Promise { const logger = new PinoLogAdapter(); const adapter = new PlaywrightAutomationAdapter( { headless: true, timeout: 5000, mode: 'mock', }, logger, ); const result = await adapter.connect(); if (!result.success) { throw new Error(result.error || 'Failed to connect mock Playwright adapter'); } return adapter; } export async function createStepHarness(useMock: boolean = false): Promise { const server = new FixtureServer(); const { url } = await server.start(); const adapter = useMock ? await createMockAdapter() : await createRealAdapter(url); async function navigateToFixtureStep(step: number): Promise { await adapter.navigateToPage(server.getFixtureUrl(step)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); } async function executeStepWithAutoNavigation( step: number, config: Record, ): Promise { const skipFixtureNavigationFlag = (config as { __skipFixtureNavigation?: unknown }).__skipFixtureNavigation; if (skipFixtureNavigationFlag === true) { throw new Error( '__skipFixtureNavigation is not allowed in auto-navigation path', ); } return adapter.executeStep(StepId.create(step), config); } async function executeStepWithFixtureMismatch( step: number, config: Record, ): Promise { return adapter.executeStep(StepId.create(step), { ...config, __skipFixtureNavigation: true, }); } async function executeStep( step: number, config: Record, ): Promise { return executeStepWithFixtureMismatch(step, config); } async function dispose(): Promise { await adapter.disconnect(); await server.stop(); } return { server, adapter, baseUrl: url, getFixtureUrl: (step) => server.getFixtureUrl(step), navigateToFixtureStep, executeStep, executeStepWithAutoNavigation, executeStepWithFixtureMismatch, dispose, }; }