193 lines
6.5 KiB
TypeScript
193 lines
6.5 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest'
|
|
import { render, screen, fireEvent } from '@testing-library/react'
|
|
import { Switch } from '../switch'
|
|
|
|
describe('Switch', () => {
|
|
it('renders switch element', () => {
|
|
render(<Switch />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toBeInTheDocument()
|
|
})
|
|
|
|
it('renders thumb element', () => {
|
|
render(<Switch />)
|
|
|
|
const thumb = document.querySelector('[data-slot="switch-thumb"]')
|
|
expect(thumb).toBeInTheDocument()
|
|
})
|
|
|
|
it('renders with default styling classes', () => {
|
|
render(<Switch />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveClass('relative', 'peer', 'cursor-pointer', 'inline-flex', 'h-[18px]', 'w-8.5', 'shrink-0', 'items-center', 'rounded-full')
|
|
})
|
|
|
|
it('renders thumb with correct styling', () => {
|
|
render(<Switch />)
|
|
|
|
const thumb = document.querySelector('[data-slot="switch-thumb"]')
|
|
expect(thumb).toHaveClass('bg-main-view', 'pointer-events-none', 'block', 'size-4', 'rounded-full', 'ring-0', 'transition-transform')
|
|
})
|
|
|
|
it('renders with custom className', () => {
|
|
render(<Switch className="custom-switch" />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveClass('custom-switch')
|
|
})
|
|
|
|
it('handles checked state', () => {
|
|
render(<Switch checked />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveAttribute('data-state', 'checked')
|
|
})
|
|
|
|
it('handles unchecked state', () => {
|
|
render(<Switch checked={false} />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveAttribute('data-state', 'unchecked')
|
|
})
|
|
|
|
it('handles disabled state', () => {
|
|
render(<Switch disabled />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveAttribute('disabled')
|
|
})
|
|
|
|
it('handles loading state', () => {
|
|
render(<Switch loading />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveClass('w-4.5', 'pointer-events-none')
|
|
|
|
// Should render loading spinner
|
|
const loader = document.querySelector('.animate-spin')
|
|
expect(loader).toBeInTheDocument()
|
|
})
|
|
|
|
it('renders loading spinner with correct styling', () => {
|
|
render(<Switch loading />)
|
|
|
|
const spinner = document.querySelector('.animate-spin')
|
|
expect(spinner).toBeInTheDocument()
|
|
expect(spinner).toHaveClass('text-main-view-fg/50')
|
|
|
|
const spinnerContainer = document.querySelector('.absolute.inset-0')
|
|
expect(spinnerContainer).toHaveClass('flex', 'items-center', 'justify-center', 'z-10', 'size-3.5')
|
|
})
|
|
|
|
it('handles onChange callback', () => {
|
|
const handleChange = vi.fn()
|
|
render(<Switch onCheckedChange={handleChange} />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
fireEvent.click(switchElement!)
|
|
|
|
expect(handleChange).toHaveBeenCalledWith(true)
|
|
})
|
|
|
|
it('handles click to toggle state', () => {
|
|
const handleChange = vi.fn()
|
|
render(<Switch onCheckedChange={handleChange} />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
fireEvent.click(switchElement!)
|
|
|
|
expect(handleChange).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('does not trigger onChange when disabled', () => {
|
|
const handleChange = vi.fn()
|
|
render(<Switch onCheckedChange={handleChange} disabled />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
fireEvent.click(switchElement!)
|
|
|
|
expect(handleChange).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('does not trigger onChange when loading', () => {
|
|
const handleChange = vi.fn()
|
|
render(<Switch onCheckedChange={handleChange} loading />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
|
|
// Check that pointer-events-none is applied when loading
|
|
expect(switchElement).toHaveClass('pointer-events-none')
|
|
|
|
// fireEvent.click can still trigger events even with pointer-events-none
|
|
// So we check that the loading state is properly applied
|
|
expect(switchElement).toHaveClass('w-4.5')
|
|
})
|
|
|
|
it('handles keyboard navigation', () => {
|
|
const handleChange = vi.fn()
|
|
render(<Switch onCheckedChange={handleChange} />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
|
|
// Test that the element can receive focus and has proper attributes
|
|
expect(switchElement).toBeInTheDocument()
|
|
expect(switchElement).toHaveAttribute('role', 'switch')
|
|
|
|
// Radix handles keyboard events internally, so we test the proper setup
|
|
switchElement?.focus()
|
|
expect(document.activeElement).toBe(switchElement)
|
|
})
|
|
|
|
it('handles space key', () => {
|
|
const handleChange = vi.fn()
|
|
render(<Switch onCheckedChange={handleChange} />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
|
|
// Test that the switch element exists and can be focused
|
|
expect(switchElement).toBeInTheDocument()
|
|
expect(switchElement).toHaveAttribute('role', 'switch')
|
|
|
|
// Verify the switch can be focused (Radix handles tabindex internally)
|
|
switchElement?.focus()
|
|
expect(document.activeElement).toBe(switchElement)
|
|
})
|
|
|
|
it('renders with aria attributes', () => {
|
|
render(<Switch aria-label="Toggle feature" />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveAttribute('aria-label', 'Toggle feature')
|
|
})
|
|
|
|
it('handles custom props', () => {
|
|
render(<Switch data-testid="custom-switch" />)
|
|
|
|
const switchElement = screen.getByTestId('custom-switch')
|
|
expect(switchElement).toBeInTheDocument()
|
|
})
|
|
|
|
it('handles focus styles', () => {
|
|
render(<Switch />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveClass('focus-visible:ring-0', 'focus-visible:border-none')
|
|
})
|
|
|
|
it('handles checked state styling', () => {
|
|
render(<Switch checked />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveClass('data-[state=checked]:bg-accent')
|
|
})
|
|
|
|
it('handles unchecked state styling', () => {
|
|
render(<Switch checked={false} />)
|
|
|
|
const switchElement = document.querySelector('[data-slot="switch"]')
|
|
expect(switchElement).toHaveClass('data-[state=unchecked]:bg-main-view-fg/20')
|
|
})
|
|
})
|