agent / ui /src /components /CommentThread.test.tsx
GraziePrego's picture
Upload folder using huggingface_hub
b152fd5 verified
// @vitest-environment jsdom
import { act } from "react";
import type { ReactNode } from "react";
import { createRoot } from "react-dom/client";
import { MemoryRouter } from "react-router-dom";
import type { Agent } from "@paperclipai/shared";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { CommentThread } from "./CommentThread";
vi.mock("./MarkdownBody", () => ({
MarkdownBody: ({ children, className }: { children: ReactNode; className?: string }) => (
<div className={className}>{children}</div>
),
}));
vi.mock("./MarkdownEditor", () => ({
MarkdownEditor: ({ value, onChange, placeholder }: {
value: string;
onChange: (value: string) => void;
placeholder?: string;
}) => (
<textarea
aria-label="Comment editor"
value={value}
placeholder={placeholder}
onChange={(event) => onChange(event.target.value)}
/>
),
}));
vi.mock("./InlineEntitySelector", () => ({
InlineEntitySelector: () => null,
}));
vi.mock("@/plugins/slots", () => ({
PluginSlotOutlet: () => null,
}));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
describe("CommentThread", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.createElement("div");
document.body.appendChild(container);
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-03-11T12:00:00.000Z"));
});
afterEach(() => {
vi.useRealTimers();
container.remove();
});
it("renders historical runs as timeline rows using the finished time", () => {
const root = createRoot(container);
const agent: Agent = {
id: "agent-1",
companyId: "company-1",
name: "CodexCoder",
urlKey: "codexcoder",
role: "engineer",
title: null,
icon: "code",
status: "active",
reportsTo: null,
capabilities: null,
adapterType: "process",
adapterConfig: {},
runtimeConfig: {},
budgetMonthlyCents: 0,
spentMonthlyCents: 0,
pauseReason: null,
pausedAt: null,
permissions: { canCreateAgents: false },
lastHeartbeatAt: null,
metadata: null,
createdAt: new Date("2026-03-11T00:00:00.000Z"),
updatedAt: new Date("2026-03-11T00:00:00.000Z"),
};
act(() => {
root.render(
<MemoryRouter>
<CommentThread
comments={[]}
linkedRuns={[{
runId: "run-12345678abcd",
status: "succeeded",
agentId: "agent-1",
createdAt: "2026-03-11T07:00:00.000Z",
startedAt: "2026-03-11T08:00:00.000Z",
finishedAt: "2026-03-11T10:00:00.000Z",
}]}
agentMap={new Map([["agent-1", agent]])}
onAdd={async () => {}}
/>
</MemoryRouter>,
);
});
const runRow = container.querySelector("#run-run-12345678abcd") as HTMLDivElement | null;
expect(runRow).not.toBeNull();
expect(runRow?.className).toContain("py-1.5");
expect(runRow?.className).toContain("items-center");
expect(runRow?.className).not.toContain("border");
expect(container.textContent).toContain("CodexCoder");
expect(container.textContent).toContain("succeeded");
expect(container.textContent).toContain("2h ago");
expect(container.textContent).not.toContain("4h ago");
const runLink = container.querySelector('a[href="/agents/agent-1/runs/run-12345678abcd"]') as HTMLAnchorElement | null;
expect(runLink?.textContent).toContain("run-1234");
expect(runLink?.className).toContain("rounded-md");
expect(runLink?.className).toContain("px-2");
act(() => {
root.unmount();
});
});
it("replaces the composer with a warning when comments are disabled", () => {
const root = createRoot(container);
act(() => {
root.render(
<MemoryRouter>
<CommentThread
comments={[]}
composerDisabledReason="Workspace is closed."
onAdd={async () => {}}
/>
</MemoryRouter>,
);
});
expect(container.textContent).toContain("Workspace is closed.");
expect(container.querySelector('textarea[aria-label="Comment editor"]')).toBeNull();
expect(container.textContent).not.toContain("Comment");
act(() => {
root.unmount();
});
});
});