// @vitest-environment jsdom import type { ReactNode } from "react"; import { flushSync } from "react-dom"; import { createRoot, type Root } from "react-dom/client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { ThemeProvider } from "../context/ThemeContext"; import { MarkdownBody } from "./MarkdownBody"; vi.mock("@/lib/router", () => ({ Link: ({ children, to, ...props }: { children: ReactNode; to: string } & React.ComponentProps<"a">) => ( {children} ), })); vi.mock("../api/issues", () => ({ issuesApi: { get: vi.fn(), }, })); describe("MarkdownBody code block wrapping", () => { let container: HTMLDivElement; let root: Root; let queryClient: QueryClient; beforeEach(() => { container = document.createElement("div"); document.body.appendChild(container); root = createRoot(container); queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); }); afterEach(() => { flushSync(() => root.unmount()); queryClient.clear(); container.remove(); }); it("toggles fenced code blocks between horizontal scroll and wrapped lines", () => { flushSync(() => { root.render( {"```text\nlong line that can wrap when requested\n```"} , ); }); const pre = container.querySelector("pre"); const actions = container.querySelector( ".paperclip-markdown-codeblock-actions", ); const wrapButton = container.querySelector( ".paperclip-markdown-codeblock-wrap", ); expect(pre).not.toBeNull(); expect(actions).not.toBeNull(); expect(wrapButton).not.toBeNull(); expect(actions?.getAttribute("data-active")).toBeNull(); expect(wrapButton?.getAttribute("aria-pressed")).toBe("false"); expect(wrapButton?.getAttribute("aria-label")).toBe("Wrap lines"); expect(pre?.style.overflowX).toBe("auto"); expect(pre?.style.whiteSpace).toBe(""); flushSync(() => { wrapButton?.dispatchEvent(new MouseEvent("click", { bubbles: true })); }); expect(wrapButton?.getAttribute("aria-pressed")).toBe("true"); expect(wrapButton?.getAttribute("aria-label")).toBe("Unwrap lines"); expect(actions?.getAttribute("data-active")).toBe("true"); expect(pre?.style.overflowX).toBe("hidden"); expect(pre?.style.whiteSpace).toBe("pre-wrap"); expect(pre?.style.overflowWrap).toBe("anywhere"); flushSync(() => { wrapButton?.dispatchEvent(new MouseEvent("click", { bubbles: true })); }); expect(wrapButton?.getAttribute("aria-pressed")).toBe("false"); expect(wrapButton?.getAttribute("aria-label")).toBe("Wrap lines"); expect(actions?.getAttribute("data-active")).toBeNull(); expect(pre?.style.overflowX).toBe("auto"); expect(pre?.style.whiteSpace).toBe(""); }); });