Spaces:
Paused
Paused
| // @vitest-environment jsdom | |
| import { act } from "react"; | |
| import { createRoot } from "react-dom/client"; | |
| import type { Issue } from "@paperclipai/shared"; | |
| import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; | |
| import { IssueRow } from "./IssueRow"; | |
| vi.mock("@/lib/router", () => ({ | |
| Link: ({ children, className, ...props }: React.ComponentProps<"a">) => ( | |
| <a className={className} {...props}>{children}</a> | |
| ), | |
| })); | |
| // 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-1", | |
| 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: 1, | |
| 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("IssueRow", () => { | |
| let container: HTMLDivElement; | |
| beforeEach(() => { | |
| container = document.createElement("div"); | |
| document.body.appendChild(container); | |
| }); | |
| afterEach(() => { | |
| container.remove(); | |
| }); | |
| it("suppresses accent hover styling when the row is selected", () => { | |
| const root = createRoot(container); | |
| const issue = createIssue(); | |
| act(() => { | |
| root.render(<IssueRow issue={issue} selected />); | |
| }); | |
| const link = container.querySelector("[data-inbox-issue-link]") as HTMLAnchorElement | null; | |
| expect(link).not.toBeNull(); | |
| expect(link?.className).toContain("hover:bg-transparent"); | |
| expect(link?.className).not.toContain("hover:bg-accent/50"); | |
| act(() => { | |
| root.unmount(); | |
| }); | |
| }); | |
| it("neutralizes selected status and unread dot accents", () => { | |
| const root = createRoot(container); | |
| act(() => { | |
| root.render(<IssueRow issue={createIssue()} selected unreadState="visible" />); | |
| }); | |
| const markReadButton = container.querySelector('button[aria-label="Mark as read"]'); | |
| const unreadDot = markReadButton?.querySelector("span"); | |
| const statusIcon = container.querySelector('span[class*="border-muted-foreground"]'); | |
| expect(markReadButton).not.toBeNull(); | |
| expect(markReadButton?.className).toContain("hover:bg-muted/80"); | |
| expect(markReadButton?.className).not.toContain("hover:bg-blue-500/20"); | |
| expect(unreadDot).not.toBeNull(); | |
| expect(unreadDot?.className).toContain("bg-muted-foreground/70"); | |
| expect(unreadDot?.className).not.toContain("bg-blue-600"); | |
| expect(statusIcon).not.toBeNull(); | |
| expect(statusIcon?.className).toContain("!border-muted-foreground"); | |
| expect(statusIcon?.className).toContain("!text-muted-foreground"); | |
| act(() => { | |
| root.unmount(); | |
| }); | |
| }); | |
| it("preserves the issue detail breadcrumb source and href in the link target", () => { | |
| const root = createRoot(container); | |
| const issue = createIssue(); | |
| const state = { | |
| issueDetailBreadcrumb: { label: "Inbox", href: "/PAP/inbox/mine" }, | |
| issueDetailSource: "inbox", | |
| }; | |
| act(() => { | |
| root.render(<IssueRow issue={issue} issueLinkState={state} />); | |
| }); | |
| const link = container.querySelector("[data-inbox-issue-link]") as HTMLAnchorElement | null; | |
| expect(link).not.toBeNull(); | |
| expect(link?.getAttribute("to") ?? link?.getAttribute("href")).toContain( | |
| "/issues/PAP-1?from=inbox&fromHref=%2FPAP%2Finbox%2Fmine", | |
| ); | |
| act(() => { | |
| root.unmount(); | |
| }); | |
| }); | |
| }); | |