源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { renderAgentConversationCopyHtml } from "./agentConversationCopyHtml";
|
||||
|
||||
describe("renderAgentConversationCopyHtml", () => {
|
||||
it("renders headings, paragraphs, lists and GFM tables", () => {
|
||||
const html = renderAgentConversationCopyHtml(
|
||||
[
|
||||
"# Session title",
|
||||
"",
|
||||
"Hello **world**",
|
||||
"",
|
||||
"- item one",
|
||||
"- item two",
|
||||
"",
|
||||
"| a | b |",
|
||||
"| - | - |",
|
||||
"| 1 | 2 |"
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
expect(html).toContain("<h1>Session title</h1>");
|
||||
expect(html).toContain("<strong>world</strong>");
|
||||
expect(html).toContain("<li>item one</li>");
|
||||
expect(html).toContain("<table>");
|
||||
expect(html).toContain("<td>1</td>");
|
||||
});
|
||||
|
||||
it("keeps inline data-URI images as real img sources", () => {
|
||||
const html = renderAgentConversationCopyHtml(
|
||||
""
|
||||
);
|
||||
|
||||
expect(html).toContain(
|
||||
'<img src="data:image/png;base64,QUFB" alt="shot.png"'
|
||||
);
|
||||
});
|
||||
|
||||
it("sanitizes non-image protocols and ignores raw HTML", () => {
|
||||
const html = renderAgentConversationCopyHtml(
|
||||
[
|
||||
"<script>alert(1)</script>",
|
||||
"",
|
||||
"[link](javascript:alert(1))",
|
||||
"",
|
||||
""
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
expect(html).not.toContain("<script>");
|
||||
expect(html).not.toContain("javascript:");
|
||||
expect(html).not.toContain("data:text/html");
|
||||
});
|
||||
|
||||
it("strips data:image/svg+xml even though it starts with data:image/", () => {
|
||||
const html = renderAgentConversationCopyHtml(
|
||||
""
|
||||
);
|
||||
|
||||
expect(html).not.toContain("data:image/svg+xml");
|
||||
});
|
||||
|
||||
it("keeps common raster data-URI subtypes", () => {
|
||||
for (const mime of ["image/jpeg", "image/jpg", "image/gif", "image/webp"]) {
|
||||
const html = renderAgentConversationCopyHtml(
|
||||
``
|
||||
);
|
||||
expect(html).toContain(`data:${mime};base64,QUFB`);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user