import { beforeEach, describe, expect, it, vi } from 'vitest' const openAIState = vi.hoisted(() => ({ generate: vi.fn(), edit: vi.fn(), toFile: vi.fn(async () => ({ name: 'mock-file' })), })) const getProviderConfigMock = vi.hoisted(() => vi.fn(async () => ({ id: 'openai-compatible:oa-1', apiKey: 'oa-key', baseUrl: 'https://oa.test/v1', }))) const getImageBase64CachedMock = vi.hoisted(() => vi.fn(async () => 'data:image/png;base64,QQ==')) vi.mock('openai', () => ({ default: class OpenAI { images = { generate: openAIState.generate, edit: openAIState.edit, } }, toFile: openAIState.toFile, })) vi.mock('@/lib/api-config', () => ({ getProviderConfig: getProviderConfigMock, })) vi.mock('@/lib/image-cache', () => ({ getImageBase64Cached: getImageBase64CachedMock, })) import { OpenAICompatibleImageGenerator } from '@/lib/generators/image/openai-compatible' describe('OpenAICompatibleImageGenerator', () => { beforeEach(() => { vi.clearAllMocks() getProviderConfigMock.mockResolvedValue({ id: 'openai-compatible:oa-1', apiKey: 'oa-key', baseUrl: 'https://oa.test/v1', }) }) it('uses official images.generate payload parameters', async () => { openAIState.generate.mockResolvedValueOnce({ data: [{ b64_json: 'YmFzZTY0' }], }) const generator = new OpenAICompatibleImageGenerator('gpt-image-1', 'openai-compatible:oa-1') const result = await generator.generate({ userId: 'user-1', prompt: 'draw a lighthouse', options: { size: '1024x1024', quality: 'high', outputFormat: 'png', responseFormat: 'b64_json', }, }) expect(result.success).toBe(true) expect(result.imageBase64).toBe('YmFzZTY0') expect(result.imageUrl).toBe('data:image/png;base64,YmFzZTY0') expect(openAIState.generate).toHaveBeenCalledWith({ model: 'gpt-image-1', prompt: 'draw a lighthouse', response_format: 'b64_json', output_format: 'png', quality: 'high', size: '1024x1024', }) }) it('uses official images.edit payload when reference images are provided', async () => { openAIState.edit.mockResolvedValueOnce({ data: [{ b64_json: 'ZWRpdA==' }], }) const generator = new OpenAICompatibleImageGenerator('gpt-image-1', 'openai-compatible:oa-1') const result = await generator.generate({ userId: 'user-1', prompt: 'edit this image', referenceImages: ['data:image/png;base64,QQ=='], options: { quality: 'medium', }, }) expect(result.success).toBe(true) expect(openAIState.toFile).toHaveBeenCalledTimes(1) const call = openAIState.edit.mock.calls[0] expect(call).toBeTruthy() if (!call) { throw new Error('images.edit should be called') } expect(call[0]).toMatchObject({ model: 'gpt-image-1', prompt: 'edit this image', response_format: 'b64_json', quality: 'medium', }) expect(Array.isArray((call[0] as { image?: unknown }).image)).toBe(true) }) it('fails explicitly on unsupported option values', async () => { const generator = new OpenAICompatibleImageGenerator('gpt-image-1', 'openai-compatible:oa-1') const result = await generator.generate({ userId: 'user-1', prompt: 'draw', options: { quality: 'ultra', }, }) expect(result.success).toBe(false) expect(result.error).toContain('OPENAI_COMPAT_IMAGE_OPTION_UNSUPPORTED') }) })