import { ElectronApplication } from '@playwright/test'; type IpcHandlerResult = { error?: string; [key: string]: unknown; }; export interface IPCTestResult { channel: string; success: boolean; error?: string; duration: number; } /** * IPCVerifier - Tests IPC channel contracts * * Purpose: Verify main <-> renderer communication works * Scope: Core IPC channels required for app functionality */ export class IPCVerifier { constructor(private app: ElectronApplication) {} /** * Test checkAuth IPC channel */ async testCheckAuth(): Promise { const start = Date.now(); const channel = 'auth:check'; try { const result = await this.app.evaluate( async ({ ipcMain }: { ipcMain: { listeners: (channel: string) => unknown[] } }) => { return new Promise((resolve) => { // Simulate IPC invoke handler by calling the first registered handler for the channel const handlers = ipcMain.listeners('auth:check') || []; const handler = handlers[0] as | ((event: unknown, ...args: unknown[]) => unknown | Promise) | undefined; if (!handler) { resolve({ error: 'Handler not registered' }); } else { // Invoke the handler similar to ipcMain.handle invocation signature // (event, ...args) => Promise const mockEvent: unknown = {}; Promise.resolve(handler(mockEvent)) .then((res: unknown) => resolve(res)) .catch((err: unknown) => resolve({ error: err && err instanceof Error && err.message ? err.message : String(err), }), ); } }); }, ); const typed: IpcHandlerResult = result as IpcHandlerResult; const resultObj: IPCTestResult = { channel, success: !typed.error, duration: Date.now() - start, }; if (typed.error) { resultObj.error = typed.error; } return resultObj; } catch (error) { return { channel, success: false, error: error instanceof Error ? error.message : String(error), duration: Date.now() - start, }; } } /** * Test getBrowserMode IPC channel */ async testGetBrowserMode(): Promise { const start = Date.now(); const channel = 'browser-mode:get'; try { const result = await this.app.evaluate( async ({ ipcMain }: { ipcMain: { listeners: (channel: string) => unknown[] } }) => { return new Promise((resolve) => { const handlers = ipcMain.listeners('browser-mode:get') || []; const handler = handlers[0] as | ((event: unknown, ...args: unknown[]) => unknown | Promise) | undefined; if (!handler) { resolve({ error: 'Handler not registered' }); } else { const mockEvent: unknown = {}; Promise.resolve(handler(mockEvent)) .then((res: unknown) => resolve(res)) .catch((err: unknown) => resolve({ error: err && err instanceof Error && err.message ? err.message : String(err), }), ); } }); }, ); const typed: IpcHandlerResult = result as IpcHandlerResult; const resultObj: IPCTestResult = { channel, success: !typed.error, duration: Date.now() - start, }; if (typed.error) { resultObj.error = typed.error; } return resultObj; } catch (error) { return { channel, success: false, error: error instanceof Error ? error.message : String(error), duration: Date.now() - start, }; } } /** * Test startAutomationSession IPC channel contract */ async testStartAutomationSession(): Promise { const start = Date.now(); const channel = 'start-automation'; try { const result = await this.app.evaluate( async ({ ipcMain }: { ipcMain: { listeners: (channel: string) => unknown[] } }) => { return new Promise((resolve) => { const handlers = ipcMain.listeners('start-automation') || []; const handler = handlers[0] as | (( event: unknown, payload: { sessionName: string; mode: string }, ) => unknown | Promise) | undefined; if (!handler) { resolve({ error: 'Handler not registered' }); } else { // Test with mock data const mockEvent: unknown = {}; Promise.resolve( handler(mockEvent, { sessionName: 'test', mode: 'test' }), ) .then((res: unknown) => resolve(res)) .catch((err: unknown) => resolve({ error: err && err instanceof Error && err.message ? err.message : String(err), }), ); } }); }, ); const typed: IpcHandlerResult = result as IpcHandlerResult; const resultObj: IPCTestResult = { channel, success: !typed.error, duration: Date.now() - start, }; if (typed.error) { resultObj.error = typed.error; } return resultObj; } catch (error) { return { channel, success: false, error: error instanceof Error ? error.message : String(error), duration: Date.now() - start, }; } } /** * Run all IPC tests and return results */ async verifyAllChannels(): Promise { return Promise.all([ this.testCheckAuth(), this.testGetBrowserMode(), this.testStartAutomationSession(), ]); } /** * Format IPC test results for output */ static formatResults(results: IPCTestResult[]): string { const lines = ['IPC Channel Verification:', '']; results.forEach(result => { const status = result.success ? '✓' : '✗'; lines.push(`${status} ${result.channel} (${result.duration}ms)`); if (result.error) { lines.push(` Error: ${result.error}`); } }); return lines.join('\n'); } }