import React from "react";
import { SimpleCard } from "./index";
import { render, screen } from "@testing-library/react";
jest.mock("@shared/components/next-image", () => ({
NextImage: ({ src, alt, width, height, className }: any) => (
),
}));
jest.mock("@shared/components/text", () => ({
Text: ({ as: Tag = "span", children, className, style }: any) => (
{children}
),
}));
jest.mock("@shared/components/link", () => ({
Link: ({ children, href, className, ...rest }: any) => (
{children}
),
}));
jest.mock("@shared/components/material-icon", () => ({
MaterialIcon: ({ name, className }: any) => (
{name}
),
}));
jest.mock("../../button", () => ({
Button: ({ children, linkClassName, buttonLabel }: any) => (
),
}));
jest.mock("@shared/utils", () => ({
cx: (...args: any[]) => args.filter(Boolean).join(" "),
}));
jest.mock("@shared/utils/speed-card-bg", () => ({
SpeedCardBg: (color: string) => ``,
}));
describe("SimpleCard", () => {
const defaultCard = {
title: "Simple Card Title",
body: "Card body content",
image: "/image.jpg",
imageAlt: "Card image",
};
describe("Rendering", () => {
it("renders the section element", () => {
const { container } = render();
expect(container.querySelector("section")).toBeInTheDocument();
});
it("renders title", () => {
render();
expect(screen.getByText("Simple Card Title")).toBeInTheDocument();
});
it("renders body", () => {
render();
expect(screen.getByText("Card body content")).toBeInTheDocument();
});
it("renders aria-labelledby with title", () => {
const { container } = render();
expect(container.querySelector("section")).toHaveAttribute(
"aria-labelledby",
"callout-Simple Card Title"
);
});
it("does not set aria-labelledby when no title", () => {
const { container } = render();
expect(container.querySelector("section")).not.toHaveAttribute(
"aria-labelledby"
);
});
});
describe("Image views", () => {
it("renders icon-sized image by default when image is provided", () => {
render();
const img = screen.getByTestId("next-image");
expect(img).toBeInTheDocument();
});
it("renders full image when imageView is 'full'", () => {
const card = { ...defaultCard, imageView: "full" as const };
render();
expect(screen.getByTestId("next-image")).toBeInTheDocument();
});
it("renders margin image when imageView is 'margin'", () => {
const card = { ...defaultCard, imageView: "margin" as const };
render();
expect(screen.getByTestId("next-image")).toBeInTheDocument();
});
it("renders standard-sized image", () => {
const card = {
...defaultCard,
imageView: "standard" as const,
imageWidth: 120,
imageHeight: 120,
};
render();
const img = screen.getByTestId("next-image");
expect(img).toHaveAttribute("width", "120");
expect(img).toHaveAttribute("height", "120");
});
it("renders inset image view", () => {
const card = { ...defaultCard, imageView: "inset" as const };
render();
expect(screen.getByTestId("next-image")).toBeInTheDocument();
});
it("does not render image when image is not provided", () => {
render();
expect(screen.queryByTestId("next-image")).not.toBeInTheDocument();
});
});
describe("CTA", () => {
it("renders CTA button when cta is provided", () => {
const card = {
...defaultCard,
cta: { buttonLabel: "Learn More", href: "/learn" },
};
render();
expect(screen.getByTestId("cta-button")).toBeInTheDocument();
});
it("does not render CTA when not provided", () => {
render();
expect(screen.queryByTestId("cta-button")).not.toBeInTheDocument();
});
it("wraps title in link when cta has href", () => {
const card = {
...defaultCard,
cta: { buttonLabel: "Click", href: "/click" },
};
render();
const titleLink = screen.getByText("Simple Card Title").closest("a");
expect(titleLink).toHaveAttribute("href", "/click");
});
});
describe("CTA Bottom (location CTA)", () => {
it("renders ctaBottom link when provided", () => {
const card = {
...defaultCard,
ctaBottom: { title: "Location", href: "/location" },
};
render();
expect(screen.getByText("Location")).toBeInTheDocument();
});
it("does not render ctaBottom when not provided", () => {
render();
expect(screen.queryByText("location_on")).not.toBeInTheDocument();
});
it("renders location_on icon with ctaBottom", () => {
const card = {
...defaultCard,
ctaBottom: { title: "Store", href: "/store" },
};
render();
expect(screen.getByText("location_on")).toBeInTheDocument();
});
});
describe("Working hours and phone", () => {
it("renders working hours table", () => {
const card = {
...defaultCard,
workingHours: ["Mon-Fri|9am-5pm", "Sat|10am-2pm"],
};
render();
expect(screen.getByText("Mon-Fri")).toBeInTheDocument();
expect(screen.getByText("9am-5pm")).toBeInTheDocument();
});
it("renders phone numbers", () => {
const card = {
...defaultCard,
phoneNumber: ["(555) 123-4567"],
};
render();
expect(screen.getByText("(555) 123-4567")).toBeInTheDocument();
});
it("creates tel: link for phone numbers", () => {
const card = {
...defaultCard,
phoneNumber: ["(555) 123-4567"],
};
render();
const phoneLink = screen.getByText("(555) 123-4567").closest("a");
expect(phoneLink).toHaveAttribute("href", "tel:5551234567");
});
});
describe("Rich text", () => {
it("renders richText when provided", () => {
const card = { ...defaultCard, richText: "Rich text content" };
render();
expect(screen.getByText("Rich text content")).toBeInTheDocument();
});
});
describe("Title location", () => {
it("renders titleLocation when provided", () => {
const card = { ...defaultCard, titleLocation: "Downtown" };
render();
expect(screen.getByText("Downtown")).toBeInTheDocument();
});
});
describe("Shadow", () => {
it("applies shadow class when shadow is true", () => {
const card = { ...defaultCard, shadow: true };
const { container } = render();
expect(container.querySelector("section")?.className).toContain(
"shadow-card"
);
});
});
describe("Background colors", () => {
it("applies background color class from map", () => {
const card = { ...defaultCard, backgroundColor: "blue" };
const { container } = render();
expect(container.querySelector("section")?.className).toContain(
"bg-fill-brand"
);
});
it("applies dynamic background color when applyCardBackgroundColor is true", () => {
const card = {
...defaultCard,
applyCardBackgroundColor: true,
backgroundColor: "#FF0000",
imageView: "icon" as const,
};
const { container } = render();
const section = container.querySelector("section") as HTMLElement;
// jsdom doesn't fully support CSS variables in style, check the attribute directly
const styleAttr = section.getAttribute("style") || "";
expect(styleAttr).toContain("--scc-bg");
});
it("applies dynamic text color when applyCardBackgroundColor is true", () => {
const card = {
...defaultCard,
applyCardBackgroundColor: true,
textColor: "#FFFFFF",
imageView: "icon" as const,
};
const { container } = render();
const section = container.querySelector("section") as HTMLElement;
const styleAttr = section.getAttribute("style") || "";
expect(styleAttr).toContain("--scc-fg");
});
});
describe("Background image (pinwheel)", () => {
it("applies background image when showBackgroundImage and pinwheelColor", () => {
const card = {
...defaultCard,
applyCardBackgroundColor: true,
backgroundColor: "#000",
showBackgroundImage: true,
pinwheelColor: "Blue-#307998",
imageView: "icon" as const,
};
const { container } = render();
const section = container.querySelector("section") as HTMLElement;
expect(section.style.backgroundImage).toContain("data:image/svg+xml");
});
});
describe("Layout props", () => {
it("applies lgWidth class", () => {
const { container } = render(
);
expect(container.querySelector("section")?.className).toContain(
"lg:w-1/3"
);
});
it("applies mdWidth class", () => {
const { container } = render(
);
expect(container.querySelector("section")?.className).toContain(
"md:w-1/2"
);
});
it("applies custom className", () => {
const { container } = render(
);
expect(container.querySelector("section")?.className).toContain(
"custom-class"
);
});
it("applies custom style", () => {
const { container } = render(
);
const section = container.querySelector("section") as HTMLElement;
expect(section.style.margin).toBe("10px");
});
});
describe("Image alignment", () => {
it("uses iconAlignment for icon position", () => {
const card = {
...defaultCard,
iconAlignment: "center" as const,
imageView: "icon" as const,
};
render();
const iconWrapper = screen.getByTestId("next-image").parentElement;
expect(iconWrapper?.style.justifyContent).toBe("center");
});
it("falls back to imageAlignment when iconAlignment not set", () => {
const card = {
...defaultCard,
imageAlignment: "right" as const,
imageView: "icon" as const,
};
render();
const iconWrapper = screen.getByTestId("next-image").parentElement;
expect(iconWrapper?.style.justifyContent).toBe("right");
});
});
});