mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
test: add tests for some base components (#32265)
This commit is contained in:
195
web/app/components/base/checkbox-list/index.spec.tsx
Normal file
195
web/app/components/base/checkbox-list/index.spec.tsx
Normal file
@ -0,0 +1,195 @@
|
||||
/* eslint-disable next/no-img-element */
|
||||
import type { ImgHTMLAttributes } from 'react'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import CheckboxList from '.'
|
||||
|
||||
vi.mock('next/image', () => ({
|
||||
default: (props: ImgHTMLAttributes<HTMLImageElement>) => <img {...props} />,
|
||||
}))
|
||||
|
||||
describe('checkbox list component', () => {
|
||||
const options = [
|
||||
{ label: 'Option 1', value: 'option1' },
|
||||
{ label: 'Option 2', value: 'option2' },
|
||||
{ label: 'Option 3', value: 'option3' },
|
||||
{ label: 'Apple', value: 'apple' },
|
||||
]
|
||||
|
||||
it('renders with title, description and options', () => {
|
||||
render(
|
||||
<CheckboxList
|
||||
title="Test Title"
|
||||
description="Test Description"
|
||||
options={options}
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByText('Test Title')).toBeInTheDocument()
|
||||
expect(screen.getByText('Test Description')).toBeInTheDocument()
|
||||
options.forEach((option) => {
|
||||
expect(screen.getByText(option.label)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('filters options by label', async () => {
|
||||
render(<CheckboxList options={options} />)
|
||||
|
||||
const input = screen.getByRole('textbox')
|
||||
await userEvent.type(input, 'app')
|
||||
|
||||
expect(screen.getByText('Apple')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Option 2')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('Option 3')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders select-all checkbox', () => {
|
||||
render(<CheckboxList options={options} showSelectAll />)
|
||||
const checkboxes = screen.getByTestId('checkbox-selectAll')
|
||||
expect(checkboxes).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('selects all options when select-all is clicked', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={[]}
|
||||
onChange={onChange}
|
||||
showSelectAll
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectAll = screen.getByTestId('checkbox-selectAll')
|
||||
await userEvent.click(selectAll)
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(['option1', 'option2', 'option3', 'apple'])
|
||||
})
|
||||
|
||||
it('does not select all options when select-all is clicked when disabled', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={[]}
|
||||
disabled
|
||||
showSelectAll
|
||||
onChange={onChange}
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectAll = screen.getByTestId('checkbox-selectAll')
|
||||
await userEvent.click(selectAll)
|
||||
|
||||
expect(onChange).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('deselects all options when select-all is clicked', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={['option1', 'option2', 'option3', 'apple']}
|
||||
onChange={onChange}
|
||||
showSelectAll
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectAll = screen.getByTestId('checkbox-selectAll')
|
||||
await userEvent.click(selectAll)
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith([])
|
||||
})
|
||||
|
||||
it('selects select-all when all options are clicked', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={['option1', 'option2', 'option3', 'apple']}
|
||||
onChange={onChange}
|
||||
showSelectAll
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectAll = screen.getByTestId('checkbox-selectAll')
|
||||
expect(selectAll.querySelector('[data-testid="check-icon-selectAll"]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('hides select-all checkbox when searching', async () => {
|
||||
render(<CheckboxList options={options} />)
|
||||
await userEvent.type(screen.getByRole('textbox'), 'app')
|
||||
expect(screen.queryByTestId('checkbox-selectAll')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('selects options when checkbox is clicked', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={[]}
|
||||
onChange={onChange}
|
||||
showSelectAll={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectOption = screen.getByTestId('checkbox-option1')
|
||||
await userEvent.click(selectOption)
|
||||
expect(onChange).toHaveBeenCalledWith(['option1'])
|
||||
})
|
||||
|
||||
it('deselects options when checkbox is clicked when selected', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={['option1']}
|
||||
onChange={onChange}
|
||||
showSelectAll={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectOption = screen.getByTestId('checkbox-option1')
|
||||
await userEvent.click(selectOption)
|
||||
expect(onChange).toHaveBeenCalledWith([])
|
||||
})
|
||||
|
||||
it('does not select options when checkbox is clicked', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={[]}
|
||||
onChange={onChange}
|
||||
disabled
|
||||
/>,
|
||||
)
|
||||
|
||||
const selectOption = screen.getByTestId('checkbox-option1')
|
||||
await userEvent.click(selectOption)
|
||||
expect(onChange).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('Reset button works', async () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
render(
|
||||
<CheckboxList
|
||||
options={options}
|
||||
value={[]}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
)
|
||||
|
||||
const input = screen.getByRole('textbox')
|
||||
await userEvent.type(input, 'ban')
|
||||
await userEvent.click(screen.getByText('common.operation.resetKeywords'))
|
||||
expect(input).toHaveValue('')
|
||||
})
|
||||
})
|
||||
@ -101,12 +101,12 @@ const CheckboxList: FC<CheckboxListProps> = ({
|
||||
return (
|
||||
<div className={cn('flex w-full flex-col gap-1', containerClassName)}>
|
||||
{label && (
|
||||
<div className="system-sm-medium text-text-secondary">
|
||||
<div className="text-text-secondary system-sm-medium">
|
||||
{label}
|
||||
</div>
|
||||
)}
|
||||
{description && (
|
||||
<div className="body-xs-regular text-text-tertiary">
|
||||
<div className="text-text-tertiary body-xs-regular">
|
||||
{description}
|
||||
</div>
|
||||
)}
|
||||
@ -120,13 +120,14 @@ const CheckboxList: FC<CheckboxListProps> = ({
|
||||
indeterminate={isIndeterminate}
|
||||
onCheck={handleSelectAll}
|
||||
disabled={disabled}
|
||||
id="selectAll"
|
||||
/>
|
||||
)}
|
||||
{!searchQuery
|
||||
? (
|
||||
<div className="flex min-w-0 flex-1 items-center gap-1">
|
||||
{title && (
|
||||
<span className="system-xs-semibold-uppercase truncate leading-5 text-text-secondary">
|
||||
<span className="truncate leading-5 text-text-secondary system-xs-semibold-uppercase">
|
||||
{title}
|
||||
</span>
|
||||
)}
|
||||
@ -138,7 +139,7 @@ const CheckboxList: FC<CheckboxListProps> = ({
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className="system-sm-medium-uppercase flex-1 leading-6 text-text-secondary">
|
||||
<div className="flex-1 leading-6 text-text-secondary system-sm-medium-uppercase">
|
||||
{
|
||||
filteredOptions.length > 0
|
||||
? t('operation.searchCount', { ns: 'common', count: filteredOptions.length, content: title })
|
||||
@ -168,7 +169,7 @@ const CheckboxList: FC<CheckboxListProps> = ({
|
||||
? (
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Image alt="search menu" src={SearchMenu} width={32} />
|
||||
<span className="system-sm-regular text-text-secondary">{t('operation.noSearchResults', { ns: 'common', content: title })}</span>
|
||||
<span className="text-text-secondary system-sm-regular">{t('operation.noSearchResults', { ns: 'common', content: title })}</span>
|
||||
<Button variant="secondary-accent" size="small" onClick={() => setSearchQuery('')}>{t('operation.resetKeywords', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
)
|
||||
@ -198,9 +199,10 @@ const CheckboxList: FC<CheckboxListProps> = ({
|
||||
handleToggleOption(option.value)
|
||||
}}
|
||||
disabled={option.disabled || disabled}
|
||||
id={option.value}
|
||||
/>
|
||||
<div
|
||||
className="system-sm-medium flex-1 truncate text-text-secondary"
|
||||
className="flex-1 truncate text-text-secondary system-sm-medium"
|
||||
title={option.label}
|
||||
>
|
||||
{option.label}
|
||||
|
||||
Reference in New Issue
Block a user