test: add MultiSelect test file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
109
src/design-system/composites/MultiSelect/MultiSelect.test.tsx
Normal file
109
src/design-system/composites/MultiSelect/MultiSelect.test.tsx
Normal 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()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user