import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { render } from "@testing-library/react";
import { Button, ButtonSizes, ButtonVariants, ButtonColors, getButtonClasses } from "./button";
describe("Button Component", () => {
const originalEnv = process.env;
beforeEach(() => {
process.env = { ...originalEnv };
});
afterEach(() => {
process.env = originalEnv;
});
describe("Component Rendering", () => {
it("should render button with children", () => {
const { getByText } = render();
expect(getByText("Click me")).toBeTruthy();
});
it("should apply custom className", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button?.className).toContain("custom-class");
});
it("should pass through native button props", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button?.disabled).toBe(true);
});
});
describe("Button Variants", () => {
it("should render primary variant by default", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
// Primary should have background color
expect(button?.className).toMatch(/bg-/);
});
it("should render secondary variant", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
// Secondary should have border
expect(button?.className).toMatch(/border/);
});
it("should render all variant types", () => {
const variants = [ButtonVariants.Primary, ButtonVariants.Secondary, ButtonVariants.Destructive];
variants.forEach((variant) => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
});
});
});
describe("Button Sizes", () => {
it("should render small size by default", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
// Should have padding styles
expect(button?.className).toMatch(/p[xy]?-/);
});
it("should render large size", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
// Should have padding styles
expect(button?.className).toMatch(/p[xy]?-/);
});
it("should render all size types", () => {
const sizes = [ButtonSizes.Small, ButtonSizes.Large];
sizes.forEach((size) => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
});
});
});
describe("Button Colors", () => {
it("should render primary color by default", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
// Should have background color
expect(button?.className).toMatch(/bg-/);
});
it("should render warn color", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
// Should have background color
expect(button?.className).toMatch(/bg-/);
});
it("should render all color types", () => {
const colors = [ButtonColors.Neutral, ButtonColors.Primary, ButtonColors.Warn];
colors.forEach((color) => {
const { container } = render();
const button = container.querySelector("button");
expect(button).toBeTruthy();
});
});
});
describe("Theme Integration", () => {
it("should apply theme-based roundness", () => {
const { container } = render();
const button = container.querySelector("button");
// Should have some roundness class applied
expect(button?.className).toBeTruthy();
expect(button?.className).toMatch(/rounded/);
});
it("should completely override theme roundness with custom roundness prop", () => {
// Set theme to have full roundness
process.env.NEXT_PUBLIC_THEME_ROUNDNESS = "full";
const customRoundness = "custom-round-test";
const { container } = render();
const button = container.querySelector("button");
// Should contain the custom roundness
expect(button?.className).toContain(customRoundness);
// The custom prop completely replaces theme roundness
expect(button).toBeTruthy();
});
it("should change appearance when theme changes", () => {
// Default theme
const { container: container1 } = render();
const button1 = container1.querySelector("button");
const defaultClasses = button1?.className;
// Change theme
process.env.NEXT_PUBLIC_THEME_ROUNDNESS = "full";
const { container: container2 } = render();
const button2 = container2.querySelector("button");
// Classes should be present (we don't check exact values)
expect(defaultClasses).toBeTruthy();
expect(button2?.className).toBeTruthy();
});
});
describe("getButtonClasses", () => {
it("should return valid class string", () => {
const classes = getButtonClasses(ButtonSizes.Small, ButtonVariants.Primary, ButtonColors.Primary);
expect(typeof classes).toBe("string");
expect(classes.length).toBeGreaterThan(0);
});
it("should include custom roundness classes", () => {
const customRoundness = "rounded-2xl";
const classes = getButtonClasses(ButtonSizes.Small, ButtonVariants.Primary, ButtonColors.Primary, customRoundness);
expect(classes).toContain(customRoundness);
});
it("should include appearance classes", () => {
const appearance = "shadow-lg";
const classes = getButtonClasses(
ButtonSizes.Small,
ButtonVariants.Primary,
ButtonColors.Primary,
"rounded-md",
appearance,
);
expect(classes).toContain(appearance);
});
it("should generate different classes for different variants", () => {
const primaryClasses = getButtonClasses(ButtonSizes.Small, ButtonVariants.Primary, ButtonColors.Primary);
const secondaryClasses = getButtonClasses(ButtonSizes.Small, ButtonVariants.Secondary, ButtonColors.Primary);
expect(primaryClasses).not.toBe(secondaryClasses);
});
it("should generate different classes for different sizes", () => {
const smallClasses = getButtonClasses(ButtonSizes.Small, ButtonVariants.Primary, ButtonColors.Primary);
const largeClasses = getButtonClasses(ButtonSizes.Large, ButtonVariants.Primary, ButtonColors.Primary);
expect(smallClasses).not.toBe(largeClasses);
});
});
describe("Accessibility", () => {
it("should have type='button' by default", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button?.type).toBe("button");
});
it("should support disabled state", () => {
const { container } = render();
const button = container.querySelector("button");
expect(button?.disabled).toBe(true);
// Should have disabled styles
expect(button?.className).toMatch(/disabled:/);
});
});
});