orcs-design-system
Version:
TeamForm's Design System, aka: ORCS
342 lines (339 loc) • 11.3 kB
JavaScript
import React from "react";
import { act } from "react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import CodeBlock from "./index";
import SystemThemeProvider from "../../SystemThemeProvider";
import { jsx as _jsx } from "react/jsx-runtime";
const renderWithTheme = (ui, options) => render(/*#__PURE__*/_jsx(SystemThemeProvider, {
children: ui
}), options);
// Mock clipboard API
const mockWriteText = jest.fn();
Object.assign(navigator, {
clipboard: {
writeText: mockWriteText
}
});
describe("CodeBlock", () => {
beforeEach(() => {
mockWriteText.mockClear();
});
describe("Basic rendering", () => {
it("renders code content", () => {
const code = "const hello = 'world';";
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: code
}));
expect(screen.getByText(/const hello/)).toBeInTheDocument();
});
it("renders with JSON language by default for JSON content", () => {
const jsonCode = JSON.stringify({
test: "data"
}, null, 2);
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "json",
children: jsonCode
}));
expect(screen.getByText("json")).toBeInTheDocument();
});
it("handles string children correctly", () => {
const code = "function test() { return true; }";
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: code
}));
expect(container.querySelector("pre")).toBeInTheDocument();
});
});
describe("Header", () => {
it("shows language label in header", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "typescript",
children: "const x: number = 42;"
}));
expect(screen.getByText("typescript")).toBeInTheDocument();
});
it("hides header when showHeader is false", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
showHeader: false,
language: "javascript",
children: "console.log('test');"
}));
expect(screen.queryByText("javascript")).not.toBeInTheDocument();
});
it("shows header by default", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "python",
children: "print('hello')"
}));
expect(screen.getByText("python")).toBeInTheDocument();
});
});
describe("Copy button", () => {
it("renders copy button by default", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "const test = true;"
}));
expect(screen.getByText("Copy")).toBeInTheDocument();
});
it("hides copy button when showCopyButton is false", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
showCopyButton: false,
children: "const test = true;"
}));
expect(screen.queryByText("Copy")).not.toBeInTheDocument();
});
it("copies code to clipboard when copy button is clicked", async () => {
const code = "const hello = 'world';";
mockWriteText.mockResolvedValue();
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: code
}));
const copyButton = screen.getByText("Copy");
await act(async () => {
fireEvent.click(copyButton);
});
await waitFor(() => {
expect(mockWriteText).toHaveBeenCalledWith(code);
});
});
it("shows 'Copied!' text after successful copy", async () => {
mockWriteText.mockResolvedValue();
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "test code"
}));
const copyButton = screen.getByText("Copy");
await act(async () => {
fireEvent.click(copyButton);
});
await waitFor(() => {
expect(screen.getByText("Copied!")).toBeInTheDocument();
});
});
it("resets copy button text after timeout", async () => {
jest.useFakeTimers();
mockWriteText.mockResolvedValue();
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "test code"
}));
const copyButton = screen.getByText("Copy");
await act(async () => {
fireEvent.click(copyButton);
});
await waitFor(() => {
expect(screen.getByText("Copied!")).toBeInTheDocument();
});
await act(async () => {
jest.advanceTimersByTime(2000);
});
await waitFor(() => {
expect(screen.getByText("Copy")).toBeInTheDocument();
});
jest.useRealTimers();
});
it("handles copy errors gracefully", async () => {
const consoleError = jest.spyOn(console, "error").mockImplementation();
mockWriteText.mockRejectedValue(new Error("Copy failed"));
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "test code"
}));
const copyButton = screen.getByText("Copy");
await act(async () => {
fireEvent.click(copyButton);
});
await waitFor(() => {
expect(consoleError).toHaveBeenCalledWith("Failed to copy code:", expect.any(Error));
});
consoleError.mockRestore();
});
});
describe("Line numbers", () => {
it("does not show line numbers by default", () => {
const code = "line 1\nline 2\nline 3";
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: code
}));
const lineNumbers = container.querySelectorAll('span[style*="width: 2em"]');
expect(lineNumbers.length).toBe(0);
});
it("shows line numbers when showLineNumbers is true", () => {
const code = "first\nsecond\nthird";
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
showLineNumbers: true,
children: code
}));
// Check for line numbers - they should be present in the rendered content
// The LineNumber component renders spans with specific styling
const preElement = container.querySelector("pre");
expect(preElement).not.toBeNull();
// Verify that line numbers appear (checking text content)
const content = container.textContent;
expect(content).toContain("1");
expect(content).toContain("2");
expect(content).toContain("3");
expect(content).toContain("first");
expect(content).toContain("second");
expect(content).toContain("third");
});
});
describe("Language support", () => {
it("supports JSON language", () => {
const json = JSON.stringify({
key: "value"
}, null, 2);
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "json",
children: json
}));
expect(screen.getByText("json")).toBeInTheDocument();
});
it("supports JavaScript language", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "javascript",
children: "const x = 42;"
}));
expect(screen.getByText("javascript")).toBeInTheDocument();
});
it("supports TypeScript language", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "typescript",
children: "const x: number = 42;"
}));
expect(screen.getByText("typescript")).toBeInTheDocument();
});
it("supports Python language", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "python",
children: "print('hello')"
}));
expect(screen.getByText("python")).toBeInTheDocument();
});
it("supports SQL language", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "sql",
children: "SELECT * FROM users;"
}));
expect(screen.getByText("sql")).toBeInTheDocument();
});
it("supports Bash language", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
language: "bash",
children: "echo \"hello\""
}));
expect(screen.getByText("bash")).toBeInTheDocument();
});
});
describe("Custom styling", () => {
it("applies custom maxHeight", () => {
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
maxHeight: "200px",
children: "test code"
}));
const pre = container.querySelector("pre");
expect(pre).toHaveStyle({
maxHeight: "200px"
});
});
it("uses default maxHeight of 500px when not specified", () => {
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "test code"
}));
const pre = container.querySelector("pre");
expect(pre).toHaveStyle({
maxHeight: "500px"
});
});
it("accepts spacing props", () => {
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
mb: "r",
mt: "s",
children: "test code"
}));
const wrapper = container.firstChild;
expect(wrapper).toBeInTheDocument();
});
});
describe("Accessibility", () => {
it("copy button has accessible label", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "test code"
}));
const copyButton = screen.getByLabelText("Copy code");
expect(copyButton).toBeInTheDocument();
});
it("copy button shows 'Copied!' in label after clicking", async () => {
mockWriteText.mockResolvedValue();
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: "test code"
}));
const copyButton = screen.getByLabelText("Copy code");
await act(async () => {
fireEvent.click(copyButton);
});
await waitFor(() => {
expect(screen.getByLabelText("Copied!")).toBeInTheDocument();
});
});
});
describe("Edge cases", () => {
it("handles empty string", () => {
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: ""
}));
const copyButton = screen.getByText("Copy");
expect(copyButton).toBeInTheDocument();
});
it("handles very long code", () => {
const longCode = "x".repeat(10000);
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: longCode
}));
const pre = container.querySelector("pre");
expect(pre).toBeInTheDocument();
});
it("handles code with special characters", () => {
const specialCode = 'const x = "<>&\'"';
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: specialCode
}));
expect(screen.getByText(/const x/)).toBeInTheDocument();
});
it("handles multiline code", () => {
const multiline = "function test() {\n return true;\n}";
renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
children: multiline
}));
expect(screen.getByText(/function test/)).toBeInTheDocument();
});
});
describe("Theme integration", () => {
it("accepts custom theme prop", () => {
const customTheme = {
colors: {
greyDarkest: "#000000"
}
};
const {
container
} = renderWithTheme(/*#__PURE__*/_jsx(CodeBlock, {
theme: customTheme,
children: "test code"
}));
expect(container.firstChild).toBeInTheDocument();
});
});
});