1 changed files with 85 additions and 0 deletions
@ -0,0 +1,85 @@ |
|||||
|
import { describe, expect, it } from "vitest"; |
||||
|
import { |
||||
|
buildComposerConfigPersistPatch, |
||||
|
} from "@/components/composer/composerDraftHelpers"; |
||||
|
import { readVideoGenerationConfig } from "@/utils/generationConfig"; |
||||
|
import type { GenerationNodeConfig } from "@/utils/generationConfig"; |
||||
|
import type { GenerateVideoNodeData, NanoBananaNodeData, SelectedModel, WorkflowNode } from "@/types"; |
||||
|
|
||||
|
const selectedModel: SelectedModel = { |
||||
|
provider: "popiserver", |
||||
|
modelId: "video-1", |
||||
|
displayName: "Video One", |
||||
|
capabilities: ["text-to-video", "image-to-video"], |
||||
|
}; |
||||
|
|
||||
|
function config(overrides: Partial<GenerationNodeConfig> = {}): GenerationNodeConfig { |
||||
|
return { |
||||
|
prompt: "a clip", |
||||
|
selectedModel, |
||||
|
inputImages: [], |
||||
|
batchSize: 1, |
||||
|
referenceSubjectList: [], |
||||
|
parameters: {}, |
||||
|
extraTaskParams: {}, |
||||
|
...overrides, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
function videoNode(): WorkflowNode { |
||||
|
return { |
||||
|
id: "vid-1", |
||||
|
type: "generateVideo", |
||||
|
selected: true, |
||||
|
position: { x: 0, y: 0 }, |
||||
|
data: { |
||||
|
inputPrompt: "a clip", |
||||
|
inputImages: [], |
||||
|
outputVideo: null, |
||||
|
selectedModel, |
||||
|
parameters: {}, |
||||
|
status: "idle", |
||||
|
error: null, |
||||
|
videoHistory: [], |
||||
|
selectedVideoHistoryIndex: 0, |
||||
|
} as GenerateVideoNodeData, |
||||
|
} as WorkflowNode; |
||||
|
} |
||||
|
|
||||
|
function imageNode(): WorkflowNode { |
||||
|
return { |
||||
|
id: "img-1", |
||||
|
type: "nanoBanana", |
||||
|
selected: true, |
||||
|
position: { x: 0, y: 0 }, |
||||
|
data: { |
||||
|
inputPrompt: "a picture", |
||||
|
inputImages: [], |
||||
|
outputImage: null, |
||||
|
selectedModel, |
||||
|
status: "idle", |
||||
|
error: null, |
||||
|
} as NanoBananaNodeData, |
||||
|
} as WorkflowNode; |
||||
|
} |
||||
|
|
||||
|
describe("buildComposerConfigPersistPatch", () => { |
||||
|
it("persists the chosen batchSize (视频数量) for video nodes", () => { |
||||
|
const patch = buildComposerConfigPersistPatch(videoNode(), config({ batchSize: 3 })); |
||||
|
expect((patch as Partial<GenerateVideoNodeData>).batchSize).toBe(3); |
||||
|
}); |
||||
|
|
||||
|
it("round-trips a video batchSize back through readVideoGenerationConfig", () => { |
||||
|
const node = videoNode(); |
||||
|
const patch = buildComposerConfigPersistPatch(node, config({ batchSize: 4 })); |
||||
|
const merged = { ...node.data, ...patch } as GenerateVideoNodeData; |
||||
|
|
||||
|
// 重新打开节点时的读取路径应保留所选数量,而不是回落到默认 1。
|
||||
|
expect(readVideoGenerationConfig(merged, selectedModel).batchSize).toBe(4); |
||||
|
}); |
||||
|
|
||||
|
it("keeps parity with image nodes, which already persist batchSize", () => { |
||||
|
const patch = buildComposerConfigPersistPatch(imageNode(), config({ batchSize: 2 })); |
||||
|
expect((patch as Partial<NanoBananaNodeData>).batchSize).toBe(2); |
||||
|
}); |
||||
|
}); |
||||
Loading…
Reference in new issue