返回 DeepSeek-Reasonix
chat-file-reference.mjs
根目录 / desktop / frontend / bench / chat-file-reference.mjs
1 // Real-browser click verification for answer file references and the SVG code
2 // block. Proves the DOM behavior the tsx suites can only simulate: a verified
3 // path becomes a clickable reference that commits a preview command into the
4 // running navigation owner, an unverified path stays plain text, and the SVG
5 // block actually renders a picture from the sanitized source with a working
6 // preview/source toggle.
7 import assert from "node:assert/strict";
8 import { createServer } from "vite";
9 import path from "node:path";
10 import { fileURLToPath } from "node:url";
11
12 const frontendDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
13 process.env.PLAYWRIGHT_BROWSERS_PATH = !process.env.PLAYWRIGHT_BROWSERS_PATH || process.env.PLAYWRIGHT_BROWSERS_PATH === ".pw-browsers"
14 ? path.join(frontendDir, ".pw-browsers")
15 : process.env.PLAYWRIGHT_BROWSERS_PATH;
16 const { chromium } = await import("playwright");
17
18 const server = await createServer({
19 root: frontendDir,
20 server: { host: "127.0.0.1", port: 0, hmr: false },
21 logLevel: "error",
22 plugins: [{
23 name: "chat-file-reference-fixture",
24 configureServer(dev) {
25 dev.middlewares.use(async (req, res, next) => {
26 if (req.url !== "/chat-file-reference-fixture") return next();
27 res.setHeader("Content-Type", "text/html");
28 res.end(await dev.transformIndexHtml(req.url, '<html><head><link rel="icon" href="data:,"></head><body><div id="root"></div><script type="module" src="/bench/chat-file-reference-fixture.tsx"></script></body></html>'));
29 });
30 },
31 }],
32 });
33 await server.listen();
34
35 let browser;
36 try {
37 const address = server.httpServer.address();
38 browser = await chromium.launch({ headless: true, executablePath: process.env.CHROME_EXECUTABLE });
39 const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
40 const errors = [];
41 page.on("pageerror", error => { errors.push(error.message); console.error(error.message); });
42 page.on("console", message => { if (message.type() === "error") { errors.push(message.text()); console.error(message.text()); } });
43 await page.goto(`http://127.0.0.1:${address.port}/chat-file-reference-fixture`);
44
45 // The verified reference is clickable and names the host's display path.
46 const reference = page.locator("button.md-code--presented-file");
47 await reference.waitFor({ timeout: 10_000 });
48 assert.equal(await reference.getAttribute("title"), "out/diagram.svg", "reference names the verified display path");
49 assert.match(await page.locator(".md").first().innerText(), /\/repo\/out\/missing\.svg/, "the answer text is preserved");
50 assert.equal(await page.locator("button.md-code--presented-file").count(), 1, "an unverified path stays text");
51 console.log("PASS verified reference is the only clickable path");
52
53 await reference.click();
54 await page.waitForFunction(() => document.getElementById("request")?.textContent !== "", null, { timeout: 10_000 });
55 const request = JSON.parse(await page.locator("#request").textContent());
56 assert.equal(request.source, "reference", "the click enters the navigation lifecycle as a reference");
57 assert.equal(request.action, "preview", "the default click previews");
58 assert.equal(request.path, "out/diagram.svg", "the preview targets the verified display path");
59 console.log("PASS click commits a reference preview command");
60
61 // The SVG fence renders a picture built from the sanitized bytes.
62 const image = page.locator(".md-svg__preview img");
63 await image.waitFor({ timeout: 10_000 });
64 const source = await image.getAttribute("src");
65 assert.match(source, /^(blob:|data:image\/svg\+xml)/, "the preview loads sanitized bytes as an image source");
66 const box = await image.boundingBox();
67 assert(box && box.width > 0 && box.height > 0, "the picture is laid out with real geometry");
68 // A malformed document still yields a sized <img> element, so prove the
69 // browser decoded the picture instead of showing a broken-image placeholder.
70 const decoded = await page.evaluate(async () => {
71 const img = document.querySelector(".md-svg__preview img");
72 if (!(img instanceof HTMLImageElement)) return null;
73 try { await img.decode(); } catch { return "decode-failed"; }
74 return img.naturalWidth > 0 && img.naturalHeight > 0 ? "decoded" : "empty";
75 });
76 assert.equal(decoded, "decoded", "the browser decoded the sanitized SVG as an image");
77 assert(box.height <= 32 * 16 + 1, "the preview stays inside its height ceiling");
78 assert.equal(await page.locator(".md-svg__note").count(), 0, "a previewable SVG shows no fallback note");
79 console.log(`PASS svg fence renders a ${Math.round(box.width)}x${Math.round(box.height)} picture`);
80
81 // Preview / source toggle, and copy keeps the original text.
82 await page.getByRole("button", { name: /source|源码|原始碼/i }).click();
83 await page.locator(".md-svg .code-block").waitFor({ timeout: 10_000 });
84 const code = await page.locator(".md-svg .code-block").innerText();
85 assert.match(code, /linearGradient/, "the source view shows the original SVG");
86 assert.equal(await page.locator(".md-svg__preview img").count(), 0, "source mode replaces the picture");
87 await page.getByRole("button", { name: /preview|预览|預覽/i }).click();
88 await page.locator(".md-svg__preview img").waitFor({ timeout: 10_000 });
89 console.log("PASS preview and source toggle both ways");
90
91 assert.deepEqual(errors, [], "no page errors");
92 console.log("PASS no page errors");
93 } finally {
94 await browser?.close();
95 await server.close();
96 }
97
97 lines Plain Text