import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { DIContainer } from '../../../..//apps/companion/main/di-container'; import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig'; import { PlaywrightAutomationAdapter } from '../../../..//packages/automation/infrastructure/adapters/automation'; describe('companion start automation - browser connection failure before steps', () => { const originalEnv = { ...process.env }; let originalTestLauncher: unknown; beforeEach(() => { process.env = { ...originalEnv, NODE_ENV: 'production' }; originalTestLauncher = (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & { testLauncher?: unknown; }).testLauncher; const failingLauncher = { launch: async () => { throw new Error('Simulated browser launch failure'); }, launchPersistentContext: async () => { throw new Error('Simulated persistent context failure'); }, }; (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & { testLauncher?: typeof failingLauncher; }).testLauncher = failingLauncher; DIContainer.resetInstance(); }); afterEach(async () => { const container = DIContainer.getInstance(); await container.shutdown(); DIContainer.resetInstance(); (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & { testLauncher?: unknown; }).testLauncher = originalTestLauncher; process.env = originalEnv; }); it('fails browser connection and aborts before executing step 1', async () => { const container = DIContainer.getInstance(); const startAutomationUseCase = container.getStartAutomationUseCase(); const sessionRepository = container.getSessionRepository(); const automationEngine = container.getAutomationEngine(); const connectionResult = await container.initializeBrowserConnection(); expect(connectionResult.success).toBe(false); expect(connectionResult.error).toBeDefined(); const executeStepSpy = vi.spyOn( automationEngine, 'executeStep' as keyof typeof automationEngine, ); const config: HostedSessionConfig = { sessionName: 'Companion integration connection failure', trackId: 'test-track', carIds: ['car-1'], }; let sessionId: string | null = null; try { const dto = await startAutomationUseCase.execute(config); sessionId = dto.sessionId; } catch (error) { expect((error as Error).message).toBeDefined(); } expect(executeStepSpy).not.toHaveBeenCalled(); if (sessionId) { const session = await sessionRepository.findById(sessionId); if (session) { const message = session.errorMessage as string | undefined; if (message) { expect(message).not.toContain('Step 1 (LOGIN) failed: Browser not connected'); expect(message.toLowerCase()).toContain('browser'); } } } }); it('treats successful adapter connect without a page as connection failure', async () => { const container = DIContainer.getInstance(); const browserAutomation = container.getBrowserAutomation(); expect(browserAutomation).toBeInstanceOf(PlaywrightAutomationAdapter); const AdapterWithPrototype = PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & { prototype: { connect: () => Promise<{ success: boolean; error?: string }>; }; }; const originalConnect = AdapterWithPrototype.prototype.connect; AdapterWithPrototype.prototype.connect = async function () { return { success: true }; }; try { const connectionResult = await container.initializeBrowserConnection(); expect(connectionResult.success).toBe(false); expect(connectionResult.error).toBeDefined(); expect(String(connectionResult.error).toLowerCase()).toContain('browser'); } finally { AdapterWithPrototype.prototype.connect = originalConnect; } }); });