181 lines
5.1 KiB
TypeScript
181 lines
5.1 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { act } from "react";
|
|
import type { ComponentProps } from "react";
|
|
import { createRoot } from "react-dom/client";
|
|
import type { Issue } from "@paperclipai/shared";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { FailedRunInboxRow, InboxIssueMetaLeading } from "./Inbox";
|
|
|
|
vi.mock("@/lib/router", () => ({
|
|
Link: ({ children, className, ...props }: ComponentProps<"a">) => (
|
|
<a className={className} {...props}>{children}</a>
|
|
),
|
|
useLocation: () => ({ pathname: "/", search: "", hash: "" }),
|
|
useNavigate: () => () => {},
|
|
}));
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
|
|
|
|
function createIssue(overrides: Partial<Issue> = {}): Issue {
|
|
return {
|
|
id: "issue-1",
|
|
identifier: "PAP-904",
|
|
companyId: "company-1",
|
|
projectId: null,
|
|
projectWorkspaceId: null,
|
|
goalId: null,
|
|
parentId: null,
|
|
title: "Inbox item",
|
|
description: null,
|
|
status: "todo",
|
|
priority: "medium",
|
|
assigneeAgentId: null,
|
|
assigneeUserId: null,
|
|
createdByAgentId: null,
|
|
createdByUserId: null,
|
|
issueNumber: 904,
|
|
requestDepth: 0,
|
|
billingCode: null,
|
|
assigneeAdapterOverrides: null,
|
|
executionWorkspaceId: null,
|
|
executionWorkspacePreference: null,
|
|
executionWorkspaceSettings: null,
|
|
checkoutRunId: null,
|
|
executionRunId: null,
|
|
executionAgentNameKey: null,
|
|
executionLockedAt: null,
|
|
startedAt: null,
|
|
completedAt: null,
|
|
cancelledAt: null,
|
|
hiddenAt: null,
|
|
createdAt: new Date("2026-03-11T00:00:00.000Z"),
|
|
updatedAt: new Date("2026-03-11T00:00:00.000Z"),
|
|
labels: [],
|
|
labelIds: [],
|
|
myLastTouchAt: null,
|
|
lastExternalCommentAt: null,
|
|
isUnreadForMe: false,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("FailedRunInboxRow", () => {
|
|
let container: HTMLDivElement;
|
|
|
|
beforeEach(() => {
|
|
container = document.createElement("div");
|
|
document.body.appendChild(container);
|
|
});
|
|
|
|
afterEach(() => {
|
|
container.remove();
|
|
});
|
|
|
|
it("suppresses accent hover styling when selected", () => {
|
|
const root = createRoot(container);
|
|
const run = {
|
|
id: "run-1",
|
|
companyId: "company-1",
|
|
agentId: "agent-1",
|
|
invocationSource: "assignment",
|
|
triggerDetail: null,
|
|
status: "failed",
|
|
error: "boom",
|
|
wakeupRequestId: null,
|
|
exitCode: null,
|
|
signal: null,
|
|
usageJson: null,
|
|
resultJson: null,
|
|
sessionIdBefore: null,
|
|
sessionIdAfter: null,
|
|
logStore: null,
|
|
logRef: null,
|
|
logBytes: null,
|
|
logSha256: null,
|
|
logCompressed: false,
|
|
errorCode: null,
|
|
externalRunId: null,
|
|
processPid: null,
|
|
processStartedAt: null,
|
|
retryOfRunId: null,
|
|
processLossRetryCount: 0,
|
|
stdoutExcerpt: null,
|
|
stderrExcerpt: null,
|
|
contextSnapshot: null,
|
|
startedAt: new Date("2026-03-11T00:00:00.000Z"),
|
|
finishedAt: null,
|
|
createdAt: new Date("2026-03-11T00:00:00.000Z"),
|
|
updatedAt: new Date("2026-03-11T00:00:00.000Z"),
|
|
} as const;
|
|
|
|
act(() => {
|
|
root.render(
|
|
<FailedRunInboxRow
|
|
run={run}
|
|
issueById={new Map()}
|
|
agentName="Agent"
|
|
issueLinkState={null}
|
|
onDismiss={() => {}}
|
|
onRetry={() => {}}
|
|
isRetrying={false}
|
|
selected
|
|
/>,
|
|
);
|
|
});
|
|
|
|
const link = container.querySelector("a");
|
|
expect(link).not.toBeNull();
|
|
expect(link?.className).toContain("hover:bg-transparent");
|
|
expect(link?.className).not.toContain("hover:bg-accent/50");
|
|
|
|
act(() => {
|
|
root.unmount();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("InboxIssueMetaLeading", () => {
|
|
let container: HTMLDivElement;
|
|
|
|
beforeEach(() => {
|
|
container = document.createElement("div");
|
|
document.body.appendChild(container);
|
|
});
|
|
|
|
afterEach(() => {
|
|
container.remove();
|
|
});
|
|
|
|
it("neutralizes selected status and live accents", () => {
|
|
const root = createRoot(container);
|
|
|
|
act(() => {
|
|
root.render(<InboxIssueMetaLeading issue={createIssue()} selected isLive />);
|
|
});
|
|
|
|
const statusIcon = container.querySelector('span[class*="border-muted-foreground"]');
|
|
const liveBadge = container.querySelector('span[class*="px-1.5"][class*="bg-muted"]');
|
|
const liveBadgeLabel = Array.from(container.querySelectorAll("span")).find(
|
|
(node) => node.textContent === "Live" && node.className.includes("text-"),
|
|
);
|
|
const liveDot = container.querySelector('span[class*="bg-muted-foreground/70"]');
|
|
const pulseRing = container.querySelector('span[class*="animate-pulse"]');
|
|
|
|
expect(statusIcon).not.toBeNull();
|
|
expect(statusIcon?.className).toContain("!border-muted-foreground");
|
|
expect(statusIcon?.className).toContain("!text-muted-foreground");
|
|
expect(liveBadge).not.toBeNull();
|
|
expect(liveBadge?.className).toContain("bg-muted");
|
|
expect(liveBadgeLabel).not.toBeNull();
|
|
expect(liveBadgeLabel?.className).toContain("text-muted-foreground");
|
|
expect(liveBadgeLabel?.className).not.toContain("text-blue-600");
|
|
expect(liveDot).not.toBeNull();
|
|
expect(pulseRing).toBeNull();
|
|
|
|
act(() => {
|
|
root.unmount();
|
|
});
|
|
});
|
|
});
|