import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { ReactNode } from "react"; import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import { TooltipProvider } from "@kandev/ui/tooltip"; import { StateProvider } from "@/components/state-provider"; import { ToastProvider } from "@/components/toast-provider"; import { PRStatusChip, aggregateChipStatus } from "./pr-status-chip"; import { makeTestPR as makePR } from "./pr-status-chip.test-fixtures"; import type { AppState } from "@/lib/state/store"; import type { TaskPR, WorkflowAttention } from "@/lib/types/github"; const CHIP_TESTID = "pr-status-chip"; const responsiveMock = vi.hoisted(() => ({ breakpoint: "desktop" as "mobile" | "tablet" | "compactDesktop" | "desktop", isFinePointer: true, })); vi.mock("@/hooks/use-responsive-breakpoint", () => ({ useResponsiveBreakpoint: () => ({ breakpoint: responsiveMock.breakpoint, isMobile: responsiveMock.breakpoint === "mobile", isTablet: responsiveMock.breakpoint === "tablet", isDesktop: responsiveMock.breakpoint === "compactDesktop" || responsiveMock.breakpoint === "desktop", isCompactDesktop: responsiveMock.breakpoint === "compactDesktop", isFullDesktop: responsiveMock.breakpoint === "desktop", isFinePointer: responsiveMock.isFinePointer, usesDesktopWorkbench: responsiveMock.breakpoint === "compactDesktop" || responsiveMock.breakpoint === "desktop", }), })); vi.mock("@/lib/api/domains/github-api", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, getPRFeedback: vi.fn().mockResolvedValue(null), getTaskCIAutomationOptions: vi.fn().mockResolvedValue({ task_id: "task-1", auto_fix_enabled: false, auto_merge_enabled: false, auto_fix_prompt_override: null, effective_auto_fix_prompt: "Default CI fix prompt", using_default_prompt: true, updated_at: "2026-06-18T10:00:00Z", pr_states: [], pr_options: [], }), listWorkspaceTaskPRs: vi.fn().mockResolvedValue({ task_prs: {} }), }; }); vi.mock("@/lib/ws/connection", () => ({ getWebSocketClient: () => null, })); function renderWithStore(initialState: Partial, ui: ReactNode) { return render( {ui} , ); } function makeAttention( state: WorkflowAttention["state"], runs: WorkflowAttention["runs"] = [], ): WorkflowAttention { return { state, head_sha: "head-1", observed_at: "2026-09-10T10:00:00Z", stale: true, runs, }; } function makeAttentionPR(attention: WorkflowAttention): TaskPR { return makePR({ head_sha: "head-1", workflow_attention: attention }); } beforeEach(() => { responsiveMock.breakpoint = "desktop"; responsiveMock.isFinePointer = true; }); afterEach(() => { cleanup(); }); describe("workflow attention chip status", () => { it("marks current-head workflow attention as a warning", () => { expect(aggregateChipStatus([makeAttentionPR(makeAttention("approval_required"))])).toBe( "attention", ); }); }); describe("workflow attention desktop popover", () => { it("shows the workflow reason and an external workflow link", async () => { const pr = makeAttentionPR( makeAttention("approval_required", [ { run_id: 7, run_attempt: 1, workflow_id: 9, name: "Run tests", url: "https://github.com/acme/demo/actions/runs/7", reason: "approval_required", }, ]), ); renderWithStore( { taskPRs: { byTaskId: { "task-1": [pr] } } }, , ); fireEvent.mouseEnter(screen.getByTestId(CHIP_TESTID)); const notice = await screen.findByTestId("pr-workflow-attention"); expect(notice.textContent).toContain("Awaiting maintainer approval"); expect(notice.textContent).toContain("Run tests"); expect(screen.getByTestId("pr-workflow-attention-link").getAttribute("href")).toBe( "https://github.com/acme/demo/actions/runs/7", ); expect(screen.getByTestId("pr-workflow-attention-link").className).toContain("min-h-11"); expect(notice.textContent).toContain("Last known status"); }); it("shows unavailable workflow evidence without claiming approval", async () => { renderWithStore( { taskPRs: { byTaskId: { "task-1": [makeAttentionPR(makeAttention("unknown"))] } } }, , ); fireEvent.mouseEnter(screen.getByTestId(CHIP_TESTID)); const notice = await screen.findByTestId("pr-workflow-attention"); expect(notice.textContent).toContain("Workflow status unavailable"); expect(notice.textContent).not.toContain("Awaiting maintainer approval"); }); });