import { describe, expect, it, vi, afterEach } from 'vitest'; import { embedCardImage, formatEmbeddingForPg } from '../../lib/card-embed.js'; describe('formatEmbeddingForPg', () => { it('formats vectors for pgvector literals', () => { expect(formatEmbeddingForPg([0.1, 0.2, 0.3])).toBe('[0.10000000,0.20000000,0.30000000]'); }); }); describe('embedCardImage', () => { afterEach(() => { vi.unstubAllGlobals(); delete process.env.AI_GATEWAY_API_KEY; }); it('throws when AI_GATEWAY_API_KEY is missing', async () => { await expect(embedCardImage('data:image/jpeg;base64,abc')).rejects.toThrow( 'AI_GATEWAY_API_KEY is not configured' ); }); it('returns embedding values from the gateway response', async () => { process.env.AI_GATEWAY_API_KEY = 'test-key'; const vector = Array.from({ length: 1024 }, (_, index) => index / 1024); vi.stubGlobal( 'fetch', vi.fn(async () => ({ ok: true, json: async () => ({ data: [{ embedding: vector }] }), })) ); const embedding = await embedCardImage('data:image/jpeg;base64,abc'); expect(embedding).toEqual(vector); }); it('sends catalog image URLs as plain strings (not OpenAI image_url objects)', async () => { process.env.AI_GATEWAY_API_KEY = 'test-key'; const fetchMock = vi.fn(async () => ({ ok: true, json: async () => ({ data: [{ embedding: Array.from({ length: 1024 }, () => 0.1) }], }), })); vi.stubGlobal('fetch', fetchMock); await embedCardImage({ imageUrl: 'https://cards.scryfall.io/normal/front/a.jpg' }); const [, requestInit] = fetchMock.mock.calls[0]; expect(JSON.parse(requestInit.body)).toMatchObject({ input: 'https://cards.scryfall.io/normal/front/a.jpg', }); }); it('truncates oversized gateway vectors to the catalog dimension', async () => { process.env.AI_GATEWAY_API_KEY = 'test-key'; vi.stubGlobal( 'fetch', vi.fn(async () => ({ ok: true, json: async () => ({ data: [{ embedding: Array.from({ length: 1536 }, (_, index) => index / 1536) }], }), })) ); const embedding = await embedCardImage('data:image/jpeg;base64,abc'); expect(embedding).toHaveLength(1024); expect(embedding[0]).toBe(0); expect(embedding[1023]).toBeCloseTo(1023 / 1536, 5); }); });