100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { expect, test } from "bun:test"
|
|
import { renderToStaticMarkup } from "react-dom/server"
|
|
import type { DynamicToolUIPart } from "ai"
|
|
|
|
import { Tool } from "../src/components/ui/tool"
|
|
|
|
test("renders compact MCP attribution in a failed chat tool row", () => {
|
|
const toolPart: DynamicToolUIPart = {
|
|
type: "dynamic-tool",
|
|
toolName: "openwork-cloud_execute_capability",
|
|
toolCallId: "call-1",
|
|
state: "output-error",
|
|
input: {},
|
|
errorText: JSON.stringify({
|
|
error: "connection_failed",
|
|
diagnostic: { code: "MCP_HTTP_504", httpStatus: 504 },
|
|
}),
|
|
}
|
|
|
|
const html = renderToStaticMarkup(<Tool toolPart={toolPart} />)
|
|
|
|
expect(html).toContain("Remote MCP · HTTP 504")
|
|
expect(html).toContain("Error attribution: Remote MCP · HTTP 504. Confirmed.")
|
|
expect(html).not.toContain(">failed<")
|
|
})
|
|
|
|
test("renders an inline reconnect button when Cloud capability discovery finds expired credentials", () => {
|
|
const toolPart: DynamicToolUIPart = {
|
|
type: "dynamic-tool",
|
|
toolName: "openwork-cloud_search_capabilities",
|
|
toolCallId: "call-reconnect",
|
|
state: "output-available",
|
|
input: {},
|
|
output: JSON.stringify({
|
|
matches: [{
|
|
kind: "connection_status",
|
|
connectionStatus: {
|
|
version: 1,
|
|
kind: "connection_action",
|
|
source: "openwork-cloud",
|
|
connectionId: "emc_knowledge",
|
|
connectionName: "Knowledge Hub",
|
|
authType: "oauth",
|
|
credentialMode: "per_member",
|
|
state: "reauth_required",
|
|
actor: "member",
|
|
action: {
|
|
type: "reconnect",
|
|
surface: "openwork_your_connections",
|
|
retry: "search_capabilities",
|
|
},
|
|
},
|
|
}],
|
|
}),
|
|
}
|
|
|
|
const html = renderToStaticMarkup(
|
|
<Tool toolPart={toolPart} onReconnect={async () => "connected"} />,
|
|
)
|
|
|
|
expect(html).toContain("Reconnect required")
|
|
expect(html).toContain('aria-label="Reconnect Knowledge Hub"')
|
|
expect(html).toContain("Reconnect</button>")
|
|
expect(html).toContain("bg-amber-3/60")
|
|
expect(html).toContain('data-testid="chat-mcp-reconnect-action"')
|
|
})
|
|
|
|
test("renders a copy action inside the expanded tool result", () => {
|
|
const toolPart: DynamicToolUIPart = {
|
|
type: "dynamic-tool",
|
|
toolName: "openwork-cloud_search_capabilities",
|
|
toolCallId: "call-copy",
|
|
state: "output-available",
|
|
input: { query: "Notion pages" },
|
|
output: { matches: [{ name: "searchPages" }] },
|
|
}
|
|
|
|
const html = renderToStaticMarkup(<Tool toolPart={toolPart} defaultOpen />)
|
|
const contentIndex = html.indexOf('data-slot="collapsible-content"')
|
|
const copyActionIndex = html.indexOf('data-testid="tool-result-copy-action"')
|
|
|
|
expect(contentIndex).toBeGreaterThan(-1)
|
|
expect(copyActionIndex).toBeGreaterThan(contentIndex)
|
|
expect(html).toContain('aria-label="Copy tool result"')
|
|
})
|
|
|
|
test("does not render a copy action before a tool has a result", () => {
|
|
const toolPart: DynamicToolUIPart = {
|
|
type: "dynamic-tool",
|
|
toolName: "openwork-cloud_search_capabilities",
|
|
toolCallId: "call-running",
|
|
state: "input-available",
|
|
input: { query: "Notion pages" },
|
|
}
|
|
|
|
const html = renderToStaticMarkup(<Tool toolPart={toolPart} />)
|
|
|
|
expect(html).not.toContain('data-testid="tool-result-copy-action"')
|
|
})
|