205 lines
5.9 KiB
TypeScript
Executable file
205 lines
5.9 KiB
TypeScript
Executable file
import { describe, it, expect, vi } from 'vitest';
|
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
import { VirtualizedCheckboxList } from './VirtualizedCheckboxList';
|
|
import type { CheckboxOption } from './VirtualizedCheckboxList';
|
|
|
|
describe('VirtualizedCheckboxList', () => {
|
|
const mockOptions: CheckboxOption[] = Array.from({ length: 250 }, (_, i) => ({
|
|
label: `Option ${i + 1}`,
|
|
value: `option-${i + 1}`,
|
|
}));
|
|
|
|
it('renders search input', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByPlaceholderText('Search...')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays selected count', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions}
|
|
selectedValues={['option-1', 'option-2']}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByText('2 / 250 selected')).toBeInTheDocument();
|
|
});
|
|
|
|
it('filters options based on search term', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const searchInput = screen.getByPlaceholderText('Search...');
|
|
fireEvent.change(searchInput, { target: { value: 'Option 10' } });
|
|
|
|
// Should find "Option 10" and "Option 100-109"
|
|
expect(screen.getByText('Option 10')).toBeInTheDocument();
|
|
});
|
|
|
|
it('calls onSelectionChange when checkbox is toggled', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions.slice(0, 10)}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const firstCheckbox = screen.getByLabelText('Option 1');
|
|
fireEvent.click(firstCheckbox);
|
|
|
|
expect(onSelectionChange).toHaveBeenCalledWith(['option-1']);
|
|
});
|
|
|
|
it('selects all filtered options when "Select All" is clicked', () => {
|
|
const onSelectionChange = vi.fn();
|
|
const smallOptions = mockOptions.slice(0, 10);
|
|
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={smallOptions}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const selectAllButton = screen.getByText('Select All');
|
|
fireEvent.click(selectAllButton);
|
|
|
|
const expectedValues = smallOptions.map((opt) => opt.value);
|
|
expect(onSelectionChange).toHaveBeenCalledWith(expectedValues);
|
|
});
|
|
|
|
it('clears all selections when "Clear All" is clicked', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions.slice(0, 10)}
|
|
selectedValues={['option-1', 'option-2']}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const clearAllButton = screen.getByText('Clear All');
|
|
fireEvent.click(clearAllButton);
|
|
|
|
expect(onSelectionChange).toHaveBeenCalledWith([]);
|
|
});
|
|
|
|
it('disables "Select All" when all options are selected', () => {
|
|
const allValues = mockOptions.slice(0, 10).map((opt) => opt.value);
|
|
const onSelectionChange = vi.fn();
|
|
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions.slice(0, 10)}
|
|
selectedValues={allValues}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const selectAllButton = screen.getByText('Select All');
|
|
expect(selectAllButton).toBeDisabled();
|
|
});
|
|
|
|
it('disables "Clear All" when no options are selected', () => {
|
|
const onSelectionChange = vi.fn();
|
|
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions.slice(0, 10)}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const clearAllButton = screen.getByText('Clear All');
|
|
expect(clearAllButton).toBeDisabled();
|
|
});
|
|
|
|
it('shows "No options found" when search returns empty', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const searchInput = screen.getByPlaceholderText('Search...');
|
|
fireEvent.change(searchInput, { target: { value: 'nonexistent' } });
|
|
|
|
expect(screen.getByText('No options found')).toBeInTheDocument();
|
|
});
|
|
|
|
it('accepts custom labels', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions.slice(0, 10)}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
searchPlaceholder="Filter items..."
|
|
selectAllLabel="Check All"
|
|
clearAllLabel="Uncheck All"
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByPlaceholderText('Filter items...')).toBeInTheDocument();
|
|
expect(screen.getByText('Check All')).toBeInTheDocument();
|
|
expect(screen.getByText('Uncheck All')).toBeInTheDocument();
|
|
});
|
|
|
|
it('hides selected count when showSelectedCount is false', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions}
|
|
selectedValues={['option-1']}
|
|
onSelectionChange={onSelectionChange}
|
|
showSelectedCount={false}
|
|
/>
|
|
);
|
|
|
|
expect(screen.queryByText(/selected/i)).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('clears search term when clear button is clicked', () => {
|
|
const onSelectionChange = vi.fn();
|
|
render(
|
|
<VirtualizedCheckboxList
|
|
options={mockOptions}
|
|
selectedValues={[]}
|
|
onSelectionChange={onSelectionChange}
|
|
/>
|
|
);
|
|
|
|
const searchInput = screen.getByPlaceholderText('Search...') as HTMLInputElement;
|
|
fireEvent.change(searchInput, { target: { value: 'test' } });
|
|
|
|
expect(searchInput.value).toBe('test');
|
|
|
|
const clearButton = screen.getByLabelText('Clear search');
|
|
fireEvent.click(clearButton);
|
|
|
|
expect(searchInput.value).toBe('');
|
|
});
|
|
});
|