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 RadioGroup from "../../app/components/RadioGroup"; describe("RadioGroup", () => { const defaultOptions = [ { value: "option1", label: "Option 1" }, { value: "option2", label: "Option 2" }, { value: "option3", label: "Option 3" }, ]; it("renders with default props", () => { render(); const radioGroup = screen.getByRole("radiogroup"); expect(radioGroup).toBeInTheDocument(); const radioButtons = screen.getAllByRole("radio"); expect(radioButtons).toHaveLength(3); }); it("renders all options", () => { render(); expect(screen.getByText("Option 1")).toBeInTheDocument(); expect(screen.getByText("Option 2")).toBeInTheDocument(); expect(screen.getByText("Option 3")).toBeInTheDocument(); }); it("shows selected option", () => { render(); const radioButtons = screen.getAllByRole("radio"); expect(radioButtons[0]).toHaveAttribute("aria-checked", "false"); expect(radioButtons[1]).toHaveAttribute("aria-checked", "true"); expect(radioButtons[2]).toHaveAttribute("aria-checked", "false"); }); it("calls onChange when option is selected", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( ); const option2 = screen.getByText("Option 2").closest("label"); await user.click(option2); expect(handleChange).toHaveBeenCalledWith({ value: "option2" }); }); it("updates selection when different option is clicked", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( ); // Click option 3 const option3 = screen.getByText("Option 3").closest("label"); await user.click(option3); expect(handleChange).toHaveBeenCalledWith({ value: "option3" }); }); it("handles keyboard navigation", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( ); const radioButtons = screen.getAllByRole("radio"); radioButtons[1].focus(); await user.keyboard(" "); expect(handleChange).toHaveBeenCalledWith({ value: "option2" }); }); it("handles Enter key activation", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( ); const radioButtons = screen.getAllByRole("radio"); await user.click(radioButtons[2]); await user.keyboard("{Enter}"); expect(handleChange).toHaveBeenCalledWith({ value: "option3" }); }); it("applies standard mode to all radio buttons", () => { render(); const radioButtons = screen.getAllByRole("radio"); radioButtons.forEach((button) => { expect(button).toHaveClass( "outline-[var(--color-border-default-tertiary)]" ); }); }); it("applies inverse mode to all radio buttons", () => { render(); const radioButtons = screen.getAllByRole("radio"); radioButtons.forEach((button) => { expect(button).toHaveClass( "outline-[var(--color-border-inverse-primary)]" ); }); }); it("applies state to all radio buttons", () => { render(); const radioButtons = screen.getAllByRole("radio"); radioButtons.forEach((button) => { expect(button).toHaveClass("focus:outline"); }); }); it("generates unique group name when not provided", () => { render(); render(); const hiddenInputs = screen.getAllByRole("radio", { hidden: true }); const names = hiddenInputs.map((input) => input.getAttribute("name")); // Should have unique names const uniqueNames = new Set(names); expect(uniqueNames.size).toBeGreaterThan(1); }); it("uses provided name for all radio buttons", () => { render(); const hiddenInputs = screen.getAllByDisplayValue("option1"); hiddenInputs.forEach((input) => { expect(input).toHaveAttribute("name", "test-group"); }); }); it("applies custom className to container", () => { render(); const radioGroup = screen.getByRole("radiogroup"); expect(radioGroup).toHaveClass("custom-group"); }); it("passes aria-label to radiogroup", () => { render( ); const radioGroup = screen.getByRole("radiogroup"); expect(radioGroup).toHaveAttribute("aria-label", "Test Radio Group"); }); it("handles empty options array", () => { render(); const radioGroup = screen.getByRole("radiogroup"); expect(radioGroup).toBeInTheDocument(); const radioButtons = screen.queryAllByRole("radio"); expect(radioButtons).toHaveLength(0); }); it("handles options with ariaLabel", () => { const optionsWithAria = [ { value: "option1", label: "Option 1", ariaLabel: "First Option" }, { value: "option2", label: "Option 2", ariaLabel: "Second Option" }, ]; render(); const radioButtons = screen.getAllByRole("radio"); expect(radioButtons[0]).toHaveAttribute("aria-label", "First Option"); expect(radioButtons[1]).toHaveAttribute("aria-label", "Second Option"); }); it("maintains selection state correctly", () => { const { rerender } = render( ); let radioButtons = screen.getAllByRole("radio"); expect(radioButtons[0]).toHaveAttribute("aria-checked", "true"); rerender(); radioButtons = screen.getAllByRole("radio"); expect(radioButtons[0]).toHaveAttribute("aria-checked", "false"); expect(radioButtons[2]).toHaveAttribute("aria-checked", "true"); }); it("does not call onChange when clicking already selected option", async () => { const user = userEvent.setup(); const handleChange = vi.fn(); render( ); const option2 = screen.getByText("Option 2").closest("label"); await user.click(option2); // Should not call onChange since it's already selected expect(handleChange).not.toHaveBeenCalled(); }); });