Files
NianAIGC/tests/bailian-client.test.ts
2026-07-14 12:59:07 +08:00

79 lines
3.5 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import {
bailianResultUrls,
bailianStatus,
buildBailianImagePayload,
buildBailianVideoPayload,
deriveBailianNativeBaseUrl,
shouldMockBailian
} from "@/lib/bailian/client";
afterEach(() => {
delete process.env.BAILIAN_IMAGE_MODEL;
delete process.env.BAILIAN_VIDEO_MODEL;
delete process.env.BAILIAN_API_KEY;
delete process.env.DASHSCOPE_API_KEY;
delete process.env.BAILIAN_MOCK;
});
describe("Bailian client", () => {
it("derives native API base from compatible-mode URL", () => {
expect(deriveBailianNativeBaseUrl("https://workspace.cn-beijing.maas.aliyuncs.com/compatible-mode/v1"))
.toBe("https://workspace.cn-beijing.maas.aliyuncs.com");
});
it("does not silently mock when the API key is missing", () => {
expect(shouldMockBailian()).toBe(false);
process.env.BAILIAN_MOCK = "true";
expect(shouldMockBailian()).toBe(true);
});
it("builds Wan 2.7 text-to-image and reference-image payloads", () => {
const text = buildBailianImagePayload("image.generate", { prompt: "海边酒店", width: 2048, height: 2048 });
expect(text).toMatchObject({ model: "wan2.7-image-pro", parameters: { size: "2048*2048", thinking_mode: true, watermark: false } });
const edit = buildBailianImagePayload("image.generate", { prompt: "保持人物一致", imageUrls: ["https://example.com/a.png"], width: 2048, height: 2048 });
expect((edit.input.messages[0].content as Array<Record<string, string>>)[0]).toEqual({ image: "https://example.com/a.png" });
expect(edit.parameters).not.toHaveProperty("thinking_mode");
});
it("preserves a user-selected 9:16 output size for reference images", () => {
const payload = buildBailianImagePayload("image.generate", {
prompt: "x",
imageUrls: ["https://example.com/a.png"],
width: 1440,
height: 2560
});
expect(payload.parameters.size).toBe("1440*2560");
});
it("rejects reference-image output only when total pixels exceed the 2K budget", () => {
expect(() => buildBailianImagePayload("image.generate", { prompt: "x", imageUrls: ["https://example.com/a.png"], width: 2048, height: 2560 }))
.toThrow("总像素");
});
it("maps one or two video images to first and last frames", () => {
const payload = buildBailianVideoPayload({
prompt: "镜头推进",
origin: "https://app.example.com",
materials: [{ type: "image", url: "/first.png" }, { type: "image", url: "/last.png" }],
settings: { duration: 10, resolution: "1080P" }
});
expect(payload.input.media).toEqual([
{ type: "first_frame", url: "https://app.example.com/first.png" },
{ type: "last_frame", url: "https://app.example.com/last.png" }
]);
expect(payload.parameters).toMatchObject({ duration: 10, resolution: "1080P", prompt_extend: true, watermark: false });
});
it("normalizes task state and result URLs", () => {
const response = { output: { task_status: "SUCCEEDED", results: [{ url: "https://example.com/result.png" }] } };
expect(bailianStatus(response)).toBe("succeeded");
expect(bailianResultUrls(response, "image")).toEqual(["https://example.com/result.png"]);
});
it("extracts Wan 2.7 image URLs from choices content", () => {
const response = { output: { task_status: "SUCCEEDED", choices: [{ message: { content: [{ type: "image", image: "https://example.com/choice.png" }] } }] } };
expect(bailianResultUrls(response, "image")).toEqual(["https://example.com/choice.png"]);
});
});