Testing
styled-cva components are standard React components that render HTML elements with specific class names. This makes them easy to test using standard testing tools like React Testing Library , Vitest , or Bun Test .
The primary goal when testing styled-cva components is to verify that:
- The component renders the correct HTML element.
- The correct classes are applied based on the props (variants).
Setup
We recommend using React Testing Library for rendering components and asserting on the DOM.
If you are using Vitest or Jest, you should also install @testing-library/jest-dom to get useful matchers like toHaveClass.
# Install testing dependencies
npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom
# or
bun add -d vitest @testing-library/react @testing-library/jest-dom jsdomIf you are using Bun Test, you can use it directly, though jest-dom matchers might require additional configuration or you can check attributes directly.
Basic Component Testing
Here is a simple example of testing a styled button to ensure it renders with the base classes.
// Button.tsx
// Button.test.tsx
import { render, screen } from "@testing-library/react";
import tw from "@styled-cva/react";
import { expect, test } from "vitest";
import { Button } from "./Button";
export const Button = tw.button`px-4 py-2 bg-blue-500 text-white rounded`;
test("renders with default styles", () => {
render(<Button>Click me</Button>);
const button = screen.getByRole("button", { name: /click me/i });
expect(button).toBeInTheDocument();
expect(button).toHaveClass(
"px-4",
"py-2",
"bg-blue-500",
"text-white",
"rounded",
);
});Testing Variants
When using .cva(), you want to ensure that passing different variant props results in the correct class names being applied.
// Alert.tsx
// Alert.test.tsx
import { render, screen } from "@testing-library/react";
import tw from "@styled-cva/react";
import { expect, test } from "vitest";
import { Alert } from "./Alert";
export const Alert = tw.div.cva("p-4 rounded border", {
variants: {
$intent: {
info: "bg-blue-100 border-blue-500 text-blue-700",
success: "bg-green-100 border-green-500 text-green-700",
danger: "bg-red-100 border-red-500 text-red-700",
},
},
defaultVariants: {
$intent: "info",
},
});
test("renders info variant by default", () => {
render(<Alert>Info message</Alert>);
const alert = screen.getByText("Info message");
expect(alert).toHaveClass("bg-blue-100", "border-blue-500");
});
test("renders success variant", () => {
render(<Alert $intent="success">Success message</Alert>);
const alert = screen.getByText("Success message");
expect(alert).toHaveClass("bg-green-100", "border-green-500");
});Snapshot Testing
Snapshot testing is particularly useful for styled components as it captures the entire structure and class list, allowing you to catch unintended style changes.
// Card.test.tsx
import { render } from "@testing-library/react";
import { expect, test } from "vitest";
import { Card } from "./Card";
test("renders correctly", () => {
const { container } = render(<Card $variant="outlined">Content</Card>);
expect(container.firstChild).toMatchSnapshot();
});Polymorphic Components
If you use the $as prop to change the rendered element, you can verify the tag name in your tests.
test("renders as a link when $as prop is provided", () => {
render(
<Button $as="a" href="/login">
Login
</Button>,
);
const link = screen.getByRole("link", { name: /login/i });
expect(link).toBeInTheDocument();
expect(link.tagName).toBe("A");
expect(link).toHaveAttribute("href", "/login");
});