Component cleanup

This commit is contained in:
adilallo
2026-04-29 07:20:16 -06:00
parent 252848eba9
commit e6127f1a3f
267 changed files with 2087 additions and 2196 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ import {
} from "../utils/test-utils";
import userEvent from "@testing-library/user-event";
import { vi, describe, test, expect, afterEach } from "vitest";
import CardStack from "../../app/components/utility/CardStack";
import CardStack from "../../app/components/cards/CardStack";
const SAMPLE_CARDS = [
{
@@ -4,14 +4,14 @@ import {
cleanup,
} from "../utils/test-utils";
import { describe, test, expect, afterEach } from "vitest";
import NumberedCards from "../../app/components/sections/NumberedCards";
import CardSteps from "../../app/components/sections/CardSteps";
afterEach(() => {
cleanup();
});
describe("NumberedCards Component", () => {
const mockCards = [
describe("CardSteps Component", () => {
const mockSteps = [
{
text: "Define your community values",
iconShape: "circle",
@@ -29,23 +29,20 @@ describe("NumberedCards Component", () => {
},
];
test("renders with title, subtitle, and cards", () => {
test("renders with title, subtitle, and step cards", () => {
render(
<NumberedCards
<CardSteps
title="How CommunityRule helps"
subtitle="Build better communities step by step"
cards={mockCards}
steps={mockSteps}
/>,
);
// Check for the heading (it contains both mobile and desktop versions)
expect(screen.getByRole("heading")).toBeInTheDocument();
// Check for the subtitle text
expect(
screen.getByText("Build better communities step by step"),
).toBeInTheDocument();
// Check for card content
expect(
screen.getByText("Define your community values"),
).toBeInTheDocument();
@@ -59,55 +56,51 @@ describe("NumberedCards Component", () => {
test("renders SectionHeader component", () => {
render(
<NumberedCards
<CardSteps
title="Test Title"
subtitle="Test Subtitle"
cards={mockCards}
steps={mockSteps}
/>,
);
// Check for the heading (it contains both mobile and desktop versions)
expect(screen.getByRole("heading")).toBeInTheDocument();
// Check for the subtitle text
expect(screen.getByText("Test Subtitle")).toBeInTheDocument();
});
test("renders NumberCard components with correct props", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
test("renders Step tiles with correct props", () => {
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
// Check that NumberCard components receive correct props
expect(screen.getByText("1")).toBeInTheDocument(); // First card number
expect(screen.getByText("2")).toBeInTheDocument(); // Second card number
expect(screen.getByText("3")).toBeInTheDocument(); // Third card number
expect(screen.getByText("1")).toBeInTheDocument();
expect(screen.getByText("2")).toBeInTheDocument();
expect(screen.getByText("3")).toBeInTheDocument();
});
test("renders call-to-action buttons", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
test("renders call-to-action button", () => {
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
expect(
screen.getByRole("button", { name: "Create CommunityRule" }),
).toBeInTheDocument();
expect(
screen.getByRole("button", { name: "See how it works" }),
).toBeInTheDocument();
});
test("applies responsive button visibility", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
test("renders stacked desktop heading lines when provided", () => {
const { container } = render(
<CardSteps
title="Mobile line"
subtitle="Test"
steps={mockSteps}
headingDesktopLines={["How", "CommunityRule", "helps"]}
/>,
);
const createButton = screen.getByRole("button", {
name: "Create CommunityRule",
});
const seeHowButton = screen.getByRole("button", {
name: "See how it works",
});
expect(createButton.closest("div")).toHaveClass("block", "lg:hidden");
expect(seeHowButton.closest("div")).toHaveClass("hidden", "lg:block");
const h2 = container.querySelector("h2");
expect(h2?.textContent).toContain("Mobile line");
expect(h2?.textContent).toContain("CommunityRule");
expect(h2?.textContent).toContain("helps");
});
test("renders with design tokens", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
const section = document.querySelector("section");
expect(section).toHaveClass(
@@ -117,7 +110,7 @@ describe("NumberedCards Component", () => {
});
test("applies responsive grid layout", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
const cardsContainer = document.querySelector(
'[class*="grid grid-cols-1"]',
@@ -127,10 +120,10 @@ describe("NumberedCards Component", () => {
test("renders schema markup", () => {
render(
<NumberedCards
<CardSteps
title="Test Title"
subtitle="Test Description"
cards={mockCards}
steps={mockSteps}
/>,
);
@@ -145,40 +138,37 @@ describe("NumberedCards Component", () => {
});
test("has proper semantic structure", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
const section = document.querySelector("section");
expect(section).toBeInTheDocument();
// Check for proper heading structure
const headings = screen.getAllByRole("heading");
expect(headings.length).toBeGreaterThan(0);
});
test("handles empty cards array", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={[]} />);
test("handles empty steps array", () => {
render(<CardSteps title="Test" subtitle="Test" steps={[]} />);
// Should still render the structure
const section = document.querySelector("section");
expect(section).toBeInTheDocument();
// Should render buttons even without cards
expect(
screen.getByRole("button", { name: "Create CommunityRule" }),
screen.getByRole("button", { name: "See how it works" }),
).toBeInTheDocument();
});
test("applies responsive text alignment", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
test("centers call-to-action region", () => {
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
const buttonContainer = screen
.getByRole("button", { name: "Create CommunityRule" })
const buttonRegion = screen
.getByRole("button", { name: "See how it works" })
.closest("div");
expect(buttonContainer).toHaveClass("block", "lg:hidden");
expect(buttonRegion).toHaveClass("text-center");
});
test("renders with proper spacing", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
const section = document.querySelector("section");
expect(section).toHaveClass(
@@ -188,7 +178,7 @@ describe("NumberedCards Component", () => {
});
test("applies max-width constraint", () => {
render(<NumberedCards title="Test" subtitle="Test" cards={mockCards} />);
render(<CardSteps title="Test" subtitle="Test" steps={mockSteps} />);
const container = document.querySelector(
'[class*="max-w-[var(--spacing-measures-max-width-lg)]"]',
@@ -4,16 +4,16 @@ import {
fireEvent,
} from "../utils/test-utils";
import { describe, it, expect, vi } from "vitest";
import RuleCard from "../../app/components/cards/RuleCard";
import Rule from "../../app/components/cards/Rule";
describe("RuleCard Component", () => {
describe("Rule Component", () => {
const defaultProps = {
title: "Test Rule",
description: "This is a test rule description",
};
it("renders rule card with all required information", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
expect(screen.getByText("Test Rule")).toBeInTheDocument();
expect(
@@ -23,14 +23,14 @@ describe("RuleCard Component", () => {
it("renders with custom className", () => {
const customClass = "custom-rule-card";
render(<RuleCard {...defaultProps} className={customClass} />);
render(<Rule {...defaultProps} className={customClass} />);
const card = screen.getByRole("button");
expect(card).toHaveClass(customClass);
});
it("applies default background color", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
const card = screen.getByRole("button");
expect(card).toHaveClass("bg-[var(--color-community-teal-100)]");
@@ -38,7 +38,7 @@ describe("RuleCard Component", () => {
it("applies custom background color", () => {
const customBg = "bg-blue-100";
render(<RuleCard {...defaultProps} backgroundColor={customBg} />);
render(<Rule {...defaultProps} backgroundColor={customBg} />);
const card = screen.getByRole("button");
expect(card).toHaveClass(customBg);
@@ -46,14 +46,14 @@ describe("RuleCard Component", () => {
it("renders with icon when provided", () => {
const Icon = () => <span data-testid="icon">🚀</span>;
render(<RuleCard {...defaultProps} icon={<Icon />} />);
render(<Rule {...defaultProps} icon={<Icon />} />);
expect(screen.getByTestId("icon")).toBeInTheDocument();
});
it("handles click events", () => {
const handleClick = vi.fn();
render(<RuleCard {...defaultProps} onClick={handleClick} />);
render(<Rule {...defaultProps} onClick={handleClick} />);
const card = screen.getByRole("button");
fireEvent.click(card);
@@ -63,7 +63,7 @@ describe("RuleCard Component", () => {
it("handles keyboard events", () => {
const handleClick = vi.fn();
render(<RuleCard {...defaultProps} onClick={handleClick} />);
render(<Rule {...defaultProps} onClick={handleClick} />);
const card = screen.getByRole("button");
@@ -77,7 +77,7 @@ describe("RuleCard Component", () => {
});
it("applies hover effects correctly", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
const card = screen.getByRole("button");
expect(card).toHaveClass(
@@ -87,7 +87,7 @@ describe("RuleCard Component", () => {
});
it("renders with proper accessibility attributes", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
const card = screen.getByRole("button");
expect(card).toHaveAttribute(
@@ -98,7 +98,7 @@ describe("RuleCard Component", () => {
});
it("handles empty description gracefully", () => {
render(<RuleCard {...defaultProps} description="" />);
render(<Rule {...defaultProps} description="" />);
expect(screen.getByText("Test Rule")).toBeInTheDocument();
expect(
@@ -107,14 +107,14 @@ describe("RuleCard Component", () => {
});
it("applies proper sizing for expanded states", () => {
render(<RuleCard {...defaultProps} expanded={true} size="L" />);
render(<Rule {...defaultProps} expanded={true} size="L" />);
const card = screen.getByRole("button");
expect(card).toHaveClass("w-[568px]");
});
it("applies proper accessibility attributes", () => {
render(<RuleCard {...defaultProps} expanded={true} />);
render(<Rule {...defaultProps} expanded={true} />);
const card = screen.getByRole("button");
expect(card).toHaveAttribute("aria-expanded", "true");
@@ -122,13 +122,13 @@ describe("RuleCard Component", () => {
});
it("renders without icon when not provided", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
expect(screen.queryByTestId("icon")).not.toBeInTheDocument();
});
it("applies proper border and shadow classes", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
const card = screen.getByRole("button");
expect(card).toHaveClass("shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)]");
@@ -136,7 +136,7 @@ describe("RuleCard Component", () => {
});
it("maintains proper heading structure", () => {
render(<RuleCard {...defaultProps} />);
render(<Rule {...defaultProps} />);
const heading = screen.getByRole("heading", { level: 3 });
expect(heading).toHaveTextContent("Test Rule");
@@ -144,7 +144,7 @@ describe("RuleCard Component", () => {
});
it("applies proper font classes for title", () => {
render(<RuleCard {...defaultProps} size="L" />);
render(<Rule {...defaultProps} size="L" />);
const heading = screen.getByRole("heading", { level: 3 });
// Check for responsive font classes - at 1440px+ it should have font-bricolage-grotesque and font-extrabold
@@ -164,7 +164,7 @@ describe("RuleCard Component", () => {
},
];
render(
<RuleCard {...defaultProps} expanded={true} categories={categories} />,
<Rule {...defaultProps} expanded={true} categories={categories} />,
);
expect(screen.getByText("Values")).toBeInTheDocument();
@@ -172,7 +172,7 @@ describe("RuleCard Component", () => {
it("renders with logo URL", () => {
render(
<RuleCard
<Rule
{...defaultProps}
logoUrl="http://localhost:3845/assets/test.png"
logoAlt="Test Logo"
@@ -184,7 +184,7 @@ describe("RuleCard Component", () => {
});
it("renders with community initials fallback", () => {
render(<RuleCard {...defaultProps} communityInitials="CE" />);
render(<Rule {...defaultProps} communityInitials="CE" />);
expect(screen.getByText("CE")).toBeInTheDocument();
});
+1 -1
View File
@@ -179,7 +179,7 @@ describe("RuleStack Component", () => {
expect(grid).toHaveClass("min-[768px]:grid", "min-[768px]:grid-cols-2");
});
test("renders RuleCard components with catalog surface colors", async () => {
test("renders Rule components with catalog surface colors", async () => {
render(<RuleStack />);
await waitForRuleStackCards();
@@ -4,9 +4,9 @@ import {
fireEvent,
} from "../utils/test-utils";
import { describe, it, expect, vi } from "vitest";
import Card from "../../app/components/cards/Card";
import Selection from "../../app/components/cards/Selection";
describe("Card Component", () => {
describe("Selection Component", () => {
const defaultProps = {
label: "Label",
supportText: "Support text here",
@@ -14,26 +14,26 @@ describe("Card Component", () => {
};
it("renders label and supportText", () => {
render(<Card {...defaultProps} />);
render(<Selection {...defaultProps} />);
expect(screen.getByText("Label")).toBeInTheDocument();
expect(screen.getByText("Support text here")).toBeInTheDocument();
});
it("renders RECOMMENDED pill when recommended is true", () => {
render(<Card {...defaultProps} recommended={true} />);
render(<Selection {...defaultProps} recommended={true} />);
expect(screen.getByText("RECOMMENDED")).toBeInTheDocument();
});
it("does not render RECOMMENDED pill when recommended is false", () => {
render(<Card {...defaultProps} recommended={false} />);
render(<Selection {...defaultProps} recommended={false} />);
expect(screen.queryByText("RECOMMENDED")).not.toBeInTheDocument();
});
it("renders SELECTED pill and inset dashed outline when selected is true", () => {
render(<Card {...defaultProps} selected={true} />);
render(<Selection {...defaultProps} selected={true} />);
expect(screen.getByText("SELECTED")).toBeInTheDocument();
const card = screen.getByRole("button");
@@ -41,14 +41,14 @@ describe("Card Component", () => {
});
it("applies horizontal layout by default", () => {
render(<Card {...defaultProps} />);
render(<Selection {...defaultProps} />);
expect(screen.getByText("Label")).toBeInTheDocument();
expect(screen.getByText("Support text here")).toBeInTheDocument();
});
it("applies vertical layout when orientation is vertical", () => {
render(<Card {...defaultProps} orientation="vertical" />);
render(<Selection {...defaultProps} orientation="vertical" />);
const card = screen.getByRole("button");
expect(card).toHaveClass("flex-row");
@@ -56,7 +56,7 @@ describe("Card Component", () => {
it("handles click events", () => {
const handleClick = vi.fn();
render(<Card {...defaultProps} onClick={handleClick} />);
render(<Selection {...defaultProps} onClick={handleClick} />);
const card = screen.getByRole("button");
fireEvent.click(card);
@@ -66,7 +66,7 @@ describe("Card Component", () => {
it("handles keyboard events", () => {
const handleClick = vi.fn();
render(<Card {...defaultProps} onClick={handleClick} />);
render(<Selection {...defaultProps} onClick={handleClick} />);
const card = screen.getByRole("button");
@@ -79,14 +79,14 @@ describe("Card Component", () => {
it("renders with custom className", () => {
const customClass = "custom-card";
render(<Card {...defaultProps} className={customClass} />);
render(<Selection {...defaultProps} className={customClass} />);
const card = screen.getByRole("button");
expect(card).toHaveClass(customClass);
});
it("renders with proper accessibility attributes", () => {
render(<Card {...defaultProps} />);
render(<Selection {...defaultProps} />);
const card = screen.getByRole("button");
expect(card).toHaveAttribute("aria-label", "Label: Support text here");
@@ -94,7 +94,7 @@ describe("Card Component", () => {
});
it("renders without supportText", () => {
render(<Card label="Label only" orientation="horizontal" />);
render(<Selection label="Label only" orientation="horizontal" />);
expect(screen.getByText("Label only")).toBeInTheDocument();
expect(screen.getByRole("button")).toHaveAttribute(
@@ -1,41 +1,41 @@
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";
import NumberCard from "../../app/components/cards/NumberCard";
import Step from "../../app/components/cards/Step";
// Pure presentational; no provider context needed.
describe("NumberCard Component", () => {
describe("Step Component", () => {
const defaultProps = {
number: 1,
text: "Test Card Text",
};
it("renders number card with all required information", () => {
render(<NumberCard {...defaultProps} />);
it("renders step with all required information", () => {
render(<Step {...defaultProps} />);
expect(screen.getByText("1")).toBeInTheDocument();
expect(screen.getByText("Test Card Text")).toBeInTheDocument();
});
it("renders with different numbers", () => {
const { rerender } = render(<NumberCard {...defaultProps} number={42} />);
const { rerender } = render(<Step {...defaultProps} number={42} />);
expect(screen.getByText("42")).toBeInTheDocument();
rerender(<NumberCard {...defaultProps} number={999} />);
rerender(<Step {...defaultProps} number={999} />);
expect(screen.getByText("999")).toBeInTheDocument();
});
it("renders with different text content", () => {
const { rerender } = render(
<NumberCard {...defaultProps} text="Different Text" />,
<Step {...defaultProps} text="Different Text" />,
);
expect(screen.getByText("Different Text")).toBeInTheDocument();
rerender(<NumberCard {...defaultProps} text="Another Text" />);
rerender(<Step {...defaultProps} text="Another Text" />);
expect(screen.getByText("Another Text")).toBeInTheDocument();
});
it("applies proper responsive layout classes when size is not specified", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -53,7 +53,7 @@ describe("NumberCard Component", () => {
});
it("applies proper responsive spacing when size is not specified", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -62,7 +62,7 @@ describe("NumberCard Component", () => {
});
it("applies proper responsive gap when size is not specified", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -71,7 +71,7 @@ describe("NumberCard Component", () => {
});
it("applies proper responsive height when size is not specified", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -80,7 +80,7 @@ describe("NumberCard Component", () => {
});
it("applies proper background and shadow", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -92,7 +92,7 @@ describe("NumberCard Component", () => {
});
it("applies proper border radius", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -101,14 +101,14 @@ describe("NumberCard Component", () => {
});
it("renders section number in correct position for responsive mode", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const numberElement = screen.getByText("1");
expect(numberElement).toBeInTheDocument();
});
it("renders text content in correct position for responsive mode", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const textElement = screen.getByText("Test Card Text");
expect(textElement).toBeInTheDocument();
@@ -125,14 +125,14 @@ describe("NumberCard Component", () => {
});
it("applies proper font classes to text", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const textElement = screen.getByText("Test Card Text");
expect(textElement).toHaveClass("font-bricolage-grotesque");
});
it("applies proper text sizing for responsive mode", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const textElement = screen.getByText("Test Card Text");
expect(textElement).toHaveClass(
@@ -147,7 +147,7 @@ describe("NumberCard Component", () => {
});
it("applies proper text color", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const textElement = screen.getByText("Test Card Text");
expect(textElement).toHaveClass("text-[#141414]");
@@ -155,14 +155,14 @@ describe("NumberCard Component", () => {
it("handles long text content gracefully", () => {
const longText =
"This is a very long text that should wrap properly and not break the layout of the number card component";
render(<NumberCard {...defaultProps} text={longText} />);
"This is a very long text that should wrap properly and not break the layout of the Step component";
render(<Step {...defaultProps} text={longText} />);
expect(screen.getByText(longText)).toBeInTheDocument();
});
it("maintains proper responsive behavior when size is not specified", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -192,7 +192,7 @@ describe("NumberCard Component", () => {
});
it("renders with proper flex layout", () => {
render(<NumberCard {...defaultProps} />);
render(<Step {...defaultProps} />);
const card = screen
.getByText("Test Card Text")
@@ -201,7 +201,7 @@ describe("NumberCard Component", () => {
});
it("applies Small size variant correctly", () => {
render(<NumberCard {...defaultProps} size="small" />);
render(<Step {...defaultProps} size="small" />);
// For Small size, text is directly in card div (no wrapper), so use closest("div")
const card = screen.getByText("Test Card Text").closest("div");
@@ -220,7 +220,7 @@ describe("NumberCard Component", () => {
});
it("applies Medium size variant correctly", () => {
render(<NumberCard {...defaultProps} size="medium" />);
render(<Step {...defaultProps} size="medium" />);
const card = screen
.getByText("Test Card Text")
@@ -238,7 +238,7 @@ describe("NumberCard Component", () => {
});
it("applies Large size variant correctly", () => {
render(<NumberCard {...defaultProps} size="large" />);
render(<Step {...defaultProps} size="large" />);
const card = screen
.getByText("Test Card Text")
@@ -258,7 +258,7 @@ describe("NumberCard Component", () => {
});
it("applies XLarge size variant correctly", () => {
render(<NumberCard {...defaultProps} size="xlarge" />);
render(<Step {...defaultProps} size="xlarge" />);
const card = screen
.getByText("Test Card Text")
+33
View File
@@ -209,6 +209,39 @@ describe("parseDocumentSectionsForDisplay", () => {
};
expect(parseDocumentSectionsForDisplay(doc)).toEqual(doc.sections);
});
it("accepts entries with labeled blocks and empty body", () => {
const doc = {
sections: [
{
categoryName: "Membership",
entries: [
{
title: "Open membership",
body: "",
blocks: [
{ label: "Eligibility", body: "Anyone may join." },
{ label: "Process", body: "Sign the sheet." },
],
},
],
},
],
};
expect(parseDocumentSectionsForDisplay(doc)).toEqual(doc.sections);
});
it("still parses entries with empty body and no blocks", () => {
const doc = {
sections: [
{
categoryName: "Values",
entries: [{ title: "Consensus", body: "" }],
},
],
};
expect(parseDocumentSectionsForDisplay(doc)).toEqual(doc.sections);
});
});
describe("parseSectionsFromCreateFlowState", () => {
+1 -1
View File
@@ -7,7 +7,7 @@ import {
} from "../../lib/create/templateReviewMapping";
describe("templateReviewMapping", () => {
it("maps body sections to RuleCard categories", () => {
it("maps body sections to Rule categories", () => {
const body = {
sections: [
{