import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, it, expect, vi } from "vitest"; import RadioButton from "../../app/components/RadioButton"; describe("RadioButton", () => { it("renders with default props", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toBeInTheDocument(); expect(radioButton).toHaveAttribute("aria-checked", "false"); }); it("renders with label", () => { render(); expect(screen.getByText("Test Radio")).toBeInTheDocument(); }); it("shows checked state", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-checked", "true"); }); it("calls onChange when clicked", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( , ); const radioButton = screen.getByRole("radio"); await user.click(radioButton); expect(handleChange).toHaveBeenCalledWith({ checked: true, value: undefined, }); }); it("calls onChange with value when clicked", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( , ); const radioButton = screen.getByRole("radio"); await user.click(radioButton); expect(handleChange).toHaveBeenCalledWith({ checked: true, value: "test-value", }); }); it("does not call onChange when clicking already checked radio button", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( , ); const radioButton = screen.getByRole("radio"); await user.click(radioButton); // Radio buttons should not be unchecked by clicking them again expect(handleChange).not.toHaveBeenCalled(); }); it("handles keyboard activation", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( , ); const radioButton = screen.getByRole("radio"); radioButton.focus(); await user.keyboard(" "); expect(handleChange).toHaveBeenCalledWith({ checked: true, value: undefined, }); }); it("handles Enter key activation", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( , ); const radioButton = screen.getByRole("radio"); await user.click(radioButton); // Focus the element first await user.keyboard("{Enter}"); expect(handleChange).toHaveBeenCalledWith({ checked: true, value: undefined, }); }); it("applies standard mode classes", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveClass( "outline-[var(--color-border-default-tertiary)]", ); }); it("applies inverse mode classes", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveClass( "outline-[var(--color-border-inverse-primary)]", ); }); it("applies focus state classes", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveClass("focus:outline"); }); it("applies hover state classes", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveClass("hover:outline"); }); it("renders hidden input for form submission", () => { render( , ); const hiddenInput = screen.getByDisplayValue("test-value"); expect(hiddenInput).toBeInTheDocument(); expect(hiddenInput).toHaveAttribute("type", "radio"); expect(hiddenInput).toHaveAttribute("name", "test-radio"); expect(hiddenInput).toBeChecked(); }); it("applies custom className", () => { render(); const label = screen.getByText("Custom Radio").closest("label"); expect(label).toHaveClass("custom-class"); }); it("generates unique ID when not provided", () => { render(); render(); const radioButtons = screen.getAllByRole("radio"); expect(radioButtons[0]).toHaveAttribute("id"); expect(radioButtons[1]).toHaveAttribute("id"); expect(radioButtons[0].id).not.toBe(radioButtons[1].id); }); it("uses provided ID", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("id", "custom-id"); }); it("associates label with radio button for accessibility", () => { render(); const radioButton = screen.getByRole("radio"); const labelId = radioButton.getAttribute("aria-labelledby"); expect(labelId).toBeTruthy(); const labelElement = document.getElementById(labelId); expect(labelElement).toHaveTextContent("Accessible Radio"); }); it("uses aria-label when provided", () => { render(); const radioButton = screen.getByRole("radio"); expect(radioButton).toHaveAttribute("aria-label", "Custom Aria Label"); }); it("shows dot indicator when checked", () => { render( , ); const dot = screen.getByRole("radio").querySelector("div"); expect(dot).toHaveClass("w-[16px]", "h-[16px]", "rounded-full"); }); it("hides dot indicator when unchecked", () => { render( , ); const dot = screen.getByRole("radio").querySelector("div"); // Check if the dot has transparent background or no background color set const computedStyle = window.getComputedStyle(dot); const backgroundColor = computedStyle.backgroundColor; // The dot should either be transparent or have no background color expect( backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)" || backgroundColor === "", ).toBe(true); }); });