Files
ttstd-infinite-canvas/web/test/canvas-video-regeneration.test.ts
T
爱笑的毛毛虫andsikongyue d33c6389d4 feat(canvas): 视频节点截取重生成 - 支持多段/时间线导入并调用视频模型批量重生成 (#197)
* feat(canvas): 视频节点截取重生成 - 支持多段/时间线导入并调用视频模型批量重生成

* test(canvas): 视频节点时间线导入 - 修正旧数据标题回退测试

* style(canvas): 视频节点截取重生成 - 格式化新增文件并修正测试

---------

Co-authored-by: sikongyue <3155157671@qq.com>
2026-08-10 00:13:02 +08:00

129 lines
5.8 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { listVideoReferenceModels, validateVideoSegmentBatch, videoReferenceOperationError, videoReferenceRegenerationError, videoReferenceSegmentError } from "../src/lib/canvas/canvas-video-regeneration";
import { defaultModelCapabilityConfig } from "../src/lib/model-capabilities";
import { defaultConfig, type AiConfig, type ModelChannel } from "../src/stores/use-config-store";
function supportedVideoConfig(overrides: { model?: string; maxVideos?: number; maxVideoDurationSeconds?: number; operations?: string[]; baseUrl?: string } = {}): AiConfig {
const model = overrides.model || "seedance-1.0-pro";
const capability = defaultModelCapabilityConfig("newapi-channel-2", model);
if (capability.video) {
capability.video.references.maxVideos = overrides.maxVideos ?? 3;
capability.video.references.maxVideoDurationSeconds = overrides.maxVideoDurationSeconds ?? 15;
capability.video.operations = overrides.operations ?? ["text_to_video", "image_to_video", "extend"];
}
const channel: ModelChannel = {
id: "test",
name: "测试渠道",
baseUrl: overrides.baseUrl || "https://api.example.com",
apiKey: "test-key",
apiFormat: "openai",
interfaceType: "newapi-channel-2",
models: [model],
scope: "user",
modelCosts: [
{
model,
capability: "video",
protocol: "newapi-channel-2",
billingMode: "per_second",
unitPriceMicrocredits: 1,
capabilityConfig: capability,
},
],
};
return {
...defaultConfig,
model: `test::${model}`,
videoModel: `test::${model}`,
models: [`test::${model}`],
videoModels: [`test::${model}`],
channels: [channel],
baseUrl: channel.baseUrl,
};
}
describe("videoReferenceRegenerationError", () => {
test("模型不支持参考视频时返回提示", () => {
const config: AiConfig = { ...defaultConfig, model: "default::grok-imagine-video", videoModel: "default::grok-imagine-video" };
expect(videoReferenceRegenerationError(config)).toContain("不支持参考视频");
});
test("模型没有可用生成模式时返回提示", () => {
const config = supportedVideoConfig({ operations: [] });
expect(videoReferenceRegenerationError(config)).toContain("没有可用的视频生成模式");
});
test("模型支持参考视频且有可用模式时无错误", () => {
expect(videoReferenceRegenerationError(supportedVideoConfig())).toBe("");
});
});
describe("videoReferenceOperationError", () => {
test("所选模式不在模型能力中时返回提示", () => {
const config = supportedVideoConfig({ operations: ["text_to_video", "image_to_video", "extend"] });
expect(videoReferenceOperationError(config, "inpaint")).toContain("不支持所选生成模式");
});
test("所选模式在模型能力中时无错误", () => {
expect(videoReferenceOperationError(supportedVideoConfig(), "extend")).toBe("");
});
});
describe("listVideoReferenceModels", () => {
test("默认配置没有可用的参考视频模型", () => {
const config: AiConfig = { ...defaultConfig, model: "default::grok-imagine-video", videoModel: "default::grok-imagine-video" };
expect(listVideoReferenceModels(config)).toEqual([]);
});
test("只返回支持参考视频且有可用模式的模型", () => {
expect(listVideoReferenceModels(supportedVideoConfig())).toEqual(["test::seedance-1.0-pro"]);
});
test("过滤掉没有可用生成模式的模型", () => {
const config = supportedVideoConfig({ operations: [] });
expect(listVideoReferenceModels(config)).toEqual([]);
});
test("过滤掉未配置 API Key 的渠道模型", () => {
const config = supportedVideoConfig();
config.channels[0].apiKey = "";
expect(listVideoReferenceModels(config)).toEqual([]);
});
});
describe("videoReferenceSegmentError", () => {
test("片段超过模型参考视频上限时返回提示", () => {
const config = supportedVideoConfig({ maxVideoDurationSeconds: 15 });
expect(videoReferenceSegmentError(config, 16000)).toContain("不能超过当前模型参考视频上限(15 秒)");
});
test("Seedance 单段少于 2 秒时返回提示", () => {
const config = supportedVideoConfig({ model: "seedance-1.0-pro" });
expect(videoReferenceSegmentError(config, 1500)).toContain("至少 2 秒");
});
test("合法片段时长无错误", () => {
expect(videoReferenceSegmentError(supportedVideoConfig(), 5000)).toBe("");
});
});
describe("validateVideoSegmentBatch", () => {
test("模型、模式与片段时长都合法时无错误", () => {
expect(validateVideoSegmentBatch(supportedVideoConfig(), [{ startMs: 2000, endMs: 5000 }], "extend")).toBe("");
});
test("模型不支持参考视频时返回首个错误", () => {
const config: AiConfig = { ...defaultConfig, model: "default::grok-imagine-video", videoModel: "default::grok-imagine-video" };
expect(validateVideoSegmentBatch(config, [{ startMs: 2000, endMs: 5000 }], "extend")).toContain("不支持参考视频");
});
test("模式不在模型能力中时返回操作错误", () => {
expect(validateVideoSegmentBatch(supportedVideoConfig(), [{ startMs: 2000, endMs: 5000 }], "inpaint")).toContain("不支持所选生成模式");
});
test("片段超过模型时长上限时返回片段错误", () => {
expect(validateVideoSegmentBatch(supportedVideoConfig({ maxVideoDurationSeconds: 15 }), [{ startMs: 0, endMs: 16000 }], "extend")).toContain("不能超过当前模型参考视频上限");
});
});