import { beforeEach, describe, expect, it, vi } from 'vitest'; vi.mock('@shared/utils/logger', () => ({ createLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), }), })); import { initializeCliInstallerHandlers, registerCliInstallerHandlers, } from '@main/ipc/cliInstaller'; import { CLI_INSTALLER_GET_PROVIDER_STATUS, CLI_INSTALLER_GET_STATUS, } from '@preload/constants/ipcChannels'; import { createDefaultCliExtensionCapabilities } from '@shared/utils/providerExtensionCapabilities'; import type { CliInstallerService } from '@main/services'; import type { CliInstallationStatus, CliProviderId, CliProviderStatus, IpcResult } from '@shared/types'; import type { IpcMain, IpcMainInvokeEvent } from 'electron'; type IpcHandler = (event: IpcMainInvokeEvent, ...args: unknown[]) => unknown; function createMockIpcMain(): IpcMain & { invoke: (channel: string, ...args: unknown[]) => Promise; } { const handlers = new Map(); const ipcMain = { handle: vi.fn((channel: string, handler: IpcHandler) => { handlers.set(channel, handler); }), removeHandler: vi.fn((channel: string) => { handlers.delete(channel); }), invoke: async (channel: string, ...args: unknown[]) => { const handler = handlers.get(channel); if (!handler) { throw new Error(`No handler for ${channel}`); } return await Promise.resolve(handler({} as IpcMainInvokeEvent, ...args)); }, }; return ipcMain as unknown as IpcMain & { invoke: (channel: string, ...args: unknown[]) => Promise; }; } function provider(overrides: Partial & { providerId: CliProviderId }): CliProviderStatus { const { providerId, ...rest } = overrides; return { providerId, displayName: providerId, supported: true, authenticated: false, authMethod: null, verificationState: 'unknown', modelVerificationState: 'idle', modelCatalogRefreshState: 'idle', statusMessage: null, detailMessage: null, models: [], modelAvailability: [], canLoginFromUi: providerId !== 'opencode', capabilities: { teamLaunch: true, oneShot: true, extensions: createDefaultCliExtensionCapabilities(), }, selectedBackendId: null, resolvedBackendId: null, availableBackends: [], externalRuntimeDiagnostics: [], backend: null, connection: null, modelCatalog: null, runtimeCapabilities: null, subscriptionRateLimits: null, ...rest, }; } function status(providers: CliProviderStatus[]): CliInstallationStatus { return { flavor: 'agent_teams_orchestrator', displayName: 'Multimodel runtime', supportsSelfUpdate: false, showVersionDetails: false, showBinaryPath: false, installed: true, installedVersion: '0.0.3', binaryPath: '/mock/agent_teams_orchestrator', launchError: null, latestVersion: null, updateAvailable: false, authLoggedIn: false, authStatusChecking: false, authMethod: null, providers, }; } describe('cliInstaller IPC handlers', () => { let ipcMain: ReturnType; let service: { getLatestStatusSnapshot: ReturnType; getStatus: ReturnType; getProviderStatus: ReturnType; verifyProviderModels: ReturnType; install: ReturnType; invalidateStatusCache: ReturnType; }; beforeEach(() => { vi.clearAllMocks(); ipcMain = createMockIpcMain(); service = { getLatestStatusSnapshot: vi.fn(() => null), getStatus: vi.fn(), getProviderStatus: vi.fn(), verifyProviderModels: vi.fn(), install: vi.fn(), invalidateStatusCache: vi.fn(), }; initializeCliInstallerHandlers(service as unknown as CliInstallerService); registerCliInstallerHandlers(ipcMain); }); it('does not let explicit hidden Gemini refresh poison cached frontend auth status', async () => { service.getStatus.mockResolvedValue( status([ provider({ providerId: 'anthropic' }), provider({ providerId: 'codex' }), provider({ providerId: 'opencode', canLoginFromUi: false }), ]) ); service.getProviderStatus.mockResolvedValue( provider({ providerId: 'gemini', authenticated: true, authMethod: 'gemini_api_key', models: ['gemini-2.5-pro'], }) ); const initial = (await ipcMain.invoke(CLI_INSTALLER_GET_STATUS)) as IpcResult; expect(initial.success).toBe(true); expect(initial.data?.providers.map((entry) => entry.providerId)).toEqual([ 'anthropic', 'codex', 'opencode', ]); const gemini = (await ipcMain.invoke( CLI_INSTALLER_GET_PROVIDER_STATUS, 'gemini' )) as IpcResult; expect(gemini.success).toBe(true); expect(gemini.data?.authenticated).toBe(true); const cached = (await ipcMain.invoke(CLI_INSTALLER_GET_STATUS)) as IpcResult; expect(service.getStatus).toHaveBeenCalledTimes(1); expect(cached.success).toBe(true); expect(cached.data?.providers.map((entry) => entry.providerId)).toEqual([ 'anthropic', 'codex', 'opencode', ]); expect(cached.data?.authLoggedIn).toBe(false); expect(cached.data?.authMethod).toBeNull(); }); });