import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react'
import { Slider } from '../slider'
describe('Slider Component', () => {
describe('Basic Rendering', () => {
it('renders correctly with default props', () => {
render()
const slider = screen.getByTestId('slider')
expect(slider).toBeInTheDocument()
expect(slider).toHaveClass('w-full')
})
it('applies custom className', () => {
render()
const sliderContainer = screen.getByTestId('slider').children[0] as HTMLElement
expect(sliderContainer).toHaveClass('custom-slider')
})
it('renders with default value', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuenow', '25')
})
it('renders with controlled value', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuenow', '50')
})
})
describe('Size Variants', () => {
it('renders sm size correctly', () => {
render()
const sliderContainer = screen.getByTestId('slider').children[0] as HTMLElement
expect(sliderContainer).toHaveClass('h-5')
})
it('renders default size correctly', () => {
render()
const sliderContainer = screen.getByTestId('slider').children[0] as HTMLElement
expect(sliderContainer).toHaveClass('h-6')
})
it('renders md size correctly', () => {
render()
const sliderContainer = screen.getByTestId('slider').children[0] as HTMLElement
expect(sliderContainer).toHaveClass('h-8')
})
it('renders lg size correctly', () => {
render()
const sliderContainer = screen.getByTestId('slider').children[0] as HTMLElement
expect(sliderContainer).toHaveClass('h-10')
})
})
describe('Track Variants', () => {
it('renders default track variant correctly', () => {
render()
const track = screen.getByTestId('slider').querySelector('.bg-muted')
expect(track).toBeInTheDocument()
})
it('renders primary track variant correctly', () => {
render()
const track = screen.getByTestId('slider').querySelector('.bg-primary\\/20')
expect(track).toBeInTheDocument()
})
it('renders secondary track variant correctly', () => {
render()
const track = screen.getByTestId('slider').querySelector('.bg-secondary\\/20')
expect(track).toBeInTheDocument()
})
it('renders success track variant correctly', () => {
render()
const track = screen.getByTestId('slider').querySelector('.bg-success\\/20')
expect(track).toBeInTheDocument()
})
it('renders error track variant correctly', () => {
render()
const track = screen.getByTestId('slider').querySelector('.bg-error\\/20')
expect(track).toBeInTheDocument()
})
})
describe('Range Variants', () => {
it('renders default range variant correctly', () => {
render()
const range = screen.getByTestId('slider').querySelector('.bg-foreground')
expect(range).toBeInTheDocument()
})
it('renders primary range variant correctly', () => {
render()
const range = screen.getByTestId('slider').querySelector('.bg-primary')
expect(range).toBeInTheDocument()
})
it('renders success range variant correctly', () => {
render()
const range = screen.getByTestId('slider').querySelector('.bg-success')
expect(range).toBeInTheDocument()
})
it('renders error range variant correctly', () => {
render()
const range = screen.getByTestId('slider').querySelector('.bg-error')
expect(range).toBeInTheDocument()
})
})
describe('Thumb Variants', () => {
it('renders default thumb variant correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('border-foreground')
})
it('renders primary thumb variant correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('border-primary')
})
it('renders success thumb variant correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('border-success')
})
it('renders error thumb variant correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('border-error')
})
})
describe('Thumb Sizes', () => {
it('renders sm thumb size correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('h-3', 'w-3')
})
it('renders default thumb size correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('h-4', 'w-4')
})
it('renders md thumb size correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('h-5', 'w-5')
})
it('renders lg thumb size correctly', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('h-6', 'w-6')
})
})
describe('Value Label', () => {
it('does not show value label by default', () => {
render()
expect(screen.queryByText('25')).not.toBeInTheDocument()
})
it('shows value label when enabled', () => {
render()
expect(screen.getByText('25')).toBeInTheDocument()
})
it('applies custom value label className', () => {
render(
)
const label = screen.getByText('25').parentElement
expect(label).toHaveClass('custom-label')
})
it('formats value label with custom formatter', () => {
const formatter = (value: number) => `${value}%`
render(
)
expect(screen.getByText('25%')).toBeInTheDocument()
})
it('shows range for multiple values', () => {
render(
)
expect(screen.getByText('25 - 75')).toBeInTheDocument()
})
})
describe('Props and Configuration', () => {
it('handles min and max values', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuemin', '10')
expect(thumb).toHaveAttribute('aria-valuemax', '90')
expect(thumb).toHaveAttribute('aria-valuenow', '50')
})
it('handles step value', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuenow', '25')
})
it('handles multiple thumbs', () => {
render()
const thumbs = screen.getAllByRole('slider')
expect(thumbs).toHaveLength(2)
expect(thumbs[0]).toHaveAttribute('aria-valuenow', '25')
expect(thumbs[1]).toHaveAttribute('aria-valuenow', '75')
})
})
describe('Disabled State', () => {
it('renders disabled state correctly', () => {
render()
const sliderContainer = screen.getByTestId('slider').querySelector('[data-disabled]')
expect(sliderContainer).toHaveAttribute('data-disabled', 'true')
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-disabled', 'true')
expect(thumb).toHaveAttribute('tabIndex', '-1')
})
it('does not handle interactions when disabled', () => {
const onValueChange = jest.fn()
render()
const thumb = screen.getByRole('slider')
fireEvent.mouseDown(thumb)
expect(onValueChange).not.toHaveBeenCalled()
})
})
describe('Event Handling', () => {
it('calls onValueChange when value changes', () => {
const onValueChange = jest.fn()
render()
const thumb = screen.getByRole('slider')
fireEvent.mouseDown(thumb)
// Simulate mouse move
fireEvent(document, new MouseEvent('mousemove', {
clientX: 100,
bubbles: true
}))
expect(onValueChange).toHaveBeenCalled()
})
it('handles track click', () => {
const onValueChange = jest.fn()
render()
const track = screen.getByTestId('slider').querySelector('.bg-muted')
if (track) {
fireEvent.click(track, { clientX: 50 })
expect(onValueChange).toHaveBeenCalled()
}
})
it('updates controlled value', () => {
const TestComponent = () => {
const [value, setValue] = React.useState([25])
return (
{value[0]}
)
}
render()
expect(screen.getByTestId('current-value')).toHaveTextContent('25')
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuenow', '25')
})
})
describe('Accessibility', () => {
it('has proper ARIA attributes', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('role', 'slider')
expect(thumb).toHaveAttribute('aria-valuemin', '0')
expect(thumb).toHaveAttribute('aria-valuemax', '100')
expect(thumb).toHaveAttribute('aria-valuenow', '50')
expect(thumb).toHaveAttribute('tabIndex', '0')
})
it('has proper aria-label for multiple thumbs', () => {
render()
const thumbs = screen.getAllByRole('slider')
expect(thumbs[0]).toHaveAttribute('aria-label', 'Thumb 1')
expect(thumbs[1]).toHaveAttribute('aria-label', 'Thumb 2')
})
it('handles keyboard navigation', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('tabIndex', '0')
thumb.focus()
expect(thumb).toHaveFocus()
})
})
describe('Ref Forwarding', () => {
it('forwards ref correctly', () => {
const ref = React.createRef()
render()
expect(ref.current).toBeInstanceOf(HTMLDivElement)
expect(ref.current).toBe(screen.getByTestId('slider'))
})
})
describe('DisplayName', () => {
it('maintains displayName', () => {
expect(Slider.displayName).toBe('Slider')
})
})
describe('HTML Attributes', () => {
it('passes through HTML attributes', () => {
render(
)
const slider = screen.getByTestId('slider')
expect(slider).toHaveAttribute('id', 'test-slider')
expect(slider).toHaveAttribute('aria-describedby', 'slider-description')
})
})
describe('Complex Combinations', () => {
it('renders with all variants and options', () => {
render(
`${v}px`}
min={0}
max={200}
step={10}
defaultValue={[50, 150]}
data-testid="slider"
/>
)
const slider = screen.getByTestId('slider')
expect(slider).toBeInTheDocument()
const thumbs = screen.getAllByRole('slider')
expect(thumbs).toHaveLength(2)
expect(screen.getByText('50px - 150px')).toBeInTheDocument()
})
it('handles variant inheritance correctly', () => {
render()
// Track should inherit from thumb variant
const track = screen.getByTestId('slider').querySelector('.bg-success\\/20')
expect(track).toBeInTheDocument()
// Range should inherit from thumb variant
const range = screen.getByTestId('slider').querySelector('.bg-success')
expect(range).toBeInTheDocument()
// Thumb should use its own variant
const thumb = screen.getByRole('slider')
expect(thumb).toHaveClass('border-success')
})
})
describe('Edge Cases', () => {
it('handles empty defaultValue', () => {
render()
const slider = screen.getByTestId('slider')
expect(slider).toBeInTheDocument()
})
it('handles undefined value', () => {
render()
const slider = screen.getByTestId('slider')
expect(slider).toBeInTheDocument()
})
it('handles extreme min/max values', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuemin', '-100')
expect(thumb).toHaveAttribute('aria-valuemax', '1000')
})
it('handles very small step values', () => {
render()
const thumb = screen.getByRole('slider')
expect(thumb).toHaveAttribute('aria-valuenow', '0.5')
})
it('handles single value array', () => {
render()
expect(screen.getByText('42')).toBeInTheDocument()
const thumbs = screen.getAllByRole('slider')
expect(thumbs).toHaveLength(1)
})
})
})