ai-chatbot/tests/routes/video-node-creation.test.ts

197 lines
5.5 KiB
TypeScript

import { expect, test } from "@playwright/test";
import {
buildVideoCanvasImageCreationParams,
buildVideoCanvasVideoCreationParams,
defaultVideoCanvasNodeCreationConfig,
getInitialVideoCanvasNodeCreationOrdinal,
normalizeVideoCanvasNodeCreationConfig,
} from "../../lib/video-canvas/node-creation";
import type { VideoCanvasModelCatalogEntry } from "../../lib/video-canvas/video-model-catalog";
import { getContentType } from "../../lib/storage/content-type";
import {
VIDEO_CANVAS_RESOURCE_UPLOAD_PURPOSE,
VIDEO_CANVAS_RESOURCE_UPLOAD_SOURCE_TYPE,
getVideoCanvasUploadedResourceMediaType,
getVideoCanvasUploadedResourceUrl,
validateVideoCanvasUploadedResource,
} from "../../lib/video-canvas/uploaded-resource";
const catalog: VideoCanvasModelCatalogEntry[] = [
{
badge: "",
description: "",
discountRate: 1,
durationLabel: "",
enabled: true,
icon: "seedance",
id: "seedance-1-5-pro",
label: "Seedance1.5 Pro",
membershipOnly: false,
modelRef: "seedance-model-ref",
pointsPerSecondByResolution: {},
shortLabel: "Seedance1.5 Pro",
},
];
test.describe("video canvas node creation defaults", () => {
test("matches the observed image, video, and audio creation state", () => {
expect(defaultVideoCanvasNodeCreationConfig).toEqual({
audio: { advancedSettingsOpen: true },
image: {
count: 1,
height: 350,
modelLabel: "Lib Image",
quality: "标准画质",
ratio: "16:9",
size: "2K",
width: 622,
},
upload: {
accept: "image/*,video/*,audio/*",
maxFileSizeMb: 50,
maxFiles: 10,
placementGap: 450,
},
video: {
count: 1,
durationSeconds: 5,
generateAudio: true,
height: 350,
modelCatalogId: "seedance-1-5-pro",
ratio: "16:9",
resolution: "1080P",
width: 622,
},
});
});
test("normalizes administrator values and preserves explicit false", () => {
expect(
normalizeVideoCanvasNodeCreationConfig({
audio: { advancedSettingsOpen: false },
image: { count: 99, height: 100, ratio: "3:4", width: 9999 },
upload: {
maxFileSizeMb: 9999,
maxFiles: 0,
placementGap: 5,
},
video: {
count: 2,
durationSeconds: 0,
generateAudio: false,
resolution: "4k",
},
}),
).toMatchObject({
audio: { advancedSettingsOpen: false },
image: { count: 4, height: 240, ratio: "3:4", width: 1600 },
upload: {
maxFileSizeMb: 500,
maxFiles: 1,
placementGap: 40,
},
video: {
count: 2,
durationSeconds: 1,
generateAudio: false,
resolution: "4K",
},
});
});
test("writes image defaults into a structured node draft", () => {
expect(
buildVideoCanvasImageCreationParams(defaultVideoCanvasNodeCreationConfig),
).toMatchObject({
count: 1,
imageQuality: "标准画质",
imageSize: "2K",
modelLabel: "Lib Image",
ratio: "16:9",
settings: { ratio: "16:9" },
});
});
test("resolves the configured video catalog item and parameters", () => {
expect(
buildVideoCanvasVideoCreationParams(
defaultVideoCanvasNodeCreationConfig,
catalog,
),
).toMatchObject({
audio: true,
count: 1,
duration: 5,
mode: "text-to-video",
model: "seedance-model-ref",
ratio: "16:9",
resolution: "1080p",
settings: {
modelCatalogId: "seedance-1-5-pro",
modelLabel: "Seedance1.5 Pro",
resolution: "1080P",
},
});
});
test("initializes a session ordinal without reusing numeric titles", () => {
expect(getInitialVideoCanvasNodeCreationOrdinal([])).toBe(1);
expect(
getInitialVideoCanvasNodeCreationOrdinal([
{ title: "提示词" },
{ title: "成品" },
]),
).toBe(2);
expect(
getInitialVideoCanvasNodeCreationOrdinal([
{ title: "图片节点 9" },
{ title: "成品" },
]),
).toBe(10);
});
test("uses a dedicated persistent upload purpose and classifies all supported media", () => {
expect(VIDEO_CANVAS_RESOURCE_UPLOAD_PURPOSE).toBe(
"video-canvas-add-resource",
);
expect(VIDEO_CANVAS_RESOURCE_UPLOAD_SOURCE_TYPE).toBe(
"video_canvas_upload",
);
expect(getVideoCanvasUploadedResourceMediaType("image/png")).toBe(
"image",
);
expect(getVideoCanvasUploadedResourceMediaType("video/webm")).toBe(
"video",
);
expect(getVideoCanvasUploadedResourceMediaType("audio/wav")).toBe(
"audio",
);
expect(getContentType("clip.webm")).toBe("video/webm");
expect(getContentType("voice.wav")).toBe("audio/wav");
});
test("validates uploaded resource size and reads the persistent URL", () => {
expect(
validateVideoCanvasUploadedResource(
{ size: 1024, type: "image/png" },
defaultVideoCanvasNodeCreationConfig.upload,
),
).toEqual({ mediaType: "image", valid: true });
expect(
validateVideoCanvasUploadedResource(
{
size:
(defaultVideoCanvasNodeCreationConfig.upload.maxFileSizeMb + 1) *
1024 *
1024,
type: "video/mp4",
},
defaultVideoCanvasNodeCreationConfig.upload,
),
).toMatchObject({ valid: false });
expect(getVideoCanvasUploadedResourceUrl({ url: "/uploads/file.png" })).toBe(
"/uploads/file.png",
);
});
});