ai-chatbot/tests/integration/canvas-image-result-sync.test.ts

102 lines
4.1 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "node:test";
import {
commitCanvasImageResultIfMissing,
getCanvasImageResultUrlKeys,
resolveCanvasImageResultAliases,
} from "@/components/canvas/chat-panel/canvas-image-result-sync";
const preview = "https://provider.example/result.png";
const archived = "https://bucket.example/archived.png";
const other = "https://bucket.example/second.png";
const image = (src: string, sourceImageKey = src, sourceMessageId = "message-1") => ({
type: "image",
data: { src, metadata: { sourceImageKey, sourceMessageId } },
});
test("archived history replay recognizes the provider preview already on canvas", async () => {
const nodes = [image(preview)];
const aliases = await resolveCanvasImageResultAliases({
nodes, messageId: "message-1", imageUrls: [archived],
resolveAliases: async (urls) => {
assert.deepEqual(urls, [preview]);
return { [preview]: archived };
},
});
let writes = 0;
const result = commitCanvasImageResultIfMissing({ getNodes: () => nodes, url: archived, aliases, commit: () => ++writes });
assert.equal(result, undefined);
assert.equal(writes, 0);
assert.equal(nodes.length, 1);
});
test("current src and previous source identity both prevent replay", () => {
const keys = getCanvasImageResultUrlKeys([image(archived, preview)]);
assert(keys.has(preview));
assert(keys.has(archived));
});
test("simultaneous stream and history image loads commit a single node", async () => {
const nodes: ReturnType<typeof image>[] = [];
let release!: () => void;
const loading = new Promise<void>((resolve) => { release = resolve; });
const insert = async () => {
// Both paths have already observed an empty canvas before image loading.
assert.equal(nodes.length, 0);
await loading;
return commitCanvasImageResultIfMissing({
getNodes: () => nodes, url: preview, aliases: {},
commit: () => { nodes.push(image(preview)); return "inserted"; },
});
};
const stream = insert();
const history = insert();
release();
assert.deepEqual(await Promise.all([stream, history]), ["inserted", undefined]);
assert.equal(nodes.length, 1);
});
test("multiple distinct results in one message remain distinct", async () => {
const nodes = [image(preview)];
const aliases = await resolveCanvasImageResultAliases({
nodes, messageId: "message-1", imageUrls: [archived, other],
resolveAliases: async () => ({ [preview]: archived }),
});
for (const url of [archived, other]) {
commitCanvasImageResultIfMissing({ getNodes: () => nodes, url, aliases, commit: () => nodes.push(image(url)) });
}
assert.equal(nodes.length, 2);
assert.equal(nodes[1].data.src, other);
});
test("new generations display immediately without an archive lookup", async () => {
const aliases = await resolveCanvasImageResultAliases({
nodes: [image(preview, preview, "previous-message")], messageId: "message-2", imageUrls: [other],
resolveAliases: async () => { throw new Error("Must not wait for archiving"); },
});
assert.deepEqual(aliases, {});
});
test("an archive lookup failure never treats the URL change as a new result", async () => {
await assert.rejects(resolveCanvasImageResultAliases({
nodes: [image(preview)], messageId: "message-1", imageUrls: [archived],
resolveAliases: async () => { throw new Error("Temporary network failure"); },
}), /Temporary network failure/);
});
test("same-message image batches respect the archive endpoint limit", async () => {
const nodes = Array.from({ length: 205 }, (_, i) => image(`https://provider.example/${i}.png`));
const batches: number[] = [];
await resolveCanvasImageResultAliases({
nodes, messageId: "message-1", imageUrls: [archived],
resolveAliases: async (urls) => { batches.push(urls.length); return {}; },
});
assert.deepEqual(batches, [100, 100, 5]);
});
test("synchronization leaves existing manual copies untouched", () => {
const nodes = [image(archived, preview), image(archived, preview)];
commitCanvasImageResultIfMissing({ getNodes: () => nodes, url: archived, aliases: {}, commit: () => { throw new Error("Unexpected insertion"); } });
assert.equal(nodes.length, 2);
});