Files
formbricks/apps/web/modules/ui/components/code-block/index.test.tsx
2025-05-08 08:16:24 +00:00

122 lines
4.2 KiB
TypeScript

import { cleanup, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Prism from "prismjs";
import toast from "react-hot-toast";
import { afterEach, describe, expect, test, vi } from "vitest";
import { CodeBlock } from "./index";
// Import toast
// Mock Prism.js
vi.mock("prismjs", () => ({
default: {
highlightAll: vi.fn(),
},
}));
// Mock react-hot-toast
vi.mock("react-hot-toast", async (importOriginal) => {
const actual = await importOriginal<typeof import("react-hot-toast")>();
return {
...actual,
default: {
success: vi.fn(), // Mock toast.success directly here
},
};
});
describe("CodeBlock", () => {
afterEach(() => {
cleanup();
vi.resetAllMocks(); // Reset mocks to avoid interference between tests
});
test("renders children and applies language class", () => {
const codeSnippet = "const greeting = 'Hello, world!';";
const language = "javascript";
render(<CodeBlock language={language}>{codeSnippet}</CodeBlock>);
const codeElement = screen.getByText(codeSnippet);
expect(codeElement).toBeInTheDocument();
expect(codeElement).toHaveClass(`language-${language}`);
});
test("calls Prism.highlightAll on render and when children change", () => {
const codeSnippet = "const greeting = 'Hello, world!';";
const language = "javascript";
const { rerender } = render(<CodeBlock language={language}>{codeSnippet}</CodeBlock>);
expect(Prism.highlightAll).toHaveBeenCalledTimes(1);
const newCodeSnippet = "const newGreeting = 'Hello, Vitest!';";
rerender(<CodeBlock language={language}>{newCodeSnippet}</CodeBlock>);
expect(Prism.highlightAll).toHaveBeenCalledTimes(2);
});
test("copies code to clipboard when copy icon is clicked", async () => {
const user = userEvent.setup();
const codeSnippet = "console.log('Copy me!');";
const language = "typescript";
render(<CodeBlock language={language}>{codeSnippet}</CodeBlock>);
// Store the original clipboard
const originalClipboard = navigator.clipboard;
// Mock clipboard API for this test
Object.defineProperty(navigator, "clipboard", {
value: {
writeText: vi.fn().mockResolvedValue(undefined),
},
writable: true,
configurable: true, // Allow redefining for cleanup
});
// Find the copy icon by its role and accessible name (if any) or by a more robust selector
// If the icon itself doesn't have a role or accessible name, find its container
const copyButtonContainer = screen.getByTestId("copy-icon"); // Assuming the button or its container has an accessible name like "Copy to clipboard"
expect(copyButtonContainer).toBeInTheDocument();
await user.click(copyButtonContainer);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(codeSnippet);
// Use the imported toast for assertion
expect(vi.mocked(toast.success)).toHaveBeenCalledWith("common.copied_to_clipboard");
// Restore the original clipboard
Object.defineProperty(navigator, "clipboard", {
value: originalClipboard,
writable: true,
});
});
test("does not show copy to clipboard button when showCopyToClipboard is false", () => {
const codeSnippet = "const secret = 'Do not copy!';";
const language = "text";
render(
<CodeBlock language={language} showCopyToClipboard={false}>
{codeSnippet}
</CodeBlock>
);
// Check if the copy button is not present
const copyButton = screen.queryByTestId("copy-icon");
expect(copyButton).not.toBeInTheDocument();
});
test("applies custom editor and code classes", () => {
const codeSnippet = "<p>Custom classes</p>";
const language = "html";
const customEditorClass = "custom-editor";
const customCodeClass = "custom-code";
render(
<CodeBlock language={language} customEditorClass={customEditorClass} customCodeClass={customCodeClass}>
{codeSnippet}
</CodeBlock>
);
const preElement = screen.getByText(codeSnippet).closest("pre");
expect(preElement).toHaveClass(customEditorClass);
const codeElement = screen.getByText(codeSnippet);
expect(codeElement).toHaveClass(`language-${language}`);
expect(codeElement).toHaveClass(customCodeClass);
});
});