// @vitest-environment jsdom import { act as reactAct, type ComponentProps, type ReactNode } from "react"; import { flushSync } from "react-dom"; import { createRoot, type Root } from "react-dom/client"; import { afterEach, describe, expect, it, vi } from "vitest"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { Agent } from "@paperclipai/shared"; import { ApiError } from "../api/client"; import { IssueThreadInteractionCard } from "./IssueThreadInteractionCard"; import { ThemeProvider } from "../context/ThemeContext"; import { TooltipProvider } from "./ui/tooltip"; import { pendingAskUserQuestionsInteraction, pendingAskUserQuestionsWithFreeTextOption, commentExpiredAskUserQuestionsInteraction, commentExpiredRequestConfirmationInteraction, declinedToolActionInteraction, disabledDeclineReasonRequestConfirmationInteraction, executedToolActionInteraction, expiredToolActionInteraction, failedRequestConfirmationInteraction, failedToolActionInteraction, pendingRequestConfirmationInteraction, pendingRequestCheckboxConfirmationInteraction, pendingToolActionDestructiveInteraction, pendingToolActionWriteInteraction, issueThreadInteractionFixtureMeta, pendingSecretProposalInteraction, pendingConnectionAuthorizationInteraction, resolvedConnectionAuthorizationInteraction, executedSecretProposalInteraction, failedSecretProposalInteraction, rejectedSecretProposalInteraction, expiredSecretProposalInteraction, planApprovalResumeFailedRequestConfirmationInteraction, pendingRequestItemVerdictsInteraction, pendingSuggestedTasksInteraction, runningToolActionInteraction, completeRequestItemVerdictsInteraction, supersededRequestItemVerdictsInteraction, staleTargetRequestConfirmationInteraction, rejectedSuggestedTasksInteraction, agentAddressedRequestConfirmationInteraction, agentResolvedRequestConfirmationInteraction, withdrawnRequestConfirmationInteraction, issueClosedRequestConfirmationInteraction, notCreatorRequestConfirmationInteraction, humanOnlyRequestConfirmationInteraction, companyCappedRequestConfirmationInteraction, legacyRestrictedRequestConfirmationInteraction, pendingConnectionIntentInteraction, retryConnectionIntentInteraction, connectedConnectionIntentInteraction, } from "../fixtures/issueThreadInteractionFixtures"; let root: Root | null = null; let container: HTMLDivElement | null = null; const connectionIntentsApiMocks = vi.hoisted(() => ({ setupOptions: vi.fn(), complete: vi.fn(), decline: vi.fn(), })); const routerMocks = vi.hoisted(() => ({ searchParams: new URLSearchParams(), readSearchParams: vi.fn(), setSearchParams: vi.fn(), navigate: vi.fn(), setBreadcrumbs: vi.fn(), pushToast: vi.fn(), })); (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; async function act(callback: () => void | Promise) { if (typeof reactAct === "function") { await reactAct(callback); return; } let result: void | Promise = undefined; flushSync(() => { result = callback(); }); await result; await new Promise((resolve) => setTimeout(resolve, 0)); } vi.mock("@/lib/router", () => ({ useParams: () => ({}), useSearchParams: () => { routerMocks.readSearchParams(); return [routerMocks.searchParams, routerMocks.setSearchParams]; }, useNavigate: () => routerMocks.navigate, Link: ({ to, children, className }: { to: string; children: ReactNode; className?: string }) => ( {children} ), })); vi.mock("@/context/CompanyContext", async (importOriginal) => ({ ...await importOriginal(), useCompany: () => ({ selectedCompanyId: issueThreadInteractionFixtureMeta.companyId, selectedCompany: null }), })); vi.mock("@/context/BreadcrumbContext", async (importOriginal) => ({ ...await importOriginal(), useBreadcrumbs: () => ({ setBreadcrumbs: routerMocks.setBreadcrumbs }), })); vi.mock("@/context/ToastContext", async (importOriginal) => ({ ...await importOriginal(), useToast: () => ({ pushToast: routerMocks.pushToast }), })); vi.mock("@/api/connection-intents", () => ({ connectionIntentsApi: connectionIntentsApiMocks })); vi.mock("./task-chat/TaskChatRichInput", () => ({ TaskChatRichInput: ({ value, onChange }: { value: string; onChange: (value: string) => void }) => (