jan/web-app/src/components/ui/__tests__/slider.test.tsx
2025-09-30 21:48:38 +07:00

194 lines
5.8 KiB
TypeScript

import { describe, it, expect, vi, beforeAll } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { Slider } from '../slider'
// Mock ResizeObserver
class MockResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
}
beforeAll(() => {
global.ResizeObserver = MockResizeObserver
// Mock getBoundingClientRect for Radix Slider positioning
Element.prototype.getBoundingClientRect = vi.fn(() => ({
width: 200,
height: 20,
top: 0,
left: 0,
bottom: 20,
right: 200,
x: 0,
y: 0,
toJSON: () => ({})
}))
})
describe('Slider', () => {
it('renders slider element', () => {
render(<Slider />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
})
it('renders with default min and max values', () => {
render(<Slider />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// Radix slider sets these on internal elements, just check component renders
})
it('renders with custom min and max values', () => {
render(<Slider min={10} max={50} />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// Radix slider handles internal ARIA attributes
})
it('renders with single value', () => {
render(<Slider value={[25]} />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
const thumbs = document.querySelectorAll('[data-slot="slider-thumb"]')
expect(thumbs).toHaveLength(1)
})
it('renders with multiple values', () => {
render(<Slider value={[25, 75]} />)
const thumbs = document.querySelectorAll('[data-slot="slider-thumb"]')
expect(thumbs).toHaveLength(2)
})
it('renders with default value', () => {
render(<Slider defaultValue={[30]} />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
const thumbs = document.querySelectorAll('[data-slot="slider-thumb"]')
expect(thumbs).toHaveLength(1)
})
it('renders track and range', () => {
render(<Slider value={[50]} />)
const track = document.querySelector('[data-slot="slider-track"]')
const range = document.querySelector('[data-slot="slider-range"]')
expect(track).toBeInTheDocument()
expect(range).toBeInTheDocument()
})
it('renders with custom className', () => {
render(<Slider className="custom-slider" />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toHaveClass('custom-slider')
})
it('renders with default styling classes', () => {
render(<Slider />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toHaveClass('relative', 'flex', 'w-full', 'touch-none', 'items-center', 'select-none')
})
it('renders track with correct styling', () => {
render(<Slider />)
const track = document.querySelector('[data-slot="slider-track"]')
expect(track).toHaveClass('bg-main-view-fg/10', 'relative', 'grow', 'overflow-hidden', 'rounded-full')
})
it('renders range with correct styling', () => {
render(<Slider />)
const range = document.querySelector('[data-slot="slider-range"]')
expect(range).toHaveClass('bg-accent', 'absolute')
})
it('renders thumb with correct styling', () => {
render(<Slider value={[50]} />)
const thumb = document.querySelector('[data-slot="slider-thumb"]')
expect(thumb).toHaveClass('border-accent', 'bg-main-view', 'ring-ring/50', 'block', 'size-4', 'shrink-0', 'rounded-full', 'border', 'shadow-sm')
})
it('handles disabled state', () => {
render(<Slider disabled value={[50]} />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// Disabled state is handled by Radix internally
})
it('handles orientation horizontal', () => {
render(<Slider orientation="horizontal" />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// Orientation is handled by Radix internally
})
it('handles orientation vertical', () => {
render(<Slider orientation="vertical" />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// Orientation is handled by Radix internally
})
it('handles onChange callback', () => {
const handleChange = vi.fn()
render(<Slider onValueChange={handleChange} />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// The onValueChange callback should be passed through to the underlying component
expect(handleChange).not.toHaveBeenCalled()
})
it('handles step property', () => {
render(<Slider step={5} />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toBeInTheDocument()
// Step property is handled by Radix internally
})
it('handles aria attributes', () => {
render(<Slider aria-label="Volume" />)
const slider = document.querySelector('[data-slot="slider"]')
expect(slider).toHaveAttribute('aria-label', 'Volume')
})
it('handles custom props', () => {
render(<Slider data-testid="custom-slider" />)
const slider = screen.getByTestId('custom-slider')
expect(slider).toBeInTheDocument()
})
it('handles range slider with two thumbs', () => {
render(<Slider defaultValue={[25, 75]} />)
const thumbs = document.querySelectorAll('[data-slot="slider-thumb"]')
expect(thumbs).toHaveLength(2)
// Both thumbs should have the same styling
thumbs.forEach(thumb => {
expect(thumb).toHaveClass('border-accent', 'bg-main-view', 'rounded-full')
})
})
})