Files
NianAIGC/tests/create-studio-paste.test.ts
2026-09-30 13:22:53 +08:00

62 lines
3.5 KiB
TypeScript

import { readFile } from "node:fs/promises";
import { describe, expect, it } from "vitest";
const createStudioUrl = new URL("../components/create-studio.tsx", import.meta.url);
async function pasteFlowSource() {
const source = await readFile(createStudioUrl, "utf8");
const start = source.indexOf("function handleImagePaste(");
const end = source.indexOf("async function uploadTemplatePreview(", start);
expect(start).toBeGreaterThanOrEqual(0);
expect(end).toBeGreaterThan(start);
return { source, flow: source.slice(start, end) };
}
describe("create studio image paste wiring", () => {
it("handles paste in both the prompt and workspace, leaving text paste to the browser", async () => {
const { source, flow } = await pasteFlowSource();
expect(source).toContain("onPaste={handleImagePaste}");
expect(source).toContain("onPasteImage={handleImagePaste}");
expect(flow.indexOf("if (!files.length && !imageURL) return;")).toBeLessThan(flow.indexOf("event.preventDefault()"));
expect(flow).toContain("clipboardImageFiles(event.clipboardData)");
});
it("requires confirmation before downloading an entire URL and keeps canceled links as native text paste", async () => {
const { flow } = await pasteFlowSource();
expect(flow).toContain("files.length ? null : clipboardImageURL(event.clipboardData)");
const confirmation = flow.indexOf("if (imageURL && !window.confirm(");
expect(confirmation).toBeGreaterThanOrEqual(0);
expect(confirmation).toBeLessThan(flow.indexOf("event.preventDefault()"));
expect(flow).toContain('fetch("/api/assets/import-image"');
expect(flow).toContain('headers: { "Content-Type": "application/json" }');
expect(flow).toContain("receiveMaterialAssets(() => importImageURL(imageURL), options, 1)");
expect(flow).toContain("receiveMaterialAssets(() => uploadAssetFiles(selectedFiles), options, allFiles.length)");
expect(flow).toContain("new URL(imageURL).hostname");
expect(flow).toContain('asset.kind !== "image"');
expect(flow).toContain('options.importedURL && options.seedreamSourceMode === "single"');
});
it("blocks concurrent uploads and discards a stale result after a mode or target switch", async () => {
const { flow } = await pasteFlowSource();
expect(flow).toContain("if (uploadingRef.current || busy)");
expect(flow).toContain("uploadingRef.current = true");
expect(flow).toContain("uploadingRef.current = false");
expect(flow).toContain("options.paste.contextKey !== pasteContextRef.current");
expect(flow.indexOf("options.paste.contextKey !== pasteContextRef.current"))
.toBeLessThan(flow.indexOf("setMaterials(next)"));
});
it("routes special modes through existing source limits and adds references only for basic image or video", async () => {
const { flow } = await pasteFlowSource();
expect(flow).toContain('imageCreationMode === "interactive" ? "append" : "single"');
expect(flow).toContain("isSeedreamLayerInputFile(files[0])");
expect(flow).toContain("if (selectedSeedreamSource && !window.confirm(");
expect(flow).toContain("options.maxFiles = 1");
expect(flow).toContain("options.replaceAll = true");
expect(flow).toContain("options.maxFiles = remaining");
expect(flow).toContain("insertReferences: !specializedImageMode");
expect(flow).toContain('const labels = addedMaterials.map((material) => material.label || "");');
expect(flow).toContain("insertClipboardImageReferences(items[pasted.mode], labels, selection)");
});
});