mirror of
https://github.com/langgenius/dify.git
synced 2026-03-04 15:26:21 +08:00
125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
import type { Option } from './custom'
|
|
import { render, screen } from '@testing-library/react'
|
|
import userEvent from '@testing-library/user-event'
|
|
import CustomSelect from './custom'
|
|
|
|
const options: Option[] = [
|
|
{ label: 'First option', value: 'first' },
|
|
{ label: 'Second option', value: 'second' },
|
|
]
|
|
|
|
describe('CustomSelect', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
// Rendering behavior and value fallback.
|
|
describe('Rendering', () => {
|
|
it('should show the placeholder when value is undefined or not found', () => {
|
|
const { rerender } = render(
|
|
<CustomSelect options={options} />,
|
|
)
|
|
|
|
expect(screen.getByTitle(/select/i)).toBeInTheDocument()
|
|
|
|
rerender(
|
|
<CustomSelect options={options} value="missing" />,
|
|
)
|
|
|
|
expect(screen.getByTitle(/select/i)).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
// User interactions for opening and selecting options.
|
|
describe('User Interactions', () => {
|
|
it('should call onChange and close the popup when an option is selected', async () => {
|
|
const user = userEvent.setup()
|
|
const onChange = vi.fn()
|
|
|
|
render(
|
|
<CustomSelect options={options} onChange={onChange} />,
|
|
)
|
|
|
|
await user.click(screen.getByTitle(/select/i))
|
|
expect(screen.getByTitle('Second option')).toBeInTheDocument()
|
|
|
|
await user.click(screen.getByTitle('Second option'))
|
|
expect(onChange).toHaveBeenCalledWith('second')
|
|
expect(screen.queryByTitle('Second option')).not.toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
// Controlled container props behavior.
|
|
describe('Container Props', () => {
|
|
it('should delegate open-state changes through containerProps.onOpenChange', async () => {
|
|
const user = userEvent.setup()
|
|
const onOpenChange = vi.fn()
|
|
|
|
render(
|
|
<CustomSelect
|
|
options={options}
|
|
containerProps={{ open: true, onOpenChange }}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByTitle('First option')).toBeInTheDocument()
|
|
|
|
await user.click(screen.getByTitle(/select/i))
|
|
expect(onOpenChange).toHaveBeenCalledWith(false)
|
|
})
|
|
})
|
|
|
|
// Custom rendering hooks for trigger and options.
|
|
describe('Custom Renderers', () => {
|
|
it('should render CustomTrigger and CustomOption with selected state', async () => {
|
|
const user = userEvent.setup()
|
|
|
|
render(
|
|
<CustomSelect
|
|
options={options}
|
|
value="first"
|
|
CustomTrigger={(option, open) => <div>{`${option?.label ?? 'none'}-${open ? 'open' : 'closed'}`}</div>}
|
|
CustomOption={(option, selected) => <div>{`${option.label}-${selected ? 'selected' : 'idle'}`}</div>}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByText('First option-closed')).toBeInTheDocument()
|
|
|
|
await user.click(screen.getByText('First option-closed'))
|
|
|
|
expect(screen.getByText('First option-open')).toBeInTheDocument()
|
|
expect(screen.getByText('First option-selected')).toBeInTheDocument()
|
|
expect(screen.getByText('Second option-idle')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
// Class-based customization props.
|
|
describe('Style Props', () => {
|
|
it('should apply trigger and popup class names from props', async () => {
|
|
const user = userEvent.setup()
|
|
|
|
render(
|
|
<CustomSelect
|
|
options={options}
|
|
triggerProps={{ className: 'trigger-class' }}
|
|
popupProps={{
|
|
wrapperClassName: 'wrapper-class',
|
|
className: 'popup-class',
|
|
itemClassName: 'item-class',
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
const triggerLabel = screen.getByTitle(/select/i)
|
|
const trigger = triggerLabel.parentElement
|
|
expect(trigger).toHaveClass('trigger-class')
|
|
|
|
await user.click(triggerLabel)
|
|
|
|
expect(document.querySelector('.wrapper-class')).toBeInTheDocument()
|
|
expect(document.querySelector('.popup-class')).toBeInTheDocument()
|
|
expect(document.querySelectorAll('.item-class')).toHaveLength(options.length)
|
|
})
|
|
})
|
|
})
|