test: add MultiSelect test file

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-18 23:01:43 +01:00
parent 8695b9b878
commit e2db46fc98

View File

@@ -0,0 +1,109 @@
import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { MultiSelect } from './MultiSelect'
const OPTIONS = [
{ value: 'admin', label: 'ADMIN' },
{ value: 'editor', label: 'EDITOR' },
{ value: 'viewer', label: 'VIEWER' },
{ value: 'operator', label: 'OPERATOR' },
]
describe('MultiSelect', () => {
it('renders trigger with placeholder', () => {
render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} />)
expect(screen.getByText('Select...')).toBeInTheDocument()
})
it('renders trigger with custom placeholder', () => {
render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} placeholder="Add roles..." />)
expect(screen.getByText('Add roles...')).toBeInTheDocument()
})
it('shows selected count on trigger', () => {
render(<MultiSelect options={OPTIONS} value={['admin', 'editor']} onChange={vi.fn()} />)
expect(screen.getByText('2 selected')).toBeInTheDocument()
})
it('opens dropdown on trigger click', async () => {
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} />)
await user.click(screen.getByRole('combobox'))
expect(screen.getByText('ADMIN')).toBeInTheDocument()
expect(screen.getByText('EDITOR')).toBeInTheDocument()
})
it('shows checkboxes for pre-selected values', async () => {
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={['admin']} onChange={vi.fn()} />)
await user.click(screen.getByRole('combobox'))
const adminCheckbox = screen.getByRole('checkbox', { name: 'ADMIN' })
expect(adminCheckbox).toBeChecked()
})
it('filters options by search text', async () => {
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} />)
await user.click(screen.getByRole('combobox'))
await user.type(screen.getByPlaceholderText('Search...'), 'adm')
expect(screen.getByText('ADMIN')).toBeInTheDocument()
expect(screen.queryByText('EDITOR')).not.toBeInTheDocument()
})
it('calls onChange with selected values on Apply', async () => {
const onChange = vi.fn()
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={[]} onChange={onChange} />)
await user.click(screen.getByRole('combobox'))
await user.click(screen.getByRole('checkbox', { name: 'ADMIN' }))
await user.click(screen.getByRole('checkbox', { name: 'VIEWER' }))
await user.click(screen.getByRole('button', { name: /Apply/ }))
expect(onChange).toHaveBeenCalledWith(['admin', 'viewer'])
})
it('discards pending changes on Escape', async () => {
const onChange = vi.fn()
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={[]} onChange={onChange} />)
await user.click(screen.getByRole('combobox'))
await user.click(screen.getByRole('checkbox', { name: 'ADMIN' }))
await user.keyboard('{Escape}')
expect(onChange).not.toHaveBeenCalled()
})
it('closes dropdown on outside click without applying', async () => {
const onChange = vi.fn()
const user = userEvent.setup()
render(
<div>
<MultiSelect options={OPTIONS} value={[]} onChange={onChange} />
<button>Outside</button>
</div>
)
await user.click(screen.getByRole('combobox'))
await user.click(screen.getByRole('checkbox', { name: 'ADMIN' }))
await user.click(screen.getByText('Outside'))
expect(onChange).not.toHaveBeenCalled()
})
it('disables trigger when disabled prop is set', () => {
render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} disabled />)
expect(screen.getByRole('combobox')).toHaveAttribute('aria-disabled', 'true')
})
it('hides search input when searchable is false', async () => {
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} searchable={false} />)
await user.click(screen.getByRole('combobox'))
expect(screen.queryByPlaceholderText('Search...')).not.toBeInTheDocument()
})
it('shows Apply button with count of pending changes', async () => {
const user = userEvent.setup()
render(<MultiSelect options={OPTIONS} value={['admin']} onChange={vi.fn()} />)
await user.click(screen.getByRole('combobox'))
await user.click(screen.getByRole('checkbox', { name: 'EDITOR' }))
expect(screen.getByRole('button', { name: /Apply \(2\)/ })).toBeInTheDocument()
})
})