109 lines
4.0 KiB
TypeScript
109 lines
4.0 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { createSeedanceTask, extractSeedanceUsage, querySeedanceTask } from "@/lib/seedance/client";
|
|
|
|
describe("Seedance usage extraction", () => {
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
delete process.env.SEEDANCE_API_KEY;
|
|
delete process.env.SEEDANCE_BASE_URL;
|
|
delete process.env.SEEDANCE_MODEL;
|
|
});
|
|
|
|
it("reads completion_tokens from top-level and nested provider responses", () => {
|
|
expect(extractSeedanceUsage({ usage: { completion_tokens: 12345 } })).toEqual({ completionTokens: 12345 });
|
|
expect(extractSeedanceUsage({ data: { usage: { completionTokens: 67890 } } })).toEqual({ completionTokens: 67890 });
|
|
expect(extractSeedanceUsage({ usage: { prompt_tokens: 100 } })).toBeUndefined();
|
|
});
|
|
|
|
it("sends the official Seedance 2.0 multimodal payload without UI labels", async () => {
|
|
process.env.SEEDANCE_API_KEY = "test-key";
|
|
process.env.SEEDANCE_BASE_URL = "https://ark.test/api/v3";
|
|
process.env.SEEDANCE_MODEL = "doubao-seedance-2-0-260128";
|
|
let body: Record<string, unknown> | undefined;
|
|
vi.stubGlobal("fetch", vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
|
|
body = JSON.parse(String(init?.body));
|
|
return new Response(JSON.stringify({ id: "task-1" }), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
}));
|
|
|
|
await createSeedanceTask({
|
|
prompt: "combine",
|
|
settings: { ratio: "16:9", duration: 8, resolution: "1080p" },
|
|
materials: [
|
|
{ type: "image", url: "/image.png", label: "@图片1" },
|
|
{ type: "video", url: "/video.mp4", label: "@视频1" },
|
|
{ type: "audio", url: "/audio.mp3", label: "@音频1" }
|
|
],
|
|
origin: "https://app.test"
|
|
});
|
|
|
|
expect(body).toMatchObject({
|
|
model: "doubao-seedance-2-0-260128",
|
|
generate_audio: true,
|
|
ratio: "16:9",
|
|
duration: 8,
|
|
resolution: "1080p",
|
|
watermark: false
|
|
});
|
|
const content = body?.content as Array<Record<string, unknown>>;
|
|
expect(content).toHaveLength(4);
|
|
expect(content.slice(1).every((item) => !("label" in item))).toBe(true);
|
|
});
|
|
|
|
it("keeps the provider expired status distinct from a failed task", async () => {
|
|
process.env.SEEDANCE_API_KEY = "test-key";
|
|
process.env.SEEDANCE_BASE_URL = "https://ark.test/api/v3";
|
|
vi.stubGlobal("fetch", vi.fn(async () => new Response(JSON.stringify({ id: "task-1", status: "expired" }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" }
|
|
})));
|
|
|
|
await expect(querySeedanceTask("task-1")).resolves.toMatchObject({ status: "expired" });
|
|
});
|
|
|
|
it("sends the selected Seedance 2.5 model and accepts its extended limits", async () => {
|
|
process.env.SEEDANCE_API_KEY = "test-key";
|
|
let body: Record<string, unknown> | undefined;
|
|
vi.stubGlobal("fetch", vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
|
|
body = JSON.parse(String(init?.body));
|
|
return new Response(JSON.stringify({ id: "task-25" }), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
}));
|
|
|
|
await createSeedanceTask({
|
|
model: "doubao-seedance-2-5-260628",
|
|
prompt: "combine",
|
|
settings: { ratio: "16:9", duration: 30, resolution: "720p" },
|
|
materials: Array.from({ length: 5 }, (_, index) => ({
|
|
type: "image" as const,
|
|
url: `/image-${index + 1}.png`,
|
|
label: `@图片${index + 1}`
|
|
})),
|
|
origin: "https://app.test"
|
|
});
|
|
|
|
expect(body).toMatchObject({
|
|
model: "doubao-seedance-2-5-260628",
|
|
duration: 30,
|
|
omni_reference_task_type: "auto"
|
|
});
|
|
expect(body?.content).toHaveLength(6);
|
|
});
|
|
|
|
it("rejects more materials than the Seedance 2.0 content limit before calling the provider", async () => {
|
|
process.env.SEEDANCE_API_KEY = "test-key";
|
|
const fetchMock = vi.fn();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
await expect(createSeedanceTask({
|
|
prompt: "combine",
|
|
settings: {},
|
|
materials: Array.from({ length: 5 }, (_, index) => ({
|
|
type: "image" as const,
|
|
url: `/image-${index + 1}.png`,
|
|
label: `@图片${index + 1}`
|
|
})),
|
|
origin: "https://app.test"
|
|
})).rejects.toThrow("最多支持 4 个素材");
|
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
});
|
|
});
|