// @vitest-environment jsdom import { act } from "react"; import { createRoot } from "react-dom/client"; import type { Issue } from "@paperclipai/shared"; import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from "@tanstack/react-query"; import { afterEach, describe, expect, it, vi } from "vitest"; import { issuesApi } from "@/api/issues"; import { queryKeys } from "@/lib/queryKeys"; import { getIssueDetailQueryOptions } from "./issueDetailCache"; vi.mock("@/api/issues", () => ({ issuesApi: { get: vi.fn(), }, })); // eslint-disable-next-line @typescript-eslint/no-explicit-any (globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; function makeIssue(overrides: Partial = {}): Issue { const now = new Date("2026-04-13T20:00:00.000Z"); return { id: "issue-1", companyId: "company-1", projectId: null, projectWorkspaceId: null, goalId: null, parentId: null, title: "Issue title", description: null, status: "todo", priority: "medium", assigneeAgentId: null, assigneeUserId: null, checkoutRunId: null, executionRunId: null, executionAgentNameKey: null, executionLockedAt: null, createdByAgentId: null, createdByUserId: null, issueNumber: 1442, identifier: "PAP-1442", requestDepth: 0, billingCode: null, assigneeAdapterOverrides: null, executionWorkspaceId: null, executionWorkspacePreference: null, executionWorkspaceSettings: null, startedAt: null, completedAt: null, cancelledAt: null, hiddenAt: null, createdAt: now, updatedAt: now, ...overrides, workMode: overrides.workMode ?? "standard", }; } function IssueDetailQueryHarness({ issueRef, placeholderIssue, }: { issueRef: string; placeholderIssue?: Pick | null; }) { const queryClient = useQueryClient(); const query = useQuery({ ...getIssueDetailQueryOptions(queryClient, issueRef, { placeholderIssue }), }); return
{query.data?.description ?? "EMPTY"}
; } async function flush() { // Multiple act cycles to allow React Query to process the async queryFn for (let i = 0; i < 5; i++) { await act(async () => { await new Promise((r) => setTimeout(r, 0)); }); } } describe("getIssueDetailQueryOptions", () => { afterEach(() => { vi.clearAllMocks(); }); it("treats cached issue data as placeholder and still fetches full detail", async () => { const container = document.createElement("div"); document.body.appendChild(container); const root = createRoot(container); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); const partialIssue = makeIssue({ description: null }); const fullIssue = makeIssue({ description: "GitHub Security Advisory body" }); queryClient.setQueryData(queryKeys.issues.detail("issue-1"), partialIssue); queryClient.setQueryData(queryKeys.issues.detail("PAP-1442"), partialIssue); vi.mocked(issuesApi.get).mockResolvedValue(fullIssue); await act(async () => { root.render( , ); }); await flush(); expect(issuesApi.get).toHaveBeenCalledWith("PAP-1442"); expect(container.textContent).toContain("GitHub Security Advisory body"); await act(async () => { root.unmount(); }); queryClient.clear(); container.remove(); }); });