fix(web): chat links open in a new tab and long URLs/CJK wrap cleanly (#27)
Co-authored-by: Alice <alice@prismshadow.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -86,10 +86,25 @@ test("chat + tool approval + stats/cost/copy + traces + files", async ({ page })
|
||||
// Final assistant answer (turn 2 from mock).
|
||||
await expect(page.getByText("Command finished; the result looks as expected.")).toBeVisible();
|
||||
|
||||
// Chat links always open in a new tab and never navigate the SPA away — including bare URLs
|
||||
// that remark-gfm autolinks (the mock reply carries one inside a CJK sentence).
|
||||
const replyLink = page.locator(".md-body a", { hasText: "example.com" }).first();
|
||||
await expect(replyLink).toBeVisible();
|
||||
await expect(replyLink).toHaveAttribute("href", /^https:\/\/example\.com\//);
|
||||
await expect(replyLink).toHaveAttribute("target", "_blank");
|
||||
await expect(replyLink).toHaveAttribute("rel", "noreferrer");
|
||||
// Wide Markdown tables scroll inside the message body instead of pushing the page wide.
|
||||
const replyTable = page.locator(".md-body table").first();
|
||||
await expect(replyTable).toBeVisible();
|
||||
expect(await replyTable.evaluate((el) => getComputedStyle(el).overflowX)).toBe("auto");
|
||||
|
||||
// Regression: after entering a session and rendering messages, the page must not overflow
|
||||
// horizontally (previously, with the Files dock panel closed, the sr-only upload input was
|
||||
// anchored to the initial containing block, bypassing the panel's overflow-hidden and
|
||||
// stretching the document wide enough to create a horizontal scrollbar).
|
||||
// stretching the document wide enough to create a horizontal scrollbar). The turn-2 reply
|
||||
// above deliberately contains a ~170-char bare URL in CJK prose and a table with a 118-char
|
||||
// unbreakable token — this assertion also proves the URL wraps and the table scrolls inside
|
||||
// the message column instead of blowing out the page.
|
||||
const docWidth = await page.evaluate(() => ({
|
||||
scrollWidth: document.documentElement.scrollWidth,
|
||||
clientWidth: document.documentElement.clientWidth,
|
||||
|
||||
@@ -185,10 +185,26 @@ const server = http.createServer((req, res) => {
|
||||
}
|
||||
|
||||
if (hasToolResult) {
|
||||
// Turn 2: final answer text.
|
||||
// Turn 2: final answer text. The first sentence is asserted verbatim across several specs —
|
||||
// keep it byte-identical and in its own paragraph. The rest is a rendering fixture for
|
||||
// chat.spec: a ~170-char bare URL inside a CJK sentence (must autolink, open in a new tab,
|
||||
// and wrap instead of widening the page) plus a Markdown table with an unbreakable
|
||||
// 118-char plain token (must scroll inside the message body, not push the page wide).
|
||||
block(res, 0, { type: "text", text: "" }, [
|
||||
{ type: "text_delta", text: "Command finished; " },
|
||||
{ type: "text_delta", text: "the result looks as expected." },
|
||||
{ type: "text_delta", text: "the result looks as expected.\n\n" },
|
||||
{ type: "text_delta", text: "长链接折行验证:完整报告地址是 " },
|
||||
{
|
||||
type: "text_delta",
|
||||
text: "https://example.com/penguin-harness/reports/2026-07/agent-session-0123456789abcdef0123456789abcdef/artifacts/deep-verification-run-with-a-very-long-descriptive-file-name-v3.html",
|
||||
},
|
||||
{ type: "text_delta", text: " ,请在浏览器中打开查看。\n\n" },
|
||||
{ type: "text_delta", text: "| 指标 | 标识 | 说明 |\n| --- | --- | --- |\n" },
|
||||
{
|
||||
type: "text_delta",
|
||||
text: "| 会话 | agent-session-0123456789abcdef0123456789abcdef-0123456789abcdef0123456789abcdef-final | 长标识验证表格横向滚动 |\n",
|
||||
},
|
||||
{ type: "text_delta", text: "| 结果 | completed | 全部通过 |\n" },
|
||||
]);
|
||||
messageStop(res, "end_turn", 20);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user