import { describe, expect, it, vi } from "vitest"; import { createDefaultProviderRegistry, MockImageProviderAdapter, normalizeImageAssets, normalizeProviderError, OpenAICompatibleImageProviderAdapter, SiliconFlowImageProviderAdapter } from "../index"; describe("provider adapter registry", () => { it("creates implemented and reserved adapters", () => { const registry = createDefaultProviderRegistry(); expect(registry.mock.provider).toBe("mock"); expect(registry["openai-compatible"].provider).toBe("openai-compatible"); expect(registry.siliconflow.provider).toBe("siliconflow"); expect(registry.dashscope.provider).toBe("dashscope"); expect(registry.volcengine.provider).toBe("volcengine"); expect(registry.zhipu.provider).toBe("zhipu"); expect(registry["custom-template"].provider).toBe("custom-template"); }); }); describe("mock provider", () => { it("returns deterministic URL assets with mapped dimensions", async () => { const adapter = new MockImageProviderAdapter(); const result = await adapter.generateTextToImage( { model: "mock-wallpaper", prompt: "misty mountain wallpaper", size: { aspectRatio: "16:9", resolution: "2k" }, seed: 42 }, {} ); expect(result.assets[0]).toMatchObject({ kind: "url", width: 2560, height: 1440, seed: 42 }); expect(result.usage?.imageCount).toBe(1); }); it("can return base64 assets for local tests", async () => { const adapter = new MockImageProviderAdapter(); const result = await adapter.generateTextToImage( { model: "mock-wallpaper", prompt: "phone wallpaper", responseFormat: "base64", size: { aspectRatio: "9:16", resolution: "1k" } }, {} ); expect(result.assets[0]?.kind).toBe("base64"); expect(result.assets[0]?.mimeType).toBe("image/png"); expect(result.assets[0]?.width).toBe(720); expect(result.assets[0]?.height).toBe(1280); }); }); describe("OpenAI compatible provider", () => { it("posts to configurable image endpoint and normalizes base64 response", async () => { const fetch = vi.fn(async (_url: URL | RequestInfo, init?: RequestInit) => { expect(_url).toBe("https://new-api.example.com/v1/images/generations"); expect(JSON.parse(String(init?.body))).toMatchObject({ model: "gpt-image-1", prompt: "desktop wallpaper", n: 1, size: "1536x1024", response_format: "b64_json" }); return jsonResponse({ data: [{ b64_json: "data:image/png;base64,abc123" }], usage: { input_tokens: 12, output_tokens: 0 } }); }); const adapter = new OpenAICompatibleImageProviderAdapter(); const result = await adapter.generateTextToImage( { baseUrl: "https://new-api.example.com", model: "gpt-image-1", prompt: "desktop wallpaper", responseFormat: "base64", size: { aspectRatio: "16:9", resolution: "4k" } }, { auth: { apiKey: "test-key" }, fetch } ); expect(result.assets[0]).toMatchObject({ kind: "base64", value: "abc123", mimeType: "image/png", width: 1536, height: 1024 }); expect(result.usage?.inputTokens).toBe(12); }); }); describe("SiliconFlow provider", () => { it("uses image_size and normalizes URL response", async () => { const fetch = vi.fn(async (_url: URL | RequestInfo, init?: RequestInit) => { expect(_url).toBe("https://api.siliconflow.cn/v1/images/generations"); expect(JSON.parse(String(init?.body))).toMatchObject({ model: "black-forest-labs/FLUX.2-pro", prompt: "portrait wallpaper", image_size: "720x1280", batch_size: 1, seed: 7 }); return jsonResponse({ data: [{ url: "https://cdn.example.com/result.png" }] }); }); const adapter = new SiliconFlowImageProviderAdapter(); const result = await adapter.generateTextToImage( { model: "black-forest-labs/FLUX.2-pro", prompt: "portrait wallpaper", size: { aspectRatio: "9:16", resolution: "1k" }, seed: 7 }, { auth: { apiKey: "sf-key" }, fetch } ); expect(result.assets[0]).toMatchObject({ kind: "url", value: "https://cdn.example.com/result.png", width: 720, height: 1280 }); }); }); describe("normalization helpers", () => { it("normalizes common provider errors", () => { expect(normalizeProviderError("siliconflow", { status: 429, message: "rate limit exceeded" })).toMatchObject({ category: "rate_limit", retryable: true, statusCode: 429 }); expect(normalizeProviderError("openai-compatible", { status: 401, message: "invalid api key" })).toMatchObject({ category: "authentication", retryable: false }); expect(normalizeProviderError("openai-compatible", { status: 504, message: "gateway timeout" })).toMatchObject({ category: "timeout", retryable: true }); }); it("normalizes URL and base64 image payloads", () => { expect(normalizeImageAssets({ data: [{ url: "https://example.com/a.png" }] })[0]).toMatchObject({ kind: "url", value: "https://example.com/a.png" }); expect(normalizeImageAssets({ images: [{ image_base64: "data:image/jpeg;base64,zzz" }] })[0]).toMatchObject({ kind: "base64", value: "zzz", mimeType: "image/jpeg" }); }); }); function jsonResponse(body: unknown, status = 200): Response { return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } }); }