diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx new file mode 100644 index 000000000000..761adc97c138 --- /dev/null +++ b/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx @@ -0,0 +1,94 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { Combobox, Option } from './Combobox'; + +// Mock data for the Combobox options +const options: Option[] = [ + { label: 'Option 1', value: '1' }, + { label: 'Option 2', value: '2' }, + { label: 'Option 3', value: '3', description: 'This is option 3' }, + { label: 'Option 4', value: '4' }, +]; + +describe('Combobox', () => { + const onChangeHandler = jest.fn(); + beforeAll(() => { + const mockGetBoundingClientRect = jest.fn(() => ({ + width: 120, + height: 120, + top: 0, + left: 0, + bottom: 0, + right: 0, + })); + + Object.defineProperty(Element.prototype, 'getBoundingClientRect', { + value: mockGetBoundingClientRect, + }); + }); + + it('renders without error', () => { + render(); + expect(screen.getByRole('combobox')).toBeInTheDocument(); + }); + + it('should allow selecting a value by clicking directly', async () => { + render(); + + const input = screen.getByRole('combobox'); + userEvent.click(input); + + const item = await screen.findByRole('option', { name: 'Option 1' }); + await userEvent.click(item); + expect(screen.getByDisplayValue('Option 1')).toBeInTheDocument(); + expect(onChangeHandler).toHaveBeenCalledWith(options[0]); + }); + + it('selects value by clicking that needs scrolling', async () => { + render(); + + await userEvent.click(screen.getByRole('combobox')); + fireEvent.scroll(screen.getByRole('listbox'), { target: { scrollY: 200 } }); + await userEvent.click(screen.getByText('Option 4')); + + expect(screen.getByDisplayValue('Option 4')).toBeInTheDocument(); + expect(onChangeHandler).toHaveBeenCalledWith(options[3]); + }); + + it('selects value by searching and pressing enter', async () => { + render(); + + const input = screen.getByRole('combobox'); + await userEvent.type(input, 'Option 3'); + await userEvent.keyboard('{ArrowDown}{Enter}'); + + expect(onChangeHandler).toHaveBeenCalledWith(options[2]); + expect(screen.getByDisplayValue('Option 3')).toBeInTheDocument(); + }); + + it('selects value by using keyboard only', async () => { + render(); + + const input = screen.getByRole('combobox'); + await userEvent.click(input); + + await userEvent.keyboard('{ArrowDown}{ArrowDown}{Enter}'); + expect(onChangeHandler).toHaveBeenCalledWith(options[1]); + expect(screen.queryByDisplayValue('Option 2')).toBeInTheDocument(); + }); + + it('clears selected value', async () => { + render(); + + expect(screen.queryByDisplayValue('Option 2')).toBeInTheDocument(); + const input = screen.getByRole('combobox'); + await userEvent.click(input); + + const clearButton = screen.getByTitle('Clear value'); + await userEvent.click(clearButton); + + expect(onChangeHandler).toHaveBeenCalledWith(null); + expect(screen.queryByDisplayValue('Option 2')).not.toBeInTheDocument(); + }); +});