import { describe, expect, it, vi, beforeEach } from 'vitest'; vi.mock('@shared/utils/logger', () => ({ createLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), }), })); vi.mock('@preload/constants/ipcChannels', () => ({ CROSS_TEAM_SEND: 'cross-team:send', CROSS_TEAM_LIST_TARGETS: 'cross-team:listTargets', CROSS_TEAM_GET_OUTBOX: 'cross-team:getOutbox', })); import { initializeCrossTeamHandlers, registerCrossTeamHandlers, removeCrossTeamHandlers, } from '@main/ipc/crossTeam'; function createMockIpcMain() { return { handle: vi.fn(), removeHandler: vi.fn(), }; } function createMockService() { return { send: vi.fn(), listAvailableTargets: vi.fn(), getOutbox: vi.fn(), }; } describe('crossTeam IPC handlers', () => { let mockIpc: ReturnType; let mockService: ReturnType; beforeEach(() => { mockIpc = createMockIpcMain(); mockService = createMockService(); // Re-initialize with fresh service for each test initializeCrossTeamHandlers(mockService as never); }); it('registers 3 IPC handlers', () => { registerCrossTeamHandlers(mockIpc as never); expect(mockIpc.handle).toHaveBeenCalledTimes(3); expect(mockIpc.handle).toHaveBeenCalledWith('cross-team:send', expect.any(Function)); expect(mockIpc.handle).toHaveBeenCalledWith('cross-team:listTargets', expect.any(Function)); expect(mockIpc.handle).toHaveBeenCalledWith('cross-team:getOutbox', expect.any(Function)); }); it('removes all 3 handlers', () => { removeCrossTeamHandlers(mockIpc as never); expect(mockIpc.removeHandler).toHaveBeenCalledTimes(3); expect(mockIpc.removeHandler).toHaveBeenCalledWith('cross-team:send'); expect(mockIpc.removeHandler).toHaveBeenCalledWith('cross-team:listTargets'); expect(mockIpc.removeHandler).toHaveBeenCalledWith('cross-team:getOutbox'); }); it('send handler returns success on valid request', async () => { mockService.send.mockResolvedValue({ messageId: 'msg-1', deliveredToInbox: true }); registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find((c) => c[0] === 'cross-team:send')![1]; const result = await handler({} as never, { fromTeam: 'team-a', fromMember: 'lead', toTeam: 'team-b', text: 'Hello', actionMode: 'delegate', }); expect(result).toEqual({ success: true, data: { messageId: 'msg-1', deliveredToInbox: true }, }); expect(mockService.send).toHaveBeenCalledWith({ fromTeam: 'team-a', fromMember: 'lead', toTeam: 'team-b', text: 'Hello', actionMode: 'delegate', summary: undefined, chainDepth: undefined, }); }); it('send handler rejects invalid actionMode', async () => { registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find((c) => c[0] === 'cross-team:send')![1]; const result = await handler({} as never, { fromTeam: 'team-a', fromMember: 'lead', toTeam: 'team-b', text: 'Hello', actionMode: 'break-everything', }); expect(result).toEqual({ success: false, error: 'actionMode must be one of: do, ask, delegate', }); }); it('send handler returns error on service throw', async () => { mockService.send.mockRejectedValue(new Error('Target team not found')); registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find((c) => c[0] === 'cross-team:send')![1]; const result = await handler({} as never, { fromTeam: 'team-a', fromMember: 'lead', toTeam: 'nonexistent', text: 'Hello', }); expect(result).toEqual({ success: false, error: 'Target team not found' }); }); it('send handler rejects invalid request', async () => { registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find((c) => c[0] === 'cross-team:send')![1]; const result = await handler({} as never, null); expect(result).toEqual({ success: false, error: 'Invalid request' }); }); it('listTargets handler calls service', async () => { mockService.listAvailableTargets.mockResolvedValue([ { teamName: 'team-b', displayName: 'Team B' }, ]); registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find( (c) => c[0] === 'cross-team:listTargets' )![1]; const result = await handler({} as never, 'team-a'); expect(result).toEqual({ success: true, data: [{ teamName: 'team-b', displayName: 'Team B' }], }); expect(mockService.listAvailableTargets).toHaveBeenCalledWith('team-a'); }); it('getOutbox handler calls service', async () => { mockService.getOutbox.mockResolvedValue([]); registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find( (c) => c[0] === 'cross-team:getOutbox' )![1]; const result = await handler({} as never, 'team-a'); expect(result).toEqual({ success: true, data: [] }); expect(mockService.getOutbox).toHaveBeenCalledWith('team-a'); }); it('getOutbox handler rejects empty teamName', async () => { registerCrossTeamHandlers(mockIpc as never); const handler = mockIpc.handle.mock.calls.find( (c) => c[0] === 'cross-team:getOutbox' )![1]; const result = await handler({} as never, ''); expect(result).toEqual({ success: false, error: 'teamName is required' }); }); });