import { renderHook } from "@testing-library/react"
import { describe, expect, it, vi } from "vitest"
const page = (cells: string) =>
`${cells}`
const box = (id: string) =>
``
// The first edit's result is loaded (the ref has it); the chartXML state
// has not caught up yet
const BEFORE_FIRST_EDIT = page(box("a"))
const AFTER_FIRST_EDIT = page(box("a") + box("b"))
const mocks = vi.hoisted(() => ({
loadDiagram: vi.fn((_xml: string, ..._rest: unknown[]) => null),
// The canvas for a test that needs another one
canvas: null as string | null,
}))
vi.mock("@/contexts/diagram-context", () => ({
useDiagram: () => ({
chartXML: mocks.canvas ?? BEFORE_FIRST_EDIT,
chartXMLRef: { current: mocks.canvas ?? AFTER_FIRST_EDIT },
loadDiagram: mocks.loadDiagram,
}),
}))
import { useDiagramStreaming } from "@/components/chat/use-diagram-streaming"
describe("the streaming preview of a second edit", () => {
it("starts from the first edit's result", () => {
const editDiagramOriginalXmlRef = { current: new Map() }
const messages = [
{
id: "m1",
role: "assistant",
parts: [
{
type: "tool-edit_diagram",
toolCallId: "edit-2",
state: "input-streaming",
input: {
operations: [
{
operation: "add",
cell_id: "c",
new_xml: box("c"),
},
],
},
},
],
},
] as any
renderHook(() =>
useDiagramStreaming({
messages,
processedToolCallsRef: { current: new Set() },
editDiagramOriginalXmlRef,
loadedMessageIdsRef: { current: new Set() },
}),
)
expect(editDiagramOriginalXmlRef.current.get("edit-2")).toBe(
AFTER_FIRST_EDIT,
)
})
})
describe("the streaming preview of display_diagram", () => {
it("expands the named styles and adds the defaults to the cells so far", () => {
mocks.loadDiagram.mockClear()
// A complete definition and cell, then a cell still being written
const xml = `
useDiagramStreaming({
messages,
processedToolCallsRef: { current: new Set() },
editDiagramOriginalXmlRef: { current: new Map() },
loadedMessageIdsRef: { current: new Set() },
}),
)
expect(mocks.loadDiagram).toHaveBeenCalledTimes(1)
const loaded = mocks.loadDiagram.mock.calls[0][0]
expect(loaded).toContain(
'style="rounded=1;fillColor=#dae8fc;strokeColor=#6c8ebf;whiteSpace=wrap;html=1;"',
)
expect(loaded).not.toContain("mxStyle")
expect(loaded).not.toContain('id="b"')
})
})
describe("the streaming preview of edit_diagram", () => {
it("adds the default styles to the cell being added, like the final edit", () => {
mocks.loadDiagram.mockClear()
const messages = [
{
id: "m1",
role: "assistant",
parts: [
{
type: "tool-edit_diagram",
toolCallId: "edit-3",
state: "input-streaming",
input: {
operations: [
{
operation: "add",
cell_id: "c",
new_xml: box("c").replace(
'vertex="1"',
'style="rounded=1;" vertex="1"',
),
},
],
},
},
],
},
] as any
renderHook(() =>
useDiagramStreaming({
messages,
processedToolCallsRef: { current: new Set() },
editDiagramOriginalXmlRef: { current: new Map() },
loadedMessageIdsRef: { current: new Set() },
}),
)
expect(mocks.loadDiagram).toHaveBeenCalledTimes(1)
expect(mocks.loadDiagram.mock.calls[0][0]).toContain(
'style="rounded=1;whiteSpace=wrap;html=1;"',
)
})
})
describe("the streaming preview on the model's page", () => {
const box2 = (id: string, parent = "1") =>
``
// Page A has an edge "g"; on page B, "g" is a shape on layer "L"
const twoPages = `${box2("s")}${box2("t")}${box2("g", "L")}`
const cellOn = (xml: string, pageId: string, id: string) =>
new DOMParser()
.parseFromString(xml, "text/xml")
.querySelector(`diagram[id="${pageId}"] mxCell[id="${id}"]`)
const stream = (part: object) =>
renderHook(() =>
useDiagramStreaming({
messages: [
{ id: "m1", role: "assistant", parts: [part] },
] as any,
processedToolCallsRef: { current: new Set() },
editDiagramOriginalXmlRef: { current: new Map() },
loadedMessageIdsRef: { current: new Set() },
turnPageIdRef: { current: "pb" },
}),
)
it("applies an edit to that page, with its layer and its edges", () => {
mocks.loadDiagram.mockClear()
mocks.canvas = twoPages
try {
stream({
type: "tool-edit_diagram",
toolCallId: "edit-p",
state: "input-streaming",
input: {
operations: [
{
operation: "add",
cell_id: "c",
new_xml:
'',
},
{
operation: "add",
cell_id: "d",
new_xml:
'',
},
],
},
})
const loaded = mocks.loadDiagram.mock.calls.at(-1)?.[0] as string
expect(cellOn(loaded, "pb", "c")?.getAttribute("parent")).toBe("L")
expect(cellOn(loaded, "pb", "d")?.getAttribute("style")).toContain(
"whiteSpace=wrap",
)
expect(cellOn(loaded, "pa", "c")).toBeNull()
} finally {
mocks.canvas = null
}
})
it("draws display_diagram's cells on that page", () => {
mocks.loadDiagram.mockClear()
mocks.canvas = twoPages
try {
stream({
type: "tool-display_diagram",
toolCallId: "draw-p",
state: "input-streaming",
input: { xml: box2("n") },
})
const loaded = mocks.loadDiagram.mock.calls.at(-1)?.[0] as string
expect(cellOn(loaded, "pb", "n")).not.toBeNull()
expect(cellOn(loaded, "pb", "g")).toBeNull()
expect(cellOn(loaded, "pa", "g")).not.toBeNull()
} finally {
mocks.canvas = null
}
})
})