import React from 'react' import { render, screen, fireEvent } from '@testing-library/react' import '@testing-library/jest-dom' import { Switch } from '../switch' describe('Switch Component', () => { describe('Basic Rendering', () => { it('renders correctly with default props', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toBeInTheDocument() expect(switchElement).toHaveClass('peer') expect(switchElement).toHaveClass('inline-flex') expect(switchElement).toHaveClass('cursor-pointer') expect(switchElement).toHaveClass('rounded-full') }) it('applies custom className', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('custom-switch') }) it('forwards ref correctly', () => { const ref = React.createRef() render() expect(ref.current).toBeInstanceOf(HTMLButtonElement) }) it('has correct role', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveAttribute('role', 'switch') }) it('maintains displayName', () => { expect(Switch.displayName).toBe('Switch') }) }) describe('Sizes', () => { it('renders sm size correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('h-4', 'w-8') }) it('renders md size correctly (default)', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('h-6', 'w-11') }) it('renders lg size correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('h-7', 'w-14') }) it('uses md size as default', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('h-6', 'w-11') }) }) describe('Variants', () => { it('renders primary variant correctly (default)', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('data-[state=checked]:bg-primary') }) it('renders success variant correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('data-[state=checked]:bg-success') }) it('renders warning variant correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('data-[state=checked]:bg-warning') }) it('renders danger variant correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('data-[state=checked]:bg-error') }) it('renders secondary variant correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('data-[state=checked]:bg-accent') }) it('uses primary variant as default', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('data-[state=checked]:bg-primary') }) }) describe('States', () => { it('renders unchecked state correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveAttribute('data-state', 'unchecked') expect(switchElement).toHaveAttribute('aria-checked', 'false') }) it('renders checked state correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveAttribute('data-state', 'checked') expect(switchElement).toHaveAttribute('aria-checked', 'true') }) it('renders disabled state correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toBeDisabled() expect(switchElement).toHaveClass('disabled:cursor-not-allowed') expect(switchElement).toHaveClass('disabled:opacity-50') }) it('handles controlled state', () => { const handleChange = jest.fn() render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveAttribute('aria-checked', 'true') }) }) describe('Loading State', () => { it('renders loading state correctly', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toBeDisabled() expect(switchElement).toHaveClass('opacity-80') expect(switchElement).toHaveClass('cursor-wait') }) it('shows loading spinner when loading', () => { render() const switchElement = screen.getByTestId('switch') const spinner = switchElement.querySelector('.animate-spin') expect(spinner).toBeInTheDocument() expect(spinner).toHaveClass('animate-spin') expect(spinner).toHaveClass('rounded-full') expect(spinner).toHaveClass('border-2') }) it('disables switch when loading', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toBeDisabled() }) it('combines loading with disabled prop', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toBeDisabled() }) }) describe('Icons and Description', () => { it('renders left icon correctly', () => { render(Left} data-testid="switch" />) expect(screen.getByText('Left')).toBeInTheDocument() const iconWrapper = screen.getByText('Left').parentElement expect(iconWrapper).toHaveClass('text-muted-foreground') }) it('renders right icon correctly', () => { render(Right} data-testid="switch" />) expect(screen.getByText('Right')).toBeInTheDocument() const iconWrapper = screen.getByText('Right').parentElement expect(iconWrapper).toHaveClass('text-muted-foreground') }) it('renders description correctly', () => { render() expect(screen.getByText('Switch description')).toBeInTheDocument() expect(screen.getByText('Switch description')).toHaveClass('text-sm') expect(screen.getByText('Switch description')).toHaveClass('text-muted-foreground') }) it('renders both icons and description together', () => { render( Left} rightIcon={Right} description="Description" data-testid="switch" /> ) expect(screen.getByText('Left')).toBeInTheDocument() expect(screen.getByText('Right')).toBeInTheDocument() expect(screen.getByText('Description')).toBeInTheDocument() }) it('does not render icons when not provided', () => { render() expect(screen.queryByText('Left')).not.toBeInTheDocument() expect(screen.queryByText('Right')).not.toBeInTheDocument() }) }) describe('Thumb Element', () => { it('renders thumb element', () => { render() const switchElement = screen.getByTestId('switch') const thumb = switchElement.querySelector('span[data-state]') expect(thumb).toBeInTheDocument() }) it('applies correct thumb size classes for sm', () => { render() const switchElement = screen.getByTestId('switch') const thumb = switchElement.querySelector('span[data-state]') expect(thumb).toHaveClass('h-3', 'w-3') }) it('applies correct thumb size classes for md', () => { render() const switchElement = screen.getByTestId('switch') const thumb = switchElement.querySelector('span[data-state]') expect(thumb).toHaveClass('h-5', 'w-5') }) it('applies correct thumb size classes for lg', () => { render() const switchElement = screen.getByTestId('switch') const thumb = switchElement.querySelector('span[data-state]') expect(thumb).toHaveClass('h-6', 'w-6') }) }) describe('Interactions', () => { it('handles click events', () => { const handleChange = jest.fn() render() const switchElement = screen.getByTestId('switch') fireEvent.click(switchElement) expect(handleChange).toHaveBeenCalledWith(true) }) it('does not trigger events when disabled', () => { const handleChange = jest.fn() render() const switchElement = screen.getByTestId('switch') fireEvent.click(switchElement) expect(handleChange).not.toHaveBeenCalled() }) it('does not trigger events when loading', () => { const handleChange = jest.fn() render() const switchElement = screen.getByTestId('switch') fireEvent.click(switchElement) expect(handleChange).not.toHaveBeenCalled() }) it('is focusable for keyboard navigation', () => { render() const switchElement = screen.getByTestId('switch') switchElement.focus() expect(switchElement).toHaveFocus() }) }) describe('Accessibility', () => { it('has correct ARIA attributes', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveAttribute('role', 'switch') expect(switchElement).toHaveAttribute('aria-checked', 'false') }) it('supports custom ARIA attributes', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveAttribute('aria-label', 'Toggle setting') }) it('has focus-visible styles', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('focus-visible:outline-none') expect(switchElement).toHaveClass('focus-visible:ring-2') expect(switchElement).toHaveClass('focus-visible:ring-ring') }) }) describe('Complex Combinations', () => { it('renders with all props correctly', () => { const handleChange = jest.fn() render( Left} rightIcon={Right} description="Toggle description" className="custom-class" data-testid="switch" /> ) const switchElement = screen.getByTestId('switch') expect(switchElement).toHaveClass('h-7', 'w-14') expect(switchElement).toHaveClass('data-[state=checked]:bg-success') expect(switchElement).toHaveClass('custom-class') expect(switchElement).toHaveAttribute('aria-checked', 'true') expect(screen.getByText('Left')).toBeInTheDocument() expect(screen.getByText('Right')).toBeInTheDocument() expect(screen.getByText('Toggle description')).toBeInTheDocument() }) it('handles loading with other props', () => { render( Left} description="Loading switch" data-testid="switch" /> ) const switchElement = screen.getByTestId('switch') expect(switchElement).toBeDisabled() expect(switchElement).toHaveClass('h-4', 'w-8') expect(switchElement).toHaveClass('data-[state=checked]:bg-error') expect(switchElement).toHaveClass('opacity-80') expect(screen.getByText('Left')).toBeInTheDocument() expect(screen.getByText('Loading switch')).toBeInTheDocument() }) }) describe('Edge Cases', () => { it('passes through HTML attributes', () => { render() const switchElement = screen.getByTestId('switch-test') expect(switchElement).toHaveAttribute('id', 'switch-1') }) it('handles empty string description', () => { render() const container = screen.getByTestId('switch').parentElement const description = container?.querySelector('.text-sm.text-muted-foreground') expect(description).not.toBeInTheDocument() }) it('handles null icons gracefully', () => { render() const switchElement = screen.getByTestId('switch') expect(switchElement).toBeInTheDocument() }) }) })