import type { IncomingMessage, ServerResponse } from 'node:http'; import { Readable } from 'node:stream'; import { beforeEach, expect, it, vi } from 'vitest'; import { handleCloudAgentsRoutes } from '@electron/api/routes/cloud-agents'; import { CloudAgentsError } from '@electron/services/cloud-agents'; const service = vi.hoisted(() => ({ useAvatarPreset: vi.fn(), uploadAvatar: vi.fn(), create: vi.fn() })); vi.mock('@electron/services/cloud-agents', () => ({ CloudAgentsModule: class { useAvatarPreset = service.useAvatarPreset; uploadAvatar = service.uploadAvatar; create = service.create; }, CloudAgentsError: class extends Error { constructor(readonly status: number, readonly code: string, readonly commandOutcome = 'unknown') { super(code); } }, })); beforeEach(() => vi.resetAllMocks()); async function call(path: string, body?: string, method = 'POST') { const request = Object.assign(Readable.from(body ? [body] : []), { method, headers: {} }) as IncomingMessage; let output = ''; const response = { setHeader: vi.fn(), statusCode: 0, end: (text: string) => { output = text; } } as unknown as ServerResponse; const handled = await handleCloudAgentsRoutes(request, response, new URL(`http://localhost/api/cloud-agents${path}`)); return { handled, status: response.statusCode, body: JSON.parse(output) }; } it('routes only the preset id to Main and returns the canonical icon projection', async () => { const avatar = { icon: '/api/storage/public/images/account/avatar.png', icon_url: 'https://agents.test/api/storage/public/images/account/avatar.png' }; service.useAvatarPreset.mockResolvedValue(avatar); expect(await call('/avatars/preset', JSON.stringify({ id: 'avatar-03' }))).toEqual({ handled: true, status: 200, body: avatar }); expect(service.useAvatarPreset).toHaveBeenCalledExactlyOnceWith({ id: 'avatar-03' }); expect(service.uploadAvatar).not.toHaveBeenCalled(); }); it('keeps the existing file picker route and rejects malformed preset JSON', async () => { service.uploadAvatar.mockResolvedValue(null); expect(await call('/avatars/pick')).toEqual({ handled: true, status: 200, body: null }); expect(service.uploadAvatar).toHaveBeenCalledOnce(); expect((await call('/avatars/preset', '{')).status).toBe(400); expect(service.useAvatarPreset).not.toHaveBeenCalled(); expect((await call('/avatars/preset', undefined, 'GET')).status).toBe(404); }); it.each(['definitive_failure', 'unknown'] as const)('preserves creation outcome %s across the Host API', async outcome => { service.create.mockRejectedValue(new CloudAgentsError(422, 'invalid_input', outcome)); expect(await call('/agents', JSON.stringify({ name: 'test' }))).toEqual({ handled: true, status: 422, body: { success: false, error: 'invalid_input', code: 'invalid_input', commandOutcome: outcome }, }); }); it('marks malformed creation JSON as rejected and unexpected failures as uncertain', async () => { expect((await call('/agents', '{')).body.commandOutcome).toBe('definitive_failure'); expect(service.create).not.toHaveBeenCalled(); service.create.mockRejectedValue(new Error('private internal error')); const result = await call('/agents', '{}'); expect(result).toMatchObject({ status: 502, body: { code: 'cloud_service_unavailable', commandOutcome: 'unknown' } }); expect(result.body.error).not.toContain('private'); });