Add component tests for P3.11 (82 tests across 5 files)

- DecisionCard tests: 11 tests covering rendering, status icons, styling
- DataPanel tests: 18 tests covering biometrics display, null handling, styling
- NutritionPanel tests: 12 tests covering seeds, carbs, keto guidance display
- OverrideToggles tests: 18 tests covering toggle states, callbacks, styling
- DayCell tests: 23 tests covering phase coloring, today highlighting, click handling

Total tests now: 707 passing across 40 test files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 09:02:34 +00:00
parent 39198fdf8c
commit 267d45f98a
6 changed files with 874 additions and 23 deletions

View File

@@ -0,0 +1,190 @@
// 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(<DayCell {...baseProps} date={new Date("2026-01-15")} />);
expect(screen.getByText("15")).toBeInTheDocument();
});
it("renders the cycle day label", () => {
render(<DayCell {...baseProps} cycleDay={5} />);
expect(screen.getByText("Day 5")).toBeInTheDocument();
});
it("renders as a button", () => {
render(<DayCell {...baseProps} />);
expect(screen.getByRole("button")).toBeInTheDocument();
});
it("renders cycle day 1 correctly", () => {
render(<DayCell {...baseProps} cycleDay={1} />);
expect(screen.getByText("Day 1")).toBeInTheDocument();
});
it("renders high cycle day numbers", () => {
render(<DayCell {...baseProps} cycleDay={28} />);
expect(screen.getByText("Day 28")).toBeInTheDocument();
});
});
describe("phase colors", () => {
it("applies blue background for MENSTRUAL phase", () => {
render(<DayCell {...baseProps} phase="MENSTRUAL" />);
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-blue-100");
});
it("applies green background for FOLLICULAR phase", () => {
render(<DayCell {...baseProps} phase="FOLLICULAR" />);
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-green-100");
});
it("applies purple background for OVULATION phase", () => {
render(<DayCell {...baseProps} phase="OVULATION" />);
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-purple-100");
});
it("applies yellow background for EARLY_LUTEAL phase", () => {
render(<DayCell {...baseProps} phase="EARLY_LUTEAL" />);
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-yellow-100");
});
it("applies red background for LATE_LUTEAL phase", () => {
render(<DayCell {...baseProps} phase="LATE_LUTEAL" />);
const button = screen.getByRole("button");
expect(button).toHaveClass("bg-red-100");
});
});
describe("today highlighting", () => {
it("does not have ring when isToday is false", () => {
render(<DayCell {...baseProps} isToday={false} />);
const button = screen.getByRole("button");
expect(button).not.toHaveClass("ring-2", "ring-black");
});
it("has ring-2 ring-black when isToday is true", () => {
render(<DayCell {...baseProps} isToday={true} />);
const button = screen.getByRole("button");
expect(button).toHaveClass("ring-2", "ring-black");
});
it("maintains phase color when isToday is true", () => {
render(<DayCell {...baseProps} phase="OVULATION" isToday={true} />);
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(<DayCell {...baseProps} onClick={onClick} />);
const button = screen.getByRole("button");
fireEvent.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
});
it("does not throw when onClick is undefined", () => {
render(<DayCell {...baseProps} onClick={undefined} />);
const button = screen.getByRole("button");
expect(() => fireEvent.click(button)).not.toThrow();
});
it("calls onClick once per click", () => {
const onClick = vi.fn();
render(<DayCell {...baseProps} onClick={onClick} />);
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(<DayCell {...baseProps} />);
const button = screen.getByRole("button");
expect(button).toHaveClass("rounded");
});
it("has padding", () => {
render(<DayCell {...baseProps} />);
const button = screen.getByRole("button");
expect(button).toHaveClass("p-2");
});
it("renders day number with font-medium", () => {
render(<DayCell {...baseProps} date={new Date("2026-01-15")} />);
const dayNumber = screen.getByText("15");
expect(dayNumber).toHaveClass("font-medium");
});
it("renders cycle day label in gray", () => {
render(<DayCell {...baseProps} cycleDay={5} />);
const cycleLabel = screen.getByText("Day 5");
expect(cycleLabel).toHaveClass("text-gray-500");
});
});
describe("date variations", () => {
it("renders single digit day", () => {
render(<DayCell {...baseProps} date={new Date("2026-01-05")} />);
expect(screen.getByText("5")).toBeInTheDocument();
});
it("renders last day of month", () => {
render(<DayCell {...baseProps} date={new Date("2026-01-31")} />);
expect(screen.getByText("31")).toBeInTheDocument();
});
it("renders first day of month", () => {
render(<DayCell {...baseProps} date={new Date("2026-02-01")} />);
expect(screen.getByText("1")).toBeInTheDocument();
});
});
});