Simplify and standardize testing structure
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import AskOrganizer from "../../app/components/AskOrganizer";
|
||||
import {
|
||||
componentTestSuite,
|
||||
ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type AskOrganizerProps = React.ComponentProps<typeof AskOrganizer>;
|
||||
|
||||
const baseProps: AskOrganizerProps = {
|
||||
title: "Need help?",
|
||||
};
|
||||
|
||||
const config: ComponentTestSuiteConfig<AskOrganizerProps> = {
|
||||
component: AskOrganizer,
|
||||
name: "AskOrganizer",
|
||||
props: baseProps,
|
||||
optionalProps: {
|
||||
subtitle: "Subtitle",
|
||||
description: "Description",
|
||||
buttonText: "Button",
|
||||
buttonHref: "/link",
|
||||
className: "custom",
|
||||
variant: "centered",
|
||||
},
|
||||
primaryRole: "region",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<AskOrganizerProps>(config);
|
||||
|
||||
describe("AskOrganizer (behavioral tests)", () => {
|
||||
it("renders title", () => {
|
||||
render(<AskOrganizer title="Test Title" />);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Test Title" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders subtitle when provided", () => {
|
||||
render(<AskOrganizer title="Test" subtitle="Subtitle" />);
|
||||
expect(screen.getByRole("heading", { name: "Subtitle" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders button with default text", () => {
|
||||
render(<AskOrganizer title="Test" />);
|
||||
expect(
|
||||
screen.getByRole("link", {
|
||||
name: /ask an organizer/i,
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders button with custom text", () => {
|
||||
render(
|
||||
<AskOrganizer title="Test" buttonText="Contact" buttonHref="/contact" />,
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("link", {
|
||||
name: /contact/i,
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import Button from "../../app/components/Button";
|
||||
import {
|
||||
componentTestSuite,
|
||||
ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type ButtonProps = React.ComponentProps<typeof Button>;
|
||||
|
||||
const baseProps: ButtonProps = {
|
||||
children: "Click me",
|
||||
};
|
||||
|
||||
const config: ComponentTestSuiteConfig<ButtonProps> = {
|
||||
component: Button,
|
||||
name: "Button",
|
||||
props: baseProps,
|
||||
requiredProps: ["children"],
|
||||
optionalProps: {
|
||||
href: "/test",
|
||||
ariaLabel: "Accessible button",
|
||||
},
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: false,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<ButtonProps>(config);
|
||||
|
||||
describe("Button (behavioral tests)", () => {
|
||||
it("calls onClick when clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
const handleClick = vi.fn();
|
||||
|
||||
render(<Button onClick={handleClick}>Click me</Button>);
|
||||
|
||||
const button = screen.getByRole("button", { name: "Click me" });
|
||||
await user.click(button);
|
||||
|
||||
expect(handleClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("renders as a link when href is provided", () => {
|
||||
render(
|
||||
<Button href="/learn" variant="default">
|
||||
Learn more
|
||||
</Button>,
|
||||
);
|
||||
|
||||
const link = screen.getByRole("link", { name: "Learn more" });
|
||||
expect(link).toHaveAttribute("href", "/learn");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import Checkbox from "../../app/components/Checkbox";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type CheckboxProps = React.ComponentProps<typeof Checkbox>;
|
||||
|
||||
componentTestSuite<CheckboxProps>({
|
||||
component: Checkbox,
|
||||
name: "Checkbox",
|
||||
props: {
|
||||
label: "Test checkbox",
|
||||
} as CheckboxProps,
|
||||
requiredProps: ["label"],
|
||||
optionalProps: {
|
||||
value: "test",
|
||||
},
|
||||
primaryRole: "checkbox",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: false,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import ContentBanner from "../../app/components/ContentBanner";
|
||||
import type { BlogPost } from "../../lib/content";
|
||||
|
||||
vi.mock("next/link", () => ({
|
||||
default: ({ children, href, ...props }: any) => (
|
||||
<a href={href} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("../../lib/assetUtils", () => ({
|
||||
getAssetPath: vi.fn((asset: string) => `/assets/${asset}`),
|
||||
}));
|
||||
|
||||
const mockPost: BlogPost = {
|
||||
slug: "test-article",
|
||||
frontmatter: {
|
||||
title: "Test Article",
|
||||
description: "Test description",
|
||||
author: "Test Author",
|
||||
date: "2025-04-15",
|
||||
},
|
||||
};
|
||||
|
||||
describe("ContentBanner", () => {
|
||||
it("renders without crashing", () => {
|
||||
render(<ContentBanner post={mockPost} />);
|
||||
});
|
||||
|
||||
it("renders article title", () => {
|
||||
render(<ContentBanner post={mockPost} />);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Test Article" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders article description", () => {
|
||||
render(<ContentBanner post={mockPost} />);
|
||||
expect(screen.getByText("Test description")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import ContextMenu from "../../app/components/ContextMenu";
|
||||
import ContextMenuItem from "../../app/components/ContextMenuItem";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type ContextMenuProps = React.ComponentProps<typeof ContextMenu>;
|
||||
|
||||
componentTestSuite<ContextMenuProps>({
|
||||
component: ContextMenu,
|
||||
name: "ContextMenu",
|
||||
props: {
|
||||
children: (
|
||||
<ContextMenuItem>
|
||||
Item
|
||||
</ContextMenuItem>
|
||||
),
|
||||
} as ContextMenuProps,
|
||||
requiredProps: [],
|
||||
primaryRole: "menu",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
import ContextMenuItem from "../../app/components/ContextMenuItem";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type ContextMenuItemProps = React.ComponentProps<typeof ContextMenuItem>;
|
||||
|
||||
componentTestSuite<ContextMenuItemProps>({
|
||||
component: ContextMenuItem,
|
||||
name: "ContextMenuItem",
|
||||
props: {
|
||||
children: "Item",
|
||||
} as ContextMenuItemProps,
|
||||
requiredProps: [],
|
||||
primaryRole: "menuitem",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: false,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: false,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import FeatureGrid from "../../app/components/FeatureGrid";
|
||||
import {
|
||||
componentTestSuite,
|
||||
ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type FeatureGridProps = React.ComponentProps<typeof FeatureGrid>;
|
||||
|
||||
const baseProps: FeatureGridProps = {
|
||||
title: "Feature Tools",
|
||||
subtitle: "Everything you need",
|
||||
};
|
||||
|
||||
const config: ComponentTestSuiteConfig<FeatureGridProps> = {
|
||||
component: FeatureGrid,
|
||||
name: "FeatureGrid",
|
||||
props: baseProps,
|
||||
optionalProps: {
|
||||
className: "custom-class",
|
||||
title: undefined,
|
||||
subtitle: undefined,
|
||||
},
|
||||
primaryRole: "region",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<FeatureGridProps>(config);
|
||||
|
||||
describe("FeatureGrid (behavioral tests)", () => {
|
||||
it("renders title and subtitle", () => {
|
||||
render(<FeatureGrid title="Test Title" subtitle="Test Subtitle" />);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Test Title" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Test Subtitle" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders all four feature cards", () => {
|
||||
render(<FeatureGrid title="Test" subtitle="Test" />);
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Decision-making support tools" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Values alignment exercises" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Membership guidance resources" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Conflict resolution tools" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("has proper accessibility attributes", () => {
|
||||
render(<FeatureGrid title="Test" subtitle="Test" />);
|
||||
const section = document.querySelector("section");
|
||||
expect(section).toHaveAttribute("aria-labelledby", "feature-grid-headline");
|
||||
expect(screen.getByRole("grid")).toHaveAttribute(
|
||||
"aria-label",
|
||||
"Feature tools and services",
|
||||
);
|
||||
});
|
||||
|
||||
it("handles missing props gracefully", () => {
|
||||
render(<FeatureGrid />);
|
||||
const section = document.querySelector("section");
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Footer from "../../app/components/Footer";
|
||||
import {
|
||||
componentTestSuite,
|
||||
ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type FooterProps = React.ComponentProps<typeof Footer>;
|
||||
|
||||
const baseProps: FooterProps = {};
|
||||
|
||||
const config: ComponentTestSuiteConfig<FooterProps> = {
|
||||
component: Footer,
|
||||
name: "Footer",
|
||||
props: baseProps,
|
||||
primaryRole: "contentinfo",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false, // Footer is not primarily keyboard navigable
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<FooterProps>(config);
|
||||
|
||||
describe("Footer (behavioral tests)", () => {
|
||||
it("renders organization schema markup", () => {
|
||||
render(<Footer />);
|
||||
const script = document.querySelector('script[type="application/ld+json"]');
|
||||
expect(script).toBeInTheDocument();
|
||||
|
||||
const schemaData = JSON.parse(script?.textContent || "{}");
|
||||
expect(schemaData["@type"]).toBe("Organization");
|
||||
expect(schemaData.name).toBe("Media Economies Design Lab");
|
||||
});
|
||||
|
||||
it("renders organization name and contact", () => {
|
||||
render(<Footer />);
|
||||
expect(
|
||||
screen.getAllByText("Media Economies Design Lab").length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "medlab@colorado.edu" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders social media links", () => {
|
||||
render(<Footer />);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Follow us on Bluesky" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Follow us on GitLab" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders navigation links", () => {
|
||||
render(<Footer />);
|
||||
expect(screen.getAllByRole("link", { name: "Use cases" }).length).toBeGreaterThan(0);
|
||||
expect(screen.getAllByRole("link", { name: "Learn" }).length).toBeGreaterThan(0);
|
||||
expect(screen.getAllByRole("link", { name: "About" }).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders legal links", () => {
|
||||
render(<Footer />);
|
||||
expect(screen.getAllByRole("link", { name: "Privacy Policy" }).length).toBeGreaterThan(0);
|
||||
expect(screen.getAllByRole("link", { name: "Terms of Service" }).length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import Header from "../../app/components/Header";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type HeaderProps = React.ComponentProps<typeof Header>;
|
||||
|
||||
componentTestSuite<HeaderProps>({
|
||||
component: Header,
|
||||
name: "Header",
|
||||
// Header has no props; it reads from routing and config.
|
||||
props: {} as HeaderProps,
|
||||
requiredProps: [],
|
||||
primaryRole: "banner",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import HeroBanner from "../../app/components/HeroBanner";
|
||||
import {
|
||||
componentTestSuite,
|
||||
ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type HeroBannerProps = React.ComponentProps<typeof HeroBanner>;
|
||||
|
||||
const baseProps: HeroBannerProps = {
|
||||
title: "Welcome",
|
||||
};
|
||||
|
||||
const config: ComponentTestSuiteConfig<HeroBannerProps> = {
|
||||
component: HeroBanner,
|
||||
name: "HeroBanner",
|
||||
props: baseProps,
|
||||
optionalProps: {
|
||||
subtitle: "Subtitle",
|
||||
description: "Description",
|
||||
ctaText: "CTA",
|
||||
ctaHref: "/link",
|
||||
},
|
||||
primaryRole: "region",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<HeroBannerProps>(config);
|
||||
|
||||
describe("HeroBanner (behavioral tests)", () => {
|
||||
it("renders title", () => {
|
||||
render(<HeroBanner title="Test Title" />);
|
||||
expect(
|
||||
screen.getByRole("heading", { name: "Test Title" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders subtitle when provided", () => {
|
||||
render(<HeroBanner title="Test" subtitle="Subtitle" />);
|
||||
expect(screen.getByRole("heading", { name: "Subtitle" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders hero image", () => {
|
||||
render(<HeroBanner title="Test" />);
|
||||
expect(
|
||||
screen.getByRole("img", { name: "Hero illustration" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders CTA button when provided", () => {
|
||||
render(
|
||||
<HeroBanner title="Test" ctaText="Get Started" ctaHref="/start" />,
|
||||
);
|
||||
expect(
|
||||
screen.getAllByRole("button", { name: "Get Started" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
import Input from "../../app/components/Input";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type InputProps = React.ComponentProps<typeof Input>;
|
||||
|
||||
componentTestSuite<InputProps>({
|
||||
component: Input,
|
||||
name: "Input",
|
||||
props: {
|
||||
label: "Test input",
|
||||
} as InputProps,
|
||||
requiredProps: ["label"],
|
||||
optionalProps: {
|
||||
placeholder: "Enter value",
|
||||
},
|
||||
primaryRole: "textbox",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: true,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
errorProps: { error: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import Logo from "../../app/components/Logo";
|
||||
import {
|
||||
componentTestSuite,
|
||||
ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type LogoProps = React.ComponentProps<typeof Logo>;
|
||||
|
||||
const baseProps: LogoProps = {};
|
||||
|
||||
const config: ComponentTestSuiteConfig<LogoProps> = {
|
||||
component: Logo,
|
||||
name: "Logo",
|
||||
props: baseProps,
|
||||
primaryRole: "link",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<LogoProps>(config);
|
||||
|
||||
describe("Logo (behavioral tests)", () => {
|
||||
it("renders as a link to home", () => {
|
||||
render(<Logo />);
|
||||
const logo = screen.getByRole("link", { name: /communityrule logo/i });
|
||||
expect(logo).toHaveAttribute("href", "/");
|
||||
expect(logo).toHaveAttribute("aria-label", "CommunityRule Logo");
|
||||
});
|
||||
|
||||
it("renders logo icon", () => {
|
||||
render(<Logo />);
|
||||
expect(
|
||||
screen.getByAltText("CommunityRule Logo Icon"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders text by default", () => {
|
||||
render(<Logo />);
|
||||
expect(screen.getByText("CommunityRule")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("hides text when showText is false", () => {
|
||||
render(<Logo showText={false} />);
|
||||
expect(screen.queryByText("CommunityRule")).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByAltText("CommunityRule Logo Icon"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders with different size variants", () => {
|
||||
const { rerender } = render(<Logo size="header" />);
|
||||
expect(screen.getByRole("link")).toBeInTheDocument();
|
||||
|
||||
rerender(<Logo size="footer" />);
|
||||
expect(screen.getByRole("link")).toBeInTheDocument();
|
||||
|
||||
rerender(<Logo size="homeHeaderMd" />);
|
||||
expect(screen.getByRole("link")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
import RadioButton from "../../app/components/RadioButton";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type RadioButtonProps = React.ComponentProps<typeof RadioButton>;
|
||||
|
||||
componentTestSuite<RadioButtonProps>({
|
||||
component: RadioButton,
|
||||
name: "RadioButton",
|
||||
props: {
|
||||
label: "Option A",
|
||||
checked: false,
|
||||
} as RadioButtonProps,
|
||||
requiredProps: [],
|
||||
optionalProps: {
|
||||
mode: "inverse",
|
||||
},
|
||||
primaryRole: "radio",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: false,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import RadioGroup from "../../app/components/RadioGroup";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type RadioGroupProps = React.ComponentProps<typeof RadioGroup>;
|
||||
|
||||
componentTestSuite<RadioGroupProps>({
|
||||
component: RadioGroup,
|
||||
name: "RadioGroup",
|
||||
props: {
|
||||
name: "example",
|
||||
value: "a",
|
||||
options: [
|
||||
{ value: "a", label: "Option A" },
|
||||
{ value: "b", label: "Option B" },
|
||||
],
|
||||
} as RadioGroupProps,
|
||||
requiredProps: [],
|
||||
primaryRole: "radiogroup",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import RelatedArticles from "../../app/components/RelatedArticles";
|
||||
import type { BlogPost } from "../../lib/content";
|
||||
|
||||
vi.mock("next/link", () => ({
|
||||
default: ({ children, href, ...props }: any) => (
|
||||
<a href={href} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("../../app/components/ContentThumbnailTemplate", () => ({
|
||||
default: ({ post }: { post: BlogPost }) => (
|
||||
<div data-testid={`thumbnail-${post.slug}`}>
|
||||
<a href={`/blog/${post.slug}`}>
|
||||
<h3>{post.frontmatter.title}</h3>
|
||||
</a>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("../../app/hooks", () => ({
|
||||
useIsMobile: () => false,
|
||||
}));
|
||||
|
||||
const mockPosts: BlogPost[] = [
|
||||
{
|
||||
slug: "article-1",
|
||||
frontmatter: {
|
||||
title: "Article 1",
|
||||
description: "Description 1",
|
||||
author: "Author",
|
||||
date: "2025-04-10",
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "article-2",
|
||||
frontmatter: {
|
||||
title: "Article 2",
|
||||
description: "Description 2",
|
||||
author: "Author",
|
||||
date: "2025-04-11",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe("RelatedArticles", () => {
|
||||
it("renders without crashing", () => {
|
||||
render(
|
||||
<RelatedArticles
|
||||
relatedPosts={mockPosts}
|
||||
currentPostSlug="current"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders related articles", () => {
|
||||
render(
|
||||
<RelatedArticles
|
||||
relatedPosts={mockPosts}
|
||||
currentPostSlug="current"
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByTestId("thumbnail-article-1")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("thumbnail-article-2")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("filters out current post", () => {
|
||||
render(
|
||||
<RelatedArticles
|
||||
relatedPosts={mockPosts}
|
||||
currentPostSlug="article-1"
|
||||
/>,
|
||||
);
|
||||
expect(screen.queryByTestId("thumbnail-article-1")).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId("thumbnail-article-2")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import SectionHeader from "../../app/components/SectionHeader";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type SectionHeaderProps = React.ComponentProps<typeof SectionHeader>;
|
||||
|
||||
componentTestSuite<SectionHeaderProps>({
|
||||
component: SectionHeader,
|
||||
name: "SectionHeader",
|
||||
props: {
|
||||
title: "Title",
|
||||
subtitle: "Subtitle",
|
||||
} as SectionHeaderProps,
|
||||
requiredProps: ["title", "subtitle"],
|
||||
primaryRole: "heading",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: false,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import Select from "../../app/components/Select";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type SelectProps = React.ComponentProps<typeof Select>;
|
||||
|
||||
componentTestSuite<SelectProps>({
|
||||
component: Select,
|
||||
name: "Select",
|
||||
props: {
|
||||
label: "Test Select",
|
||||
placeholder: "Select an option",
|
||||
options: [
|
||||
{ value: "option1", label: "Option 1" },
|
||||
{ value: "option2", label: "Option 2" },
|
||||
],
|
||||
} as SelectProps,
|
||||
requiredProps: ["options"],
|
||||
optionalProps: {
|
||||
size: "medium",
|
||||
},
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: true,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
errorProps: { error: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import Switch from "../../app/components/Switch";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type SwitchProps = React.ComponentProps<typeof Switch>;
|
||||
|
||||
componentTestSuite<SwitchProps>({
|
||||
component: Switch,
|
||||
name: "Switch",
|
||||
props: {
|
||||
label: "Test Switch",
|
||||
} as SwitchProps,
|
||||
requiredProps: [],
|
||||
optionalProps: {
|
||||
state: "focus",
|
||||
},
|
||||
primaryRole: "switch",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: false,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
import TextArea from "../../app/components/TextArea";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type TextAreaProps = React.ComponentProps<typeof TextArea>;
|
||||
|
||||
componentTestSuite<TextAreaProps>({
|
||||
component: TextArea,
|
||||
name: "TextArea",
|
||||
props: {
|
||||
label: "Description",
|
||||
value: "",
|
||||
} as TextAreaProps,
|
||||
requiredProps: ["label"],
|
||||
optionalProps: {
|
||||
placeholder: "Enter description",
|
||||
},
|
||||
primaryRole: "textbox",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: true,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
errorProps: { error: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import Toggle from "../../app/components/Toggle";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type ToggleProps = React.ComponentProps<typeof Toggle>;
|
||||
|
||||
componentTestSuite<ToggleProps>({
|
||||
component: Toggle,
|
||||
name: "Toggle",
|
||||
props: {
|
||||
label: "Notifications",
|
||||
checked: false,
|
||||
} as ToggleProps,
|
||||
requiredProps: [],
|
||||
primaryRole: "switch",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: false,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
import ToggleGroup from "../../app/components/ToggleGroup";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type ToggleGroupProps = React.ComponentProps<typeof ToggleGroup>;
|
||||
|
||||
componentTestSuite<ToggleGroupProps>({
|
||||
component: ToggleGroup,
|
||||
name: "ToggleGroup",
|
||||
props: {
|
||||
children: "Option",
|
||||
} as ToggleGroupProps,
|
||||
requiredProps: [],
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: false,
|
||||
errorState: false,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user