import { expect, test } from "vitest"; import { appendHtmlPreviewBaseHref, appendHtmlPreviewScrollRestoration, buildWriteFileDraftContent, createHtmlPreviewScrollKey, getArtifactViewState, } from "@/core/artifacts/preview"; const ARTIFACT_PATH = "/artifact-fixtures/report.html"; const UNSUPPORTED_ARTIFACT_PATH = "/artifact-fixtures/data.csv"; test("allows in-progress write artifacts to render a throttled preview", () => { expect( getArtifactViewState({ filepath: `write-file:${ARTIFACT_PATH}?message_id=ai-1&tool_call_id=call-1`, isSupportPreview: true, }), ).toEqual({ canPreview: true, initialViewMode: "preview", }); }); test("allows preview for a write artifact once the tool call has a result", () => { expect( getArtifactViewState({ filepath: `write-file:${ARTIFACT_PATH}?message_id=ai-1&tool_call_id=call-1`, isSupportPreview: true, toolResult: "OK", }), ).toEqual({ canPreview: true, initialViewMode: "preview", }); }); test("keeps failed write artifacts in code view", () => { expect( getArtifactViewState({ filepath: `write-file:${ARTIFACT_PATH}?message_id=ai-1&tool_call_id=call-1`, isSupportPreview: true, toolResult: "Error: Failed to write file", }), ).toEqual({ canPreview: false, initialViewMode: "code", }); }); test("keeps completed artifacts on their existing preview defaults", () => { expect( getArtifactViewState({ filepath: ARTIFACT_PATH, isSupportPreview: true, }), ).toEqual({ canPreview: true, initialViewMode: "preview", }); }); test("keeps unsupported artifacts in code view", () => { expect( getArtifactViewState({ filepath: UNSUPPORTED_ARTIFACT_PATH, isSupportPreview: false, }), ).toEqual({ canPreview: false, initialViewMode: "code", }); }); test("builds a draft write-file artifact from successful writes plus the selected in-progress append", () => { const filepath = `write-file:${ARTIFACT_PATH}?message_id=ai-2&tool_call_id=call-2`; expect( buildWriteFileDraftContent({ filepath, messages: [ { type: "ai", id: "ai-1", tool_calls: [ { id: "call-1", name: "write_file", args: { path: ARTIFACT_PATH, content: "", }, }, ], }, { type: "tool", id: "tool-1", name: "write_file", tool_call_id: "call-1", content: "OK", }, { type: "ai", id: "ai-2", tool_calls: [ { id: "call-2", name: "write_file", args: { append: true, path: ARTIFACT_PATH, content: "

追加内容

", }, }, ], }, ], }), ).toBe("

追加内容

"); }); test("does not include failed writes in a draft artifact", () => { const filepath = `write-file:${ARTIFACT_PATH}?message_id=ai-3&tool_call_id=call-3`; expect( buildWriteFileDraftContent({ filepath, messages: [ { type: "ai", id: "ai-1", tool_calls: [ { id: "call-1", name: "write_file", args: { path: ARTIFACT_PATH, content: "", }, }, ], }, { type: "tool", id: "tool-1", name: "write_file", tool_call_id: "call-1", content: "OK", }, { type: "ai", id: "ai-2", tool_calls: [ { id: "call-2", name: "write_file", args: { append: true, path: ARTIFACT_PATH, content: "

失败内容

", }, }, ], }, { type: "tool", id: "tool-2", name: "write_file", tool_call_id: "call-2", content: "Error: write failed", }, { type: "ai", id: "ai-3", tool_calls: [ { id: "call-3", name: "write_file", args: { append: true, path: ARTIFACT_PATH, content: "", }, }, ], }, ], }), ).toBe(""); }); test("returns undefined when the selected append failed so the caller can fall back", () => { const filepath = `write-file:${ARTIFACT_PATH}?message_id=ai-2&tool_call_id=call-2`; expect( buildWriteFileDraftContent({ filepath, messages: [ { type: "ai", id: "ai-1", tool_calls: [ { id: "call-1", name: "write_file", args: { path: ARTIFACT_PATH, content: "", }, }, ], }, { type: "tool", id: "tool-1", name: "write_file", tool_call_id: "call-1", content: "OK", }, { type: "ai", id: "ai-2", tool_calls: [ { id: "call-2", name: "write_file", args: { append: true, path: ARTIFACT_PATH, content: "

失败的追加内容

", }, }, ], }, { type: "tool", id: "tool-2", name: "write_file", tool_call_id: "call-2", content: "Error: write failed", }, ], }), ).toBeUndefined(); }); test("injects scroll restoration at the start of the HTML head", () => { const html = '
content
'; expect(appendHtmlPreviewScrollRestoration(html, ARTIFACT_PATH)).toContain( ".html'; const html = appendHtmlPreviewScrollRestoration( "x", artifactPath, ); expect(html).toContain(createHtmlPreviewScrollKey(artifactPath)); expect(html).toContain("window.parent.postMessage"); expect(html).not.toContain("window.name"); expect(html).not.toContain("/artifact-fixtures/a"); expect(html).not.toContain("