import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; jest.mock('lucide-react', () => ({ CheckIcon: () =>
, ChevronDownIcon: () =>
, ChevronUpIcon: () =>
, })); jest.mock('@radix-ui/react-select', () => ({ Root: ({ children, ...props }: any) => (
{children}
), Trigger: ({ children, className, ...props }: any) => ( ), Content: ({ children, ...props }: any) => (
{children}
), Viewport: ({ children, ...props }: any) => (
{children}
), Item: ({ children, ...props }: any) => (
{children}
), ItemText: ({ children, ...props }: any) => ( {children} ), ItemIndicator: ({ children, ...props }: any) => ( {children} ), Group: ({ children, ...props }: any) => (
{children}
), Label: ({ children, ...props }: any) => (
{children}
), Separator: ({ ...props }: any) => (
), ScrollUpButton: ({ children, ...props }: any) => ( ), ScrollDownButton: ({ children, ...props }: any) => ( ), Icon: ({ children, ...props }: any) => ( {children} ), Value: ({ placeholder, children, ...props }: any) => ( {children || placeholder} ), Portal: ({ children, ...props }: any) => (
{children}
), __esModule: true, })); import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, } from '../../../../src/renderer/components/ui/select'; describe('Select Components', () => { const mockOnValueChange = jest.fn(); const mockOnOpenChange = jest.fn(); describe('Select Root', () => { test('should render with default props', () => { render( ); expect(screen.getByTestId('radix-select-root')).toBeInTheDocument(); expect(screen.getByTestId('radix-select-trigger')).toBeInTheDocument(); expect(screen.getByTestId('radix-select-content')).toBeInTheDocument(); }); test('should handle value changes', async () => { const user = userEvent.setup(); render( ); const trigger = screen.getByTestId('radix-select-trigger'); await user.click(trigger); const item = screen.getByTestId('radix-select-item'); await user.click(item); expect(screen.getByTestId('radix-select-root')).toHaveAttribute( 'value', 'option1' ); }); test('should handle open state changes', () => { render( ); expect(screen.getByTestId('radix-select-root')).toHaveAttribute( 'open', 'true' ); }); }); describe('SelectTrigger', () => { test('should render with default size', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('data-size', 'default'); expect(trigger).toHaveClass('data-[size=default]:h-9'); }); test('should render with small size', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('data-size', 'sm'); expect(trigger).toHaveClass('data-[size=sm]:h-8'); }); test('should apply custom className', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveClass('custom-class'); }); test('should render chevron icon', () => { render( ); expect(screen.getByTestId('chevron-down-icon')).toBeInTheDocument(); }); test('should forward additional props', () => { render( ); const trigger = screen.getByTestId('custom-trigger'); expect(trigger).toBeDisabled(); }); }); describe('SelectValue', () => { test('should render placeholder when no value is selected', () => { render( ); expect(screen.getByTestId('radix-select-value')).toBeInTheDocument(); }); test('should render children when provided', () => { render( ); expect(screen.getByText('Custom content')).toBeInTheDocument(); }); test('should handle placeholder attribute', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('data-placeholder', 'true'); }); }); describe('SelectContent', () => { test('should render content when open', () => { render( ); expect(screen.getByTestId('radix-select-content')).toBeInTheDocument(); }); test('should not render content when closed', () => { render( ); expect( screen.queryByTestId('radix-select-content') ).not.toBeInTheDocument(); }); test('should forward props to content', () => { render( ); const content = screen.getByTestId('radix-select-content'); expect(content).toHaveClass('custom-content'); expect(content).toHaveAttribute('position', 'popper'); }); }); describe('SelectItem', () => { test('should render item with value and text', () => { render( ); expect(screen.getByTestId('radix-select-item')).toHaveAttribute( 'value', 'option1' ); expect(screen.getByTestId('radix-select-item-text')).toHaveTextContent( 'Option 1' ); }); test('should render check icon for selected item', () => { render( ); expect(screen.getByTestId('check-icon')).toBeInTheDocument(); }); test('should handle disabled state', () => { render( ); const item = screen.getByTestId('radix-select-item'); expect(item).toHaveAttribute('disabled', ''); }); }); describe('SelectGroup', () => { test('should render group with items', () => { render( ); expect(screen.getByTestId('radix-select-group')).toBeInTheDocument(); expect(screen.getByTestId('radix-select-label')).toHaveTextContent( 'Group 1' ); expect(screen.getAllByTestId('radix-select-item')).toHaveLength(2); }); }); describe('SelectLabel', () => { test('should render label', () => { render( ); expect(screen.getByTestId('radix-select-label')).toHaveTextContent( 'Choose an option' ); }); }); describe('SelectSeparator', () => { test('should render separator', () => { render( ); expect(screen.getByTestId('radix-select-separator')).toBeInTheDocument(); }); }); describe('SelectScrollButtons', () => { test('should render scroll buttons', () => { render( ); expect(screen.getByTestId('radix-select-scroll-up')).toBeInTheDocument(); expect( screen.getByTestId('radix-select-scroll-down') ).toBeInTheDocument(); }); test('should render chevron icons in scroll buttons', () => { render( ); expect(screen.getByTestId('chevron-up-icon')).toBeInTheDocument(); expect(screen.getByTestId('chevron-down-icon')).toBeInTheDocument(); }); }); describe('Integration Tests', () => { test('should handle complete select workflow', async () => { const user = userEvent.setup(); const onValueChange = jest.fn(); render( ); expect(screen.getByTestId('radix-select-trigger')).toBeInTheDocument(); expect( screen.queryByTestId('radix-select-content') ).not.toBeInTheDocument(); expect(screen.getByTestId('radix-select-root')).toBeInTheDocument(); }); test('should handle complex select with multiple groups and separators', () => { render( ); expect(screen.getAllByTestId('radix-select-group')).toHaveLength(3); expect(screen.getAllByTestId('radix-select-separator')).toHaveLength(2); expect(screen.getAllByTestId('radix-select-label')).toHaveLength(3); expect(screen.getAllByTestId('radix-select-item')).toHaveLength(6); }); }); describe('Accessibility', () => { test('should have proper ARIA attributes', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('aria-label', 'Select option'); }); test('should support disabled state', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toBeDisabled(); }); test('should handle required state', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('aria-required', 'true'); }); }); describe('Styling and Classes', () => { test('should apply default styling classes', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(mockCn).toHaveBeenCalledWith( expect.stringContaining('border-input'), expect.stringContaining('focus-visible:border-ring'), expect.stringContaining('data-[size=default]:h-9'), expect.anything() ); }); test('should apply size-specific classes', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(mockCn).toHaveBeenCalledWith( expect.stringContaining('data-[size=sm]:h-8'), expect.anything() ); }); test('should merge custom classes with default classes', () => { mockCn.mockClear(); render( ); expect(mockCn).toHaveBeenCalled(); const callArgs = mockCn.mock.calls[0]; expect(callArgs).toContain('custom-class'); expect(callArgs.some((arg) => arg && arg.includes('border-input'))).toBe( true ); }); }); describe('Error States', () => { test('should handle invalid aria state', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('aria-invalid', 'true'); }); test('should apply error styling for invalid state', () => { mockCn.mockClear(); render( ); expect(mockCn).toHaveBeenCalledWith( expect.stringContaining('aria-invalid:ring-destructive/20'), expect.stringContaining('dark:aria-invalid:ring-destructive/40'), expect.stringContaining('aria-invalid:border-destructive'), expect.anything() ); }); }); describe('Data Attributes', () => { test('should apply proper data attributes', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('data-slot', 'select-trigger'); expect(trigger).toHaveAttribute('data-size', 'default'); }); test('should handle placeholder data attribute', () => { render( ); const trigger = screen.getByTestId('radix-select-trigger'); expect(trigger).toHaveAttribute('data-placeholder', ''); }); }); });