import { afterEach, describe, expect, it, vi } from 'vitest'; import { attachInteractionSession, sendInteractionMessage, stopInteractionSession, } from './gateway-api.js'; const gateway = 'https://gateway.example.test'; const cookie = 'session=test'; const base = { agentName: 'Nova', correlationId: 'corr-1', sessionId: 'session-1' }; afterEach(() => vi.unstubAllGlobals()); /** Unit coverage: the TUI preserves a non-success gateway response in its CLI error. */ describe('interaction gateway error mapping', (): void => { it.each([ { name: 'attach unauthorized', response: { status: 401, message: 'Invalid or expired session' }, invoke: (): Promise => attachInteractionSession(gateway, cookie, base), expected: 'Failed to attach interaction session (401): {"message":"Invalid or expired session"}', }, { name: 'send invalid request', response: { status: 403, message: 'Content and idempotency key are required' }, invoke: (): Promise => sendInteractionMessage(gateway, cookie, { ...base, content: 'hello', idempotencyKey: 'message-1', }), expected: 'Failed to send interaction message (403): {"message":"Content and idempotency key are required"}', }, { name: 'stop forbidden', response: { status: 403, message: 'Runtime termination approval denied' }, invoke: (): Promise => stopInteractionSession(gateway, cookie, { ...base, approvalRef: 'approval-1' }), expected: 'Failed to stop interaction session (403): {"message":"Runtime termination approval denied"}', }, ])( '$name preserves the typed gateway denial in the CLI error', async ({ response, invoke, expected }) => { vi.stubGlobal( 'fetch', vi.fn( async () => new Response(JSON.stringify({ message: response.message }), { status: response.status, headers: { 'Content-Type': 'application/json' }, }), ), ); await expect(invoke()).rejects.toThrow(expected); }, ); });