Files
community-rule/tests/unit/QuoteBlock.test.jsx
T
adilalloandCursor c180e79c38 Give every public route its own description, and keep canonicals and structured data on the host that serves the page.
Decorative images on the marketing pages stay quiet, and every dialog close button is named Close.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 11:04:52 -07:00

267 lines
7.9 KiB
React

import {
renderWithProviders as render,
screen,
cleanup,
} from "../utils/test-utils";
import { vi, describe, test, expect, afterEach } from "vitest";
import QuoteBlock from "../../app/components/sections/QuoteBlock";
afterEach(() => {
cleanup();
});
describe("QuoteBlock Component", () => {
test("renders with default props", () => {
render(<QuoteBlock />);
expect(
screen.getByText(/The rules of decision-making must be open/),
).toBeInTheDocument();
expect(screen.getByText("Jo Freeman")).toBeInTheDocument();
expect(
screen.getByText("The Tyranny of Structurelessness"),
).toBeInTheDocument();
expect(document.querySelector("img")).toHaveAttribute("alt", "");
});
test("renders with custom props", () => {
render(
<QuoteBlock
quote="Custom quote text"
author="Custom Author"
source="Custom Source"
/>,
);
expect(screen.getByText("Custom quote text")).toBeInTheDocument();
expect(screen.getByText("Custom Author")).toBeInTheDocument();
expect(screen.getByText("Custom Source")).toBeInTheDocument();
});
test("renders with custom className", () => {
render(
<QuoteBlock
quote="Test quote"
author="Test Author"
className="custom-class"
/>,
);
const section = document.querySelector("section");
expect(section).toHaveClass("custom-class");
});
test("renders different variants", () => {
const { rerender } = render(
<QuoteBlock quote="Test quote" author="Test Author" variant="compact" />,
);
// Compact variant should have different styling
const section = screen.getByRole("region");
expect(section).toHaveClass(
"py-[var(--space-800)]",
"px-[var(--space-400)]",
);
rerender(
<QuoteBlock quote="Test quote" author="Test Author" variant="extended" />,
);
// Extended variant should have different styling
expect(section).toHaveClass(
"py-[var(--space-1200)]",
"px-[var(--space-600)]",
);
});
test("renders with custom ID", () => {
render(
<QuoteBlock
quote="Test quote"
author="Test Author"
id="custom-quote-id"
/>,
);
const quoteElement = screen.getByText("Test quote");
expect(quoteElement).toBeInTheDocument();
});
test("handles image error gracefully", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" />);
// Should render the quote and author
expect(screen.getByText("Test quote")).toBeInTheDocument();
expect(screen.getByText("Test Author")).toBeInTheDocument();
});
test("calls onError callback when image fails", () => {
const onError = vi.fn();
render(
<QuoteBlock quote="Test quote" author="Test Author" onError={onError} />,
);
// Should render without errors
expect(screen.getByText("Test quote")).toBeInTheDocument();
});
test("renders with fallback avatar", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" />);
// Should render the quote and author
expect(screen.getByText("Test quote")).toBeInTheDocument();
expect(screen.getByText("Test Author")).toBeInTheDocument();
});
test("renders decorative elements for standard variant", () => {
render(
<QuoteBlock quote="Test quote" author="Test Author" variant="standard" />,
);
// Should render QuoteDecor for standard variant
const decor = document.querySelector(
'[class*="pointer-events-none absolute z-0"]',
);
expect(decor).toBeInTheDocument();
});
test("does not render decorative elements for compact variant", () => {
render(
<QuoteBlock quote="Test quote" author="Test Author" variant="compact" />,
);
// Should not render QuoteDecor for compact variant
const decor = document.querySelector(
'[class*="pointer-events-none absolute z-0"]',
);
expect(decor).not.toBeInTheDocument();
});
test("renders with proper semantic structure", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" />);
const section = document.querySelector("section");
expect(section).toBeInTheDocument();
const blockquote = document.querySelector("blockquote");
expect(blockquote).toBeInTheDocument();
const cite = document.querySelector("cite");
expect(cite).toBeInTheDocument();
});
test("applies correct accessibility attributes", () => {
render(
<QuoteBlock quote="Test quote" author="Test Author" id="test-quote" />,
);
const section = document.querySelector("section");
expect(section).toHaveAttribute("aria-labelledby", "test-quote-content");
const blockquote = document.querySelector("blockquote");
expect(blockquote).toHaveAttribute("aria-labelledby", "test-quote-author");
});
test("renders with design tokens", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" />);
const section = document.querySelector("section");
expect(section).toHaveClass("md:py-[var(--space-800)]");
const card = section.querySelector(
'[class*="bg-[var(--color-surface-invert-brand-secondary)]"]',
);
expect(card).toBeInTheDocument();
});
test("handles missing required props", () => {
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
render(<QuoteBlock quote="" author="" />);
expect(consoleSpy).toHaveBeenCalledWith(
"QuoteBlock: Missing required props (quote or author)",
);
consoleSpy.mockRestore();
});
test("renders with proper quote styling", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" />);
const quoteElement = screen.getByText("Test quote");
expect(quoteElement).toHaveClass("font-bricolage-grotesque", "font-normal");
});
test("renders with proper author styling", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" />);
const authorElement = screen.getByText("Test Author");
expect(authorElement).toHaveClass("font-normal", "uppercase");
});
test("applies responsive text sizing", () => {
render(
<QuoteBlock quote="Test quote" author="Test Author" variant="standard" />,
);
const quoteElement = screen.getByText("Test quote");
expect(quoteElement).toHaveClass(
"text-xx-small-display",
"md:text-small-display",
"lg:text-large-display",
);
});
test("renders without source when not provided", () => {
render(<QuoteBlock quote="Test quote" author="Test Author" source="" />);
expect(screen.getByText("Test quote")).toBeInTheDocument();
expect(screen.getByText("Test Author")).toBeInTheDocument();
expect(
screen.queryByText("The Tyranny of Structurelessness"),
).not.toBeInTheDocument();
});
test("statement variant uses one paragraph with responsive stack (Figma 21967-24638)", () => {
render(
<QuoteBlock
variant="statement"
id="about-test-quote"
quote="First paragraph of the statement."
quoteSecondary="Second paragraph of the statement."
/>,
);
const region = screen.getByRole("region", {
name: /first paragraph of the statement/i,
});
expect(region).toBeInTheDocument();
expect(region).toHaveAttribute("data-figma-node", "21967-24638");
expect(
screen.getByText("Second paragraph of the statement."),
).toBeInTheDocument();
expect(screen.queryByRole("cite")).not.toBeInTheDocument();
const heading = region.querySelector("#about-test-quote-content");
expect(heading?.querySelectorAll("span.block.lg\\:inline").length).toBe(2);
});
test("statement variant logs when quoteSecondary is missing", () => {
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
render(
<QuoteBlock
variant="statement"
quote="Only one paragraph"
/>,
);
expect(consoleSpy).toHaveBeenCalledWith(
"QuoteBlock: statement variant requires non-empty quote and quoteSecondary",
);
consoleSpy.mockRestore();
});
});