// ABOUTME: Unit tests for DayCell component.
// ABOUTME: Tests phase coloring, today highlighting, and click handling.
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import type { CyclePhase } from "@/types";
import { DayCell } from "./day-cell";
describe("DayCell", () => {
const baseProps = {
date: new Date("2026-01-15"),
cycleDay: 5,
phase: "FOLLICULAR" as CyclePhase,
isToday: false,
onClick: vi.fn(),
};
describe("rendering", () => {
it("renders the day number from date", () => {
render();
expect(screen.getByText("15")).toBeInTheDocument();
});
it("renders the cycle day label", () => {
render();
expect(screen.getByText("Day 5")).toBeInTheDocument();
});
it("renders as a button", () => {
render();
expect(screen.getByRole("button")).toBeInTheDocument();
});
it("renders cycle day 1 correctly", () => {
render();
expect(screen.getByText("Day 1")).toBeInTheDocument();
});
it("renders high cycle day numbers", () => {
render();
expect(screen.getByText("Day 28")).toBeInTheDocument();
});
});
describe("phase colors", () => {
it("applies blue background for MENSTRUAL phase", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-blue-100");
});
it("applies green background for FOLLICULAR phase", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-green-100");
});
it("applies purple background for OVULATION phase", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-purple-100");
});
it("applies yellow background for EARLY_LUTEAL phase", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-yellow-100");
});
it("applies red background for LATE_LUTEAL phase", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-red-100");
});
});
describe("today highlighting", () => {
it("does not have ring when isToday is false", () => {
render();
const button = screen.getByRole("button");
expect(button).not.toHaveClass("ring-2", "ring-black");
});
it("has ring-2 ring-black when isToday is true", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("ring-2", "ring-black");
});
it("maintains phase color when isToday is true", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-purple-100");
expect(button).toHaveClass("ring-2", "ring-black");
});
});
describe("click handling", () => {
it("calls onClick when clicked", () => {
const onClick = vi.fn();
render();
const button = screen.getByRole("button");
fireEvent.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
it("does not throw when onClick is undefined", () => {
render();
const button = screen.getByRole("button");
expect(() => fireEvent.click(button)).not.toThrow();
});
it("calls onClick once per click", () => {
const onClick = vi.fn();
render();
const button = screen.getByRole("button");
fireEvent.click(button);
fireEvent.click(button);
fireEvent.click(button);
expect(onClick).toHaveBeenCalledTimes(3);
});
});
describe("styling", () => {
it("has rounded corners", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("rounded");
});
it("has padding", () => {
render();
const button = screen.getByRole("button");
expect(button).toHaveClass("p-2");
});
it("renders day number with font-medium", () => {
render();
const dayNumber = screen.getByText("15");
expect(dayNumber).toHaveClass("font-medium");
});
it("renders cycle day label in gray", () => {
render();
const cycleLabel = screen.getByText("Day 5");
expect(cycleLabel).toHaveClass("text-gray-500");
});
});
describe("date variations", () => {
it("renders single digit day", () => {
render();
expect(screen.getByText("5")).toBeInTheDocument();
});
it("renders last day of month", () => {
render();
expect(screen.getByText("31")).toBeInTheDocument();
});
it("renders first day of month", () => {
render();
expect(screen.getByText("1")).toBeInTheDocument();
});
});
});