// @vitest-environment jsdom
import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { afterEach, describe, expect, it, vi } from "vitest";
import { ApiError } from "@/api/client";
import { TaskDocumentPanel } from "./TaskDocumentPanel";
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
const mocks = vi.hoisted(() => ({ get: vi.fn(), revision: vi.fn() }));
vi.mock("@/api/issues", () => ({ issuesApi: { getDocument: mocks.get, getDocumentRevision: mocks.revision } }));
vi.mock("@/lib/router", () => ({ useLocation: () => ({ hash: "#document-copy&revision=old&interaction=review" }) }));
vi.mock("@/components/IssueDocumentAnnotations", () => ({
DocumentAnnotationsCountChip: () => Annotations,
IssueDocumentAnnotations: ({ children, historicalPreview }: { children: React.ReactNode; historicalPreview: boolean }) =>
{children}
,
}));
vi.mock("@/components/MarkdownBody", () => ({ MarkdownBody: ({ children }: { children: React.ReactNode }) => {children}
}));
let root: Root | undefined;
let container: HTMLDivElement;
afterEach(async () => { if (root) await act(async () => root!.unmount()); container?.remove(); root = undefined; vi.clearAllMocks(); });
async function render(issueId = "task") {
container = document.createElement("div"); document.body.appendChild(container); root = createRoot(container);
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
await act(async () => { root!.render(); });
await act(async () => { await new Promise((resolve) => setTimeout(resolve, 0)); });
}
describe("exact reviewed revision panel", () => {
it("renders the pinned body read-only even when the current document has advanced", async () => {
mocks.get.mockResolvedValue({ id: "doc", key: "copy", title: "New copy", body: "LATEST BODY", latestRevisionId: "new", latestRevisionNumber: 4, updatedAt: new Date() });
mocks.revision.mockResolvedValue({ id: "old", key: "copy", title: "Reviewed copy", body: "REVIEWED BODY", format: "markdown", revisionNumber: 2, createdAt: new Date() });
await render();
expect(container.textContent).toContain("REVIEWED BODY");
expect(container.textContent).not.toContain("LATEST BODY");
expect(container.querySelector('[data-historical="true"]')).not.toBeNull();
expect(mocks.revision).toHaveBeenCalledWith("task", "copy", "old");
});
it("does not silently substitute latest when the reviewed revision is missing", async () => {
mocks.get.mockResolvedValue({ id: "doc", key: "copy", title: "New copy", body: "LATEST BODY", latestRevisionId: "new", latestRevisionNumber: 4, updatedAt: new Date() });
mocks.revision.mockRejectedValue(new ApiError("Not found", 404, {}));
await render();
expect(container.textContent).toContain("Reviewed revision unavailable");
expect(container.textContent).not.toContain("LATEST BODY");
});
it("reads the actual document owner and fails closed when that task is inaccessible", async () => {
mocks.get.mockRejectedValue(new ApiError("Forbidden", 403, {}));
await render("task-b");
expect(mocks.get).toHaveBeenCalledWith("task-b", "copy");
expect(mocks.revision).not.toHaveBeenCalled();
expect(container.textContent).toContain("Couldn't load the document");
expect(container.querySelector("article")).toBeNull();
});
});