Spaces:
Sleeping
Sleeping
File size: 3,977 Bytes
cd99321 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | import { render, screen, fireEvent } from '../../../tests/helpers/render';
import userEvent from '@testing-library/user-event';
import CustomSelect from './CustomSelect';
const OPTIONS = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'cherry', label: 'Cherry' },
];
describe('CustomSelect', () => {
const onChange = vi.fn();
beforeEach(() => {
onChange.mockClear();
});
it('FE-COMP-SELECT-001: renders placeholder when no value is selected', () => {
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} placeholder="Pick a fruit" />);
expect(screen.getByText('Pick a fruit')).toBeTruthy();
});
it('FE-COMP-SELECT-002: renders the selected option label', () => {
render(<CustomSelect value="banana" onChange={onChange} options={OPTIONS} placeholder="Pick" />);
expect(screen.getByText('Banana')).toBeTruthy();
});
it('FE-COMP-SELECT-003: clicking trigger opens the dropdown', async () => {
const user = userEvent.setup();
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} />);
const trigger = screen.getByRole('button');
await user.click(trigger);
// All options should now be visible in the portal
expect(screen.getByText('Apple')).toBeTruthy();
expect(screen.getByText('Banana')).toBeTruthy();
expect(screen.getByText('Cherry')).toBeTruthy();
});
it('FE-COMP-SELECT-004: options are displayed in the dropdown', async () => {
const user = userEvent.setup();
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} />);
await user.click(screen.getByRole('button'));
expect(screen.getAllByRole('button').length).toBeGreaterThan(1); // trigger + option buttons
});
it('FE-COMP-SELECT-005: clicking an option calls onChange with correct value', async () => {
const user = userEvent.setup();
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} />);
await user.click(screen.getByRole('button')); // open
// Options in dropdown are also buttons
const optionBtns = screen.getAllByRole('button');
// Find the Cherry option button (not the trigger which shows placeholder)
const cherryBtn = optionBtns.find(b => b.textContent?.includes('Cherry'));
await user.click(cherryBtn!);
expect(onChange).toHaveBeenCalledWith('cherry');
});
it('FE-COMP-SELECT-006: clicking an option closes the dropdown', async () => {
const user = userEvent.setup();
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} />);
await user.click(screen.getByRole('button')); // open
const optionBtns = screen.getAllByRole('button');
const appleBtn = optionBtns.find(b => b.textContent?.includes('Apple'));
await user.click(appleBtn!);
// After selection, only the trigger button remains in DOM
expect(screen.getAllByRole('button')).toHaveLength(1);
});
it('FE-COMP-SELECT-007: searchable mode filters options by typed text', async () => {
const user = userEvent.setup();
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} searchable={true} />);
await user.click(screen.getByRole('button')); // open
const searchInput = screen.getByPlaceholderText('...');
await user.type(searchInput, 'ban');
// Only Banana should remain, Apple and Cherry should be filtered out
expect(screen.getByText('Banana')).toBeTruthy();
expect(screen.queryByText('Apple')).toBeNull();
expect(screen.queryByText('Cherry')).toBeNull();
});
it('FE-COMP-SELECT-008: disabled state prevents the dropdown from opening', async () => {
const user = userEvent.setup();
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} disabled={true} placeholder="Pick" />);
const trigger = screen.getByRole('button');
await user.click(trigger);
// Dropdown should not be in the DOM — options remain hidden
expect(screen.queryByText('Apple')).toBeNull();
});
});
|