Files
PaperClipAI/tests/runner-e2e/native-task-reply.spec.ts
T
DottaandPaperclip 7aa94ff745 Preserve ordinary link labels and production route semantics
Restrict renamed labels to existing product chips. Reuse the company routing helper and current task URL, with browser regressions for prefixes, fragments and wrong task/company targets.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-29 23:20:06 -05:00

48 lines
3.4 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { readBoundTaskFinalReply } from "./native-task-reply.js";
const markdown = "I **couldn't retrieve** the pages. See [Connection outcome](/QA/issues/QA-123#document-outcome).";
const rendered = "I <strong>couldn't retrieve</strong> the pages. See <a data-mention-kind='issue' href='/QA/issues/QA-123#document-outcome'><svg aria-hidden='true'></svg>QA-123</a>.";
const run = { id: "final-run", companyId: "company", agentId: "agent", status: "succeeded", runtimeMode: "native",
resultJson: { presentationDecision: { commentId: "selected" } } };
const comment = { id: "selected", authorAgentId: "agent", createdByRunId: run.id, body: markdown };
for (const [name, content, passes] of [
["decorated document link and bold text", rendered, true],
["ordinary link with its source label", rendered.replace(" data-mention-kind='issue'", "").replace(">QA-123</a>", ">Connection outcome</a>"), true],
["renamed ordinary link", rendered.replace(" data-mention-kind='issue'", ""), false],
["wrong destination", rendered.replace("#document-outcome", "#document-other"), false],
["missing link", rendered.replace(/<a.*?<\/a>/, "QA-123"), false],
["extra visible text", rendered + " Extra.", false],
["hidden source text", rendered.replace("couldn't retrieve", "<span hidden>couldn't retrieve</span>"), false],
] as const) test(`reloaded task reply: ${name}`, async ({ page }) => {
await page.route("https://fixture.test/task", route => route.fulfill({ contentType: "text/html", body:
`<div data-testid='task-chat-thread'><div data-thread-anchor='selected'><div data-testid='task-chat-agent-bubble'>${content}</div></div></div>` }));
await page.goto("https://fixture.test/task");
const result = readBoundTaskFinalReply({ page, runId: run.id, agentId: "agent", deadlineAt: Date.now() + (passes ? 3000 : 300),
load: async () => ({ run, comments: [comment], events: [] }) });
if (passes) {
const receipt = await result;
expect(receipt.source).toBe("posted-comment");
expect(receipt.sourceBody).toBe(markdown);
expect(receipt.body).toBe(content.includes(">Connection outcome</a>") ? "I couldn't retrieve the pages. See Connection outcome." : "I couldn't retrieve the pages. See QA-123.");
expect(receipt.observedAfterReload).toBe(true);
} else await expect(result).rejects.toThrow();
});
for (const [sourceHref, renderedHref, passes] of [
["/issues/QA-123#document-outcome", "/QA/issues/QA-123#document-outcome", true],
["#document-outcome", "/QA/issues/QA-123#document-outcome", true],
["/issues/QA-123#document-outcome", "/OTHER/issues/QA-123#document-outcome", false],
["#document-outcome", "/QA/issues/QA-999#document-outcome", false],
] as const) test(`reloaded link ${sourceHref} to ${renderedHref}`, async ({ page }) => {
const url = "https://fixture.test/QA/issues/QA-123";
await page.route(url, route => route.fulfill({ contentType: "text/html", body:
`<div data-testid='task-chat-thread'><div data-thread-anchor='selected'><div data-testid='task-chat-agent-bubble'>Read <a href='${renderedHref}'>Outcome</a></div></div></div>` }));
await page.goto(url);
const result = readBoundTaskFinalReply({ page, runId: run.id, agentId: "agent", deadlineAt: Date.now() + (passes ? 3000 : 300),
load: async () => ({ run, comments: [{ ...comment, body: `Read [Outcome](${sourceHref})` }], events: [] }) });
if (passes) expect((await result).pageUrl).toBe(url);
else await expect(result).rejects.toThrow();
});