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", ); }); });