56 lines
3.3 KiB
TypeScript
56 lines
3.3 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { executeArtCritique } from "../src/services/art-critique-execution";
|
|
import { defaultConfig } from "../src/stores/use-config-store";
|
|
import { createCanvasNode } from "../src/lib/canvas/canvas-project-domain";
|
|
import { CanvasNodeType } from "../src/types/canvas";
|
|
import { runArtCritiquePipeline, type ArtCritiquePipelineOptions } from "../src/lib/art-critique/pipeline";
|
|
|
|
const source = createCanvasNode(CanvasNodeType.Image, { x: 0, y: 0 }, { storageKey: "resource:original" });
|
|
const options = () => ({ nodeId: "analysis", runId: "run", source, config: defaultConfig, signal: new AbortController().signal, onTaskCreated: (_stage: string, _id: string) => {} });
|
|
|
|
test("分析阶段使用资源引用、记录后台任务并拒绝重复阶段提交", async () => {
|
|
let submitted = 0;
|
|
const created: string[] = [];
|
|
const input = options();
|
|
input.onTaskCreated = (stage, id) => created.push(`${stage}:${id}`);
|
|
await executeArtCritique(input, {
|
|
inspectImage: async () => ({ storageKey: "resource:original", encodedBytes: 30 }),
|
|
runTask: async (request) => {
|
|
submitted++;
|
|
expect(JSON.stringify(request.messages)).toContain("resource:original");
|
|
expect(request.metadata).toMatchObject({ source: "art-critique", runId: "run", nodeId: "analysis" });
|
|
request.onTaskCreated?.({ id: "task-1" } as never);
|
|
return { content: "{}", toolCalls: [] };
|
|
},
|
|
runPipeline: async (config, image, opts: ArtCritiquePipelineOptions = {}) => {
|
|
expect(image.dataUrl).toBe("resource:original");
|
|
const stage = { config, messages: [{ role: "user" as const, content: [{ type: "image_url" as const, image_url: { url: image.dataUrl } }] }], tool: { type: "function" as const, name: "review", description: "review", parameters: {} }, toolName: "review", signal: input.signal };
|
|
await opts.requestStage!(stage);
|
|
await expect(opts.requestStage!(stage)).rejects.toThrow("重复");
|
|
return {} as never;
|
|
},
|
|
});
|
|
expect(submitted).toBe(1);
|
|
expect(created).toEqual(["review:task-1"]);
|
|
});
|
|
|
|
test("准备素材期间取消不会提交后台模型任务", async () => {
|
|
const controller = new AbortController();
|
|
let submitted = false;
|
|
await expect(executeArtCritique({ ...options(), signal: controller.signal }, {
|
|
inspectImage: async () => { controller.abort(); return { storageKey: "resource:image", encodedBytes: 30 }; },
|
|
runTask: async () => { submitted = true; return { content: "", toolCalls: [] }; },
|
|
runPipeline: async () => { throw new Error("不应开始分析"); },
|
|
})).rejects.toThrow();
|
|
expect(submitted).toBe(false);
|
|
});
|
|
|
|
test("审批执行器中止不能被管线降级为已完成报告", async () => {
|
|
await expect(runArtCritiquePipeline({ ...defaultConfig, textModel: "model" }, { dataUrl: "resource:image", title: "image", sourceFingerprint: "image" }, {
|
|
requestStage: async ({ toolName }) => {
|
|
if (toolName === "analyze_art_scene") throw new DOMException("报价服务不可用", "AbortError");
|
|
return { content: "", toolCalls: [{ id: toolName, type: "function", function: { name: toolName, arguments: JSON.stringify({ candidates: [] }) } }] };
|
|
},
|
|
})).rejects.toThrow("报价服务不可用");
|
|
});
|