|
|
@ -68,6 +68,27 @@ beforeEach(() => { |
|
|
vi.clearAllMocks(); |
|
|
vi.clearAllMocks(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
function mockPopiTaskSuccess() { |
|
|
|
|
|
mockFetch.mockImplementation(async (url: string) => { |
|
|
|
|
|
if (url === "/api/generate/task/create") { |
|
|
|
|
|
return { |
|
|
|
|
|
ok: true, |
|
|
|
|
|
json: () => Promise.resolve({ success: true, taskId: "task-1" }), |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
if (url.startsWith("/api/generate/task/poll")) { |
|
|
|
|
|
return { |
|
|
|
|
|
ok: true, |
|
|
|
|
|
json: () => Promise.resolve({ |
|
|
|
|
|
status: "completed", |
|
|
|
|
|
result: { success: true, video: "data:video/mp4;base64,output" }, |
|
|
|
|
|
}), |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
throw new Error(`Unexpected fetch URL: ${url}`); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
async function withProviderMode<T>(mode: "multi" | "popi", run: () => Promise<T>): Promise<T> { |
|
|
async function withProviderMode<T>(mode: "multi" | "popi", run: () => Promise<T>): Promise<T> { |
|
|
const originalNextPublicMode = process.env.NEXT_PUBLIC_PROVIDER_MODE; |
|
|
const originalNextPublicMode = process.env.NEXT_PUBLIC_PROVIDER_MODE; |
|
|
const originalProviderMode = process.env.PROVIDER_MODE; |
|
|
const originalProviderMode = process.env.PROVIDER_MODE; |
|
|
@ -394,10 +415,7 @@ describe("executeGenerateVideo", () => { |
|
|
selectedModel: { provider: "popiserver", modelId: "44", displayName: "Seedance" }, |
|
|
selectedModel: { provider: "popiserver", modelId: "44", displayName: "Seedance" }, |
|
|
parameters: { subType: 202 }, |
|
|
parameters: { subType: 202 }, |
|
|
}); |
|
|
}); |
|
|
mockFetch.mockResolvedValueOnce({ |
|
|
mockPopiTaskSuccess(); |
|
|
ok: true, |
|
|
|
|
|
json: () => Promise.resolve({ success: true, video: "data:video/mp4;base64,output" }), |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const ctx = makeCtx(node, { |
|
|
const ctx = makeCtx(node, { |
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
@ -424,10 +442,7 @@ describe("executeGenerateVideo", () => { |
|
|
selectedModel: { provider: "popiserver", modelId: "44", displayName: "Seedance" }, |
|
|
selectedModel: { provider: "popiserver", modelId: "44", displayName: "Seedance" }, |
|
|
parameters: { subType: 204 }, |
|
|
parameters: { subType: 204 }, |
|
|
}); |
|
|
}); |
|
|
mockFetch.mockResolvedValueOnce({ |
|
|
mockPopiTaskSuccess(); |
|
|
ok: true, |
|
|
|
|
|
json: () => Promise.resolve({ success: true, video: "data:video/mp4;base64,output" }), |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const ctx = makeCtx(node, { |
|
|
const ctx = makeCtx(node, { |
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
@ -445,15 +460,68 @@ describe("executeGenerateVideo", () => { |
|
|
expect(body.parameters.subType).toBe(204); |
|
|
expect(body.parameters.subType).toBe(204); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it("normalizes image-to-video subtype to all-purpose reference when video input exists", async () => { |
|
|
|
|
|
const node = makeNode({ |
|
|
|
|
|
selectedModel: { |
|
|
|
|
|
provider: "popiserver", |
|
|
|
|
|
modelId: "44", |
|
|
|
|
|
displayName: "Seedance", |
|
|
|
|
|
metadata: { isSupportVideos: true }, |
|
|
|
|
|
}, |
|
|
|
|
|
parameters: { subType: 202 }, |
|
|
|
|
|
}); |
|
|
|
|
|
mockPopiTaskSuccess(); |
|
|
|
|
|
|
|
|
|
|
|
const ctx = makeCtx(node, { |
|
|
|
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
|
|
|
images: ["https://static.popi.art/1.png"], |
|
|
|
|
|
videos: ["https://static.popi.art/input.mp4"], |
|
|
|
|
|
audio: [], |
|
|
|
|
|
text: "video prompt", |
|
|
|
|
|
dynamicInputs: {}, |
|
|
|
|
|
easeCurve: null, |
|
|
|
|
|
}), |
|
|
|
|
|
}); |
|
|
|
|
|
await executeGenerateVideo(ctx); |
|
|
|
|
|
|
|
|
|
|
|
const body = JSON.parse(mockFetch.mock.calls[0][1].body); |
|
|
|
|
|
expect(body.parameters.subType).toBe(203); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it("normalizes first-last-frame subtype to all-purpose reference when audio input exists", async () => { |
|
|
|
|
|
const node = makeNode({ |
|
|
|
|
|
selectedModel: { |
|
|
|
|
|
provider: "popiserver", |
|
|
|
|
|
modelId: "44", |
|
|
|
|
|
displayName: "Seedance", |
|
|
|
|
|
metadata: { isSupportAudios: true }, |
|
|
|
|
|
}, |
|
|
|
|
|
parameters: { subType: 204 }, |
|
|
|
|
|
}); |
|
|
|
|
|
mockPopiTaskSuccess(); |
|
|
|
|
|
|
|
|
|
|
|
const ctx = makeCtx(node, { |
|
|
|
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
|
|
|
images: ["https://static.popi.art/first.png", "https://static.popi.art/last.png"], |
|
|
|
|
|
videos: [], |
|
|
|
|
|
audio: ["https://static.popi.art/input.mp3"], |
|
|
|
|
|
text: "video prompt", |
|
|
|
|
|
dynamicInputs: {}, |
|
|
|
|
|
easeCurve: null, |
|
|
|
|
|
}), |
|
|
|
|
|
}); |
|
|
|
|
|
await executeGenerateVideo(ctx); |
|
|
|
|
|
|
|
|
|
|
|
const body = JSON.parse(mockFetch.mock.calls[0][1].body); |
|
|
|
|
|
expect(body.parameters.subType).toBe(203); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
it("defaults PopiServer video subtype to image-to-video for exactly one image", async () => { |
|
|
it("defaults PopiServer video subtype to image-to-video for exactly one image", async () => { |
|
|
const node = makeNode({ |
|
|
const node = makeNode({ |
|
|
selectedModel: { provider: "popiserver", modelId: "44", displayName: "Seedance" }, |
|
|
selectedModel: { provider: "popiserver", modelId: "44", displayName: "Seedance" }, |
|
|
parameters: {}, |
|
|
parameters: {}, |
|
|
}); |
|
|
}); |
|
|
mockFetch.mockResolvedValueOnce({ |
|
|
mockPopiTaskSuccess(); |
|
|
ok: true, |
|
|
|
|
|
json: () => Promise.resolve({ success: true, video: "data:video/mp4;base64,output" }), |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const ctx = makeCtx(node, { |
|
|
const ctx = makeCtx(node, { |
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
getConnectedInputs: vi.fn().mockReturnValue({ |
|
|
|