From d87b14ff4faba003129557dc2fb28f87e6462872 Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 3 Jun 2026 17:39:42 +0000 Subject: [PATCH] test comment deletion cleanup regressions --- ui/src/components/IssueChatThread.test.tsx | 19 +++++++++++----- ui/src/lib/issue-chat-messages.test.ts | 26 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/ui/src/components/IssueChatThread.test.tsx b/ui/src/components/IssueChatThread.test.tsx index 6e1172e5..c4af6461 100644 --- a/ui/src/components/IssueChatThread.test.tsx +++ b/ui/src/components/IssueChatThread.test.tsx @@ -1,6 +1,7 @@ // @vitest-environment jsdom import { act, createRef, forwardRef, useImperativeHandle, useState } from "react"; +import { flushSync } from "react-dom"; import type { ReactNode } from "react"; import { createRoot } from "react-dom/client"; import { MemoryRouter } from "react-router-dom"; @@ -33,6 +34,14 @@ import type { IssueChatTranscriptEntry, } from "../lib/issue-chat-messages"; +function flushAct(callback: () => T): T { + let result: T | undefined; + flushSync(() => { + result = callback(); + }); + return result as T; +} + function hasSmoothScrollBehavior(arg: unknown) { return typeof arg === "object" && arg !== null @@ -1327,7 +1336,7 @@ describe("IssueChatThread", () => { it("renders deleted comments as tombstones without the original body", () => { const root = createRoot(container); - act(() => { + flushAct(() => { root.render( { ); }); - expect(container.textContent).toContain("Comment deleted"); + expect(container.textContent).toContain("You deleted this comment"); expect(container.textContent).not.toContain("Sensitive deleted body"); expect(container.querySelector("button[aria-label='Delete comment']")).toBeNull(); expect(container.querySelector("button[aria-label='Copy message']")).toBeNull(); - act(() => { + flushAct(() => { root.unmount(); }); }); @@ -1374,7 +1383,7 @@ describe("IssueChatThread", () => { const root = createRoot(container); const replaceStateSpy = vi.spyOn(window.history, "replaceState").mockImplementation(() => {}); - act(() => { + flushAct(() => { root.render( { expect(replaceStateSpy).toHaveBeenCalledWith(null, "", "/issues/PAP-1"); replaceStateSpy.mockRestore(); - act(() => { + flushAct(() => { root.unmount(); }); }); diff --git a/ui/src/lib/issue-chat-messages.test.ts b/ui/src/lib/issue-chat-messages.test.ts index 4aa62a71..0382db75 100644 --- a/ui/src/lib/issue-chat-messages.test.ts +++ b/ui/src/lib/issue-chat-messages.test.ts @@ -324,6 +324,32 @@ describe("buildIssueChatMessages", () => { }); }); + it("redacts deleted comment bodies while preserving tombstone metadata", () => { + const messages = buildIssueChatMessages({ + comments: [ + createComment({ + body: "Sensitive deleted body", + deletedAt: new Date("2026-04-06T12:05:00.000Z"), + deletedByType: "user", + deletedByUserId: "user-1", + }), + ], + timelineEvents: [], + linkedRuns: [], + liveRuns: [], + currentUserId: "user-1", + userLabelMap: new Map([["user-1", "Dotta"]]), + }); + + expect(messages[0]?.content).toEqual([{ type: "text", text: "" }]); + expect(messages[0]?.metadata.custom).toMatchObject({ + deletedAt: "2026-04-06T12:05:00.000Z", + deletedByType: "user", + deletedByUserId: "user-1", + }); + expect(JSON.stringify(messages[0])).not.toContain("Sensitive deleted body"); + }); + it("prefers derived agent attribution when a board-authored comment is proven to come from a run", () => { const agentMap = new Map([["agent-1", createAgent("agent-1", "Claude")]]); const messages = buildIssueChatMessages({