import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { removeCreationAttachment } from "../src/pages/create/creation-assets";
import { moduleGroupSource } from "./helpers/module-group-source";
function compactSource(source: string) {
return source.replace(/\s+/g, " ").trim();
}
function readCreateSource() {
return readFileSync(resolve(import.meta.dir, "../src/pages/create/index.tsx"), "utf8");
}
function readCreateWorkspaceSource() {
return moduleGroupSource("pages/create/creation-workspace.tsx");
}
describe("creation library button", () => {
test("keeps library selection in the reference area instead of the bottom dock", () => {
const source = readCreateWorkspaceSource();
const dockStart = source.indexOf('", dockStart);
expect(dockStart).toBeGreaterThanOrEqual(0);
expect(dockEnd).toBeGreaterThan(dockStart);
const dockSource = compactSource(source.slice(dockStart, dockEnd));
const modePickerIndex = dockSource.indexOf(" {
const source = readCreateSource();
const pickerSource = readFileSync(resolve(import.meta.dir, "../src/components/assets/asset-library-picker-modal.tsx"), "utf8");
const uploadStart = source.indexOf("const uploadLibraryAssets = async");
const uploadEnd = source.indexOf("const handleLibrarySelect", uploadStart);
expect(uploadStart).toBeGreaterThanOrEqual(0);
expect(uploadEnd).toBeGreaterThan(uploadStart);
expect(source.slice(uploadStart, uploadEnd)).not.toContain("setAttachments");
expect(source).toContain("onUpload: uploadLibraryAssets");
expect(source).not.toContain("onUpload={() => fileInputRef.current?.click()}");
expect(source).toContain("上传后保存到素材库");
expect(pickerSource).toContain("保存完成后会自动选中");
expect(source).toContain("个素材已上传到素材库并自动选中");
});
test("视频创作使用同名模型组的全部参考能力开放素材入口", () => {
const source = readCreateSource();
const workspace = readCreateWorkspaceSource();
expect(source).toContain('modelGroupReferenceLimits(config, preferredModel || selectedModel, "video")');
expect(source).toContain("reconcileCreationAttachmentLimits(attachments, mentionReferences, videoReferenceLimits)");
expect(workspace).toContain('props.mode !== "video" || props.maxReferences > 0');
expect(workspace).not.toContain('props.videoProfile.operations.includes("image_to_video")');
});
test("previews prompt reference images without removing them", () => {
const createSource = readCreateWorkspaceSource();
const canvasSource = moduleGroupSource("components/canvas/canvas-node-prompt-panel.tsx");
expect(createSource).toContain('className="creation-user-message-attachments"');
expect(createSource).toContain('setPreviewType(kind === "video" ? "video" : "image")');
expect(createSource).toContain(" onInsert(reference)}");
});
test("参考内容层叠轨道支持折叠、展开和 Reorder 排序", () => {
const source = readCreateWorkspaceSource();
const styles = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
expect(source).toContain('import { Reorder, LayoutGroup, motion, useReducedMotion } from "motion/react"');
expect(source).toContain(" {
const assets = readFileSync(resolve(import.meta.dir, "../src/pages/create/creation-assets.ts"), "utf8");
const createSource = readCreateWorkspaceSource();
expect(assets).toContain("resolveResourceUrl(asset.data.storageKey");
expect(createSource.replace(/\s+/g, " ")).toContain(" {
const attachments = [
{ id: "first", name: "首个" },
{ id: "middle", name: "中间" },
{ id: "last", name: "末尾" },
];
expect(removeCreationAttachment(attachments, "first").map((item) => item.id)).toEqual(["middle", "last"]);
expect(removeCreationAttachment(attachments, "middle").map((item) => item.id)).toEqual(["first", "last"]);
expect(removeCreationAttachment(attachments, "last").map((item) => item.id)).toEqual(["first", "middle"]);
});
test("删除按钮在指针按下阶段隔离拖拽,素材库入口职责独立", () => {
const source = compactSource(readCreateWorkspaceSource());
expect(source).toContain("onPointerDownCapture={(event) => event.stopPropagation()}");
expect(source).toContain("onRemove(item.id)");
expect(source).toContain("onClick={props.onOpenLibrary}");
expect(source).not.toContain("onClick={() => props.fileInputRef.current?.click()}");
});
});
describe("creation homepage default mode", () => {
test("opens the empty homepage on image generation instead of video", () => {
const source = readCreateSource();
expect(source).toContain("import { defaultCreationMode, modeLabels,");
expect(source).toContain("initialComposerPreferences.mode || defaultCreationMode");
expect(source).toContain("saved.mode || defaultCreationMode");
expect(source).not.toContain('mode || "video"');
});
});
describe("creation thread chrome", () => {
test("docks the conversation toolbar into the workspace top bar and keeps a compact thread composer", () => {
const workspace = readCreateWorkspaceSource();
const topBar = readFileSync(resolve(import.meta.dir, "../src/components/layout/workspace-top-bar.tsx"), "utf8");
const product = readFileSync(resolve(import.meta.dir, "../src/styles/workspace-product.css"), "utf8");
expect(workspace).toContain("useWorkspaceTopBarMount");
expect(workspace).toContain("createPortal(toolbar, mount)");
expect(topBar).toContain("WorkspaceTopBarExtensionSlot");
expect(product).toContain(".creation-chat-dock .creation-mode-tabs");
expect(product).not.toContain("creation-composer-mode-row");
});
test("parameter popovers use the user surface without a hairline stroke", () => {
const css = readFileSync(resolve(import.meta.dir, "../src/pages/create/creation-product.css"), "utf8");
expect(css).toContain(".creation-control-popover .ant-popover-inner");
expect(css).toContain("background: var(--user-surface-raised) !important");
expect(css).toContain("border: 0 !important");
expect(css).toContain("--border: transparent");
expect(css).toContain(".creation-choice-grid button.is-selected");
expect(css).toContain("background: var(--user-control-pressed) !important");
});
});