test comment deletion cleanup regressions
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
// @vitest-environment jsdom
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
import { act, createRef, forwardRef, useImperativeHandle, useState } from "react";
|
import { act, createRef, forwardRef, useImperativeHandle, useState } from "react";
|
||||||
|
import { flushSync } from "react-dom";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
@@ -33,6 +34,14 @@ import type {
|
|||||||
IssueChatTranscriptEntry,
|
IssueChatTranscriptEntry,
|
||||||
} from "../lib/issue-chat-messages";
|
} from "../lib/issue-chat-messages";
|
||||||
|
|
||||||
|
function flushAct<T>(callback: () => T): T {
|
||||||
|
let result: T | undefined;
|
||||||
|
flushSync(() => {
|
||||||
|
result = callback();
|
||||||
|
});
|
||||||
|
return result as T;
|
||||||
|
}
|
||||||
|
|
||||||
function hasSmoothScrollBehavior(arg: unknown) {
|
function hasSmoothScrollBehavior(arg: unknown) {
|
||||||
return typeof arg === "object"
|
return typeof arg === "object"
|
||||||
&& arg !== null
|
&& arg !== null
|
||||||
@@ -1327,7 +1336,7 @@ describe("IssueChatThread", () => {
|
|||||||
it("renders deleted comments as tombstones without the original body", () => {
|
it("renders deleted comments as tombstones without the original body", () => {
|
||||||
const root = createRoot(container);
|
const root = createRoot(container);
|
||||||
|
|
||||||
act(() => {
|
flushAct(() => {
|
||||||
root.render(
|
root.render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<IssueChatThread
|
<IssueChatThread
|
||||||
@@ -1360,12 +1369,12 @@ describe("IssueChatThread", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.textContent).toContain("Comment deleted");
|
expect(container.textContent).toContain("You deleted this comment");
|
||||||
expect(container.textContent).not.toContain("Sensitive deleted body");
|
expect(container.textContent).not.toContain("Sensitive deleted body");
|
||||||
expect(container.querySelector("button[aria-label='Delete comment']")).toBeNull();
|
expect(container.querySelector("button[aria-label='Delete comment']")).toBeNull();
|
||||||
expect(container.querySelector("button[aria-label='Copy message']")).toBeNull();
|
expect(container.querySelector("button[aria-label='Copy message']")).toBeNull();
|
||||||
|
|
||||||
act(() => {
|
flushAct(() => {
|
||||||
root.unmount();
|
root.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1374,7 +1383,7 @@ describe("IssueChatThread", () => {
|
|||||||
const root = createRoot(container);
|
const root = createRoot(container);
|
||||||
const replaceStateSpy = vi.spyOn(window.history, "replaceState").mockImplementation(() => {});
|
const replaceStateSpy = vi.spyOn(window.history, "replaceState").mockImplementation(() => {});
|
||||||
|
|
||||||
act(() => {
|
flushAct(() => {
|
||||||
root.render(
|
root.render(
|
||||||
<MemoryRouter initialEntries={["/issues/PAP-1#comment-comment-deleted"]}>
|
<MemoryRouter initialEntries={["/issues/PAP-1#comment-comment-deleted"]}>
|
||||||
<IssueChatThread
|
<IssueChatThread
|
||||||
@@ -1409,7 +1418,7 @@ describe("IssueChatThread", () => {
|
|||||||
expect(replaceStateSpy).toHaveBeenCalledWith(null, "", "/issues/PAP-1");
|
expect(replaceStateSpy).toHaveBeenCalledWith(null, "", "/issues/PAP-1");
|
||||||
|
|
||||||
replaceStateSpy.mockRestore();
|
replaceStateSpy.mockRestore();
|
||||||
act(() => {
|
flushAct(() => {
|
||||||
root.unmount();
|
root.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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", () => {
|
it("prefers derived agent attribution when a board-authored comment is proven to come from a run", () => {
|
||||||
const agentMap = new Map<string, Agent>([["agent-1", createAgent("agent-1", "Claude")]]);
|
const agentMap = new Map<string, Agent>([["agent-1", createAgent("agent-1", "Claude")]]);
|
||||||
const messages = buildIssueChatMessages({
|
const messages = buildIssueChatMessages({
|
||||||
|
|||||||
Reference in New Issue
Block a user