mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
64c82812a5
* feat(boards): mint pinned MCP app views * feat(ui): render pinned MCP apps on dashboards * fix(dashboard): reconcile MCP app rebase * fix(dashboard): align generated CI contracts * test(gateway): record board.widget.appView release train * fix(dashboard): revalidate pinned MCP app views
110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
// Canvas-render tests cover [embed] shortcode extraction and text stripping.
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
extractCanvasFromDetails,
|
|
extractCanvasFromText,
|
|
extractCanvasShortcodes,
|
|
} from "./canvas-render.ts";
|
|
|
|
describe("extractCanvasFromText", () => {
|
|
it("preserves a valid pinned board widget identity", () => {
|
|
expect(
|
|
extractCanvasFromText(
|
|
JSON.stringify({
|
|
kind: "canvas",
|
|
view: {
|
|
id: "cv_status",
|
|
url: "/__openclaw__/canvas/documents/cv_status/index.html",
|
|
boardWidgetName: "release-status",
|
|
},
|
|
}),
|
|
),
|
|
).toMatchObject({ viewId: "cv_status", boardWidgetName: "release-status" });
|
|
});
|
|
|
|
it("extracts safe MCP App preview metadata from tool details", () => {
|
|
expect(
|
|
extractCanvasFromDetails({
|
|
mcpAppPreview: {
|
|
kind: "canvas",
|
|
view: { id: "cv_app" },
|
|
presentation: { target: "assistant_message", sandbox: "scripts" },
|
|
mcpApp: {
|
|
viewId: "cv_app",
|
|
serverName: "demo",
|
|
toolName: "show",
|
|
uiResourceUri: "ui://demo/app",
|
|
toolCallId: "call-1",
|
|
originSessionKey: "agent:main:main",
|
|
resultMetaState: "unavailable",
|
|
},
|
|
},
|
|
}),
|
|
).toMatchObject({
|
|
viewId: "cv_app",
|
|
mcpApp: {
|
|
viewId: "cv_app",
|
|
serverName: "demo",
|
|
toolName: "show",
|
|
uiResourceUri: "ui://demo/app",
|
|
toolCallId: "call-1",
|
|
originSessionKey: "agent:main:main",
|
|
resultMetaState: "unavailable",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("keeps MCP App previews opaque while preserving model-visible results", () => {
|
|
const preview = extractCanvasFromText(
|
|
JSON.stringify({
|
|
kind: "canvas",
|
|
view: { id: "cv_app" },
|
|
presentation: { target: "assistant_message", sandbox: "scripts" },
|
|
mcpApp: { viewId: "cv_app" },
|
|
result: [{ type: "text", text: "model-visible result" }],
|
|
}),
|
|
);
|
|
|
|
expect(preview).toMatchObject({
|
|
viewId: "cv_app",
|
|
sandbox: "scripts",
|
|
mcpApp: { viewId: "cv_app" },
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("extractCanvasShortcodes", () => {
|
|
it("does not let a self-closing embed start a greedy block match", () => {
|
|
// Regression: the block regex used to greedily swallow the span from a
|
|
// self-closing "[embed ... /]" open tag up to a later stray "[/embed]",
|
|
// deleting the visible text in between (" keep me ") from channel delivery.
|
|
const input = '[embed url="https://a.com" /] keep me [/embed]';
|
|
const { text, previews } = extractCanvasShortcodes(input);
|
|
|
|
expect(previews).toHaveLength(1);
|
|
expect(previews[0]?.url).toBe("https://a.com");
|
|
// The visible text between the self-closing embed and the stray close
|
|
// marker must be preserved, not silently stripped.
|
|
expect(text).toContain("keep me");
|
|
expect(text).toBe("keep me [/embed]");
|
|
});
|
|
|
|
it("still extracts a normal block embed and strips only the shortcode span", () => {
|
|
const input = 'before [embed ref="doc1"] hi [/embed] after';
|
|
const { text, previews } = extractCanvasShortcodes(input);
|
|
|
|
expect(previews).toHaveLength(1);
|
|
expect(previews[0]?.viewId).toBe("doc1");
|
|
expect(text).toBe("before after");
|
|
});
|
|
|
|
it("still extracts a plain self-closing embed and keeps surrounding text", () => {
|
|
const input = 'see [embed url="https://b.com" /] end';
|
|
const { text, previews } = extractCanvasShortcodes(input);
|
|
|
|
expect(previews).toHaveLength(1);
|
|
expect(previews[0]?.url).toBe("https://b.com");
|
|
expect(text).toBe("see end");
|
|
});
|
|
});
|