import { describe, it, expect, vi, beforeEach } from 'vitest'; import { supabase } from '../supabase'; vi.mock('../supabase', () => { return { supabase: { functions: { invoke: vi.fn(), }, }, }; }); // Mock global fetch const mockFetch = vi.fn(); global.fetch = mockFetch; // Import code under test after mock definition import { invokeEdgeFunction, setUseGoGateway, setGoGatewayUrl } from '../apiAdapter'; describe('apiAdapter - Go Gateway Strangler Pattern', () => { beforeEach(() => { vi.clearAllMocks(); setUseGoGateway('verify-receipt', false); // Reset switch setGoGatewayUrl('http://localhost:8080'); // Reset gateway url }); it('routes to Supabase Deno Edge Function when USE_GO_GATEWAY is false', async () => { // 1. Mock Deno successful response vi.mocked(supabase.functions.invoke).mockResolvedValue({ data: { success: true, co2Reduction: 21, confidence: 0.95, }, error: null, } as any); // 2. Act const res = await invokeEdgeFunction<{ text: string }, { success: boolean; co2Reduction: number }>('verify-receipt', { text: 'receipt-data', }); // 3. Assertions expect(supabase.functions.invoke).toHaveBeenCalledWith('verify-receipt', { body: { text: 'receipt-data' }, }); expect(mockFetch).not.toHaveBeenCalled(); expect(res.success).toBe(true); expect(res.co2Reduction).toBe(21); }); it('routes to Go Gateway via fetch when USE_GO_GATEWAY is true', async () => { // 1. Enable Go Gateway routing switch setUseGoGateway('verify-receipt', true); setGoGatewayUrl('https://gateway.carboany.com'); // 2. Mock global fetch to return successful response mockFetch.mockResolvedValue({ ok: true, json: vi.fn().mockResolvedValue({ success: true, co2Reduction: 33, confidence: 0.88, }), } as any); // 3. Act const res = await invokeEdgeFunction<{ text: string }, { success: boolean; co2Reduction: number }>('verify-receipt', { text: 'receipt-data', }); // 4. Assertions expect(supabase.functions.invoke).not.toHaveBeenCalled(); expect(mockFetch).toHaveBeenCalledWith('https://gateway.carboany.com/api/v1/verify-receipt', expect.objectContaining({ method: 'POST', body: JSON.stringify({ text: 'receipt-data' }), })); expect(res.success).toBe(true); expect(res.co2Reduction).toBe(33); }); it('throws structured exception when response data contract is broken', async () => { // Enable Go Gateway routing switch setUseGoGateway('verify-receipt', true); // Mock global fetch to return broken schema (missing "co2Reduction" which is required) mockFetch.mockResolvedValue({ ok: true, json: vi.fn().mockResolvedValue({ success: true, // missing co2Reduction confidence: 0.99, }), } as any); // Act & Assert (expecting Contract Validation error) await expect( invokeEdgeFunction<{ text: string }, { success: boolean; co2Reduction: number }>('verify-receipt', { text: 'receipt-data', }) ).rejects.toThrow( '[apiAdapter] API 계약 검증 실패: verify-receipt 응답에 필수 필드(co2Reduction)가 누락되었습니다.' ); }); });