@baseplate-dev/ui-components
Version:
Shared UI component library
148 lines • 7.12 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { screen, waitFor } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { renderWithProviders } from '#src/tests/render.test-helper.js';
import { Combobox, ComboboxContent, ComboboxInput, ComboboxItem, } from './combobox.js';
const mockOptions = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'orange', label: 'Orange' },
];
const TestCombobox = ({ value, onChange = vi.fn(), disabled = false, placeholder = 'Select fruit...', options = mockOptions, }) => (_jsxs(Combobox, { value: value, onChange: onChange, disabled: disabled, children: [_jsx(ComboboxInput, { placeholder: placeholder }), _jsx(ComboboxContent, { children: options.map((option) => (_jsx(ComboboxItem, { value: option.value, label: option.label, children: option.label }, option.value))) })] }));
describe('Combobox', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('Rendering', () => {
it('renders with placeholder when no value is selected', () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
expect(screen.getByPlaceholderText('Select fruit...')).toBeInTheDocument();
});
it('renders with selected value', () => {
renderWithProviders(_jsx(TestCombobox, { value: mockOptions[0] }));
expect(screen.getByText('Apple')).toBeInTheDocument();
});
it('renders in disabled state', () => {
renderWithProviders(_jsx(TestCombobox, { disabled: true, value: null }));
const input = screen.getByRole('combobox');
expect(input).toBeDisabled();
});
});
describe('User Interactions', () => {
it('opens dropdown on click', async () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
const input = screen.getByRole('combobox');
await userEvent.click(input);
await waitFor(() => {
for (const option of mockOptions) {
expect(screen.getByText(option.label)).toBeInTheDocument();
}
});
});
it('filters options based on input', async () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
const input = screen.getByRole('combobox');
await userEvent.click(input);
await userEvent.type(input, 'ap');
await waitFor(() => {
expect(screen.getByText('Apple')).toBeInTheDocument();
expect(screen.queryByText('Banana')).not.toBeInTheDocument();
});
});
it('selects option on click', async () => {
const onChange = vi.fn();
renderWithProviders(_jsx(TestCombobox, { value: null, onChange: onChange }));
const input = screen.getByRole('combobox');
await userEvent.click(input);
const option = await screen.findByText('Apple');
await userEvent.click(option);
expect(onChange).toHaveBeenCalledWith({
value: 'apple',
label: 'Apple',
});
});
it('clears search query after selection', async () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
const input = screen.getByRole('combobox');
await userEvent.click(input);
await userEvent.type(input, 'ap');
const option = await screen.findByText('Apple');
await userEvent.click(option);
expect(input).toHaveValue('');
});
});
describe('Keyboard Navigation', () => {
it('opens dropdown on arrow down', async () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
const input = screen.getByRole('combobox');
input.focus();
await userEvent.keyboard('{ArrowDown}');
await waitFor(() => {
for (const option of mockOptions) {
expect(screen.getByText(option.label)).toBeInTheDocument();
}
});
});
it('closes dropdown on escape', async () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
const input = screen.getByRole('combobox');
// Open dropdown
await userEvent.click(input);
// Verify it's open
expect(await screen.findByText('Apple')).toBeInTheDocument();
// Press escape
await userEvent.keyboard('{Escape}');
// Verify it's closed
await waitFor(() => {
expect(screen.queryByText('Apple')).not.toBeInTheDocument();
});
});
it('selects option with enter key', async () => {
const onChange = vi.fn();
renderWithProviders(_jsx(TestCombobox, { value: null, onChange: onChange }));
const input = screen.getByRole('combobox');
input.focus();
await userEvent.keyboard('{ArrowDown}');
expect(await screen.findByText('Apple')).toBeInTheDocument();
await userEvent.keyboard('{Enter}');
expect(onChange).toHaveBeenCalled();
});
it('selects a specific option with enter key', async () => {
const onChange = vi.fn();
renderWithProviders(_jsx(TestCombobox, { options: [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'orange', label: 'Orange' },
], value: null, onChange: onChange }));
const input = screen.getByRole('combobox');
input.focus();
await userEvent.keyboard('ban');
await userEvent.keyboard('{Enter}');
expect(onChange).toHaveBeenCalledWith({
value: 'banana',
label: 'Banana',
});
});
});
describe('Edge Cases', () => {
it('handles empty search results', async () => {
renderWithProviders(_jsx(TestCombobox, { value: null }));
const input = screen.getByRole('combobox');
await userEvent.click(input);
await userEvent.keyboard('xyz');
expect(screen.queryByRole('option')).not.toBeInTheDocument();
});
it('maintains selected value when closing without selection', async () => {
const initialValue = mockOptions[0];
const onChange = vi.fn();
renderWithProviders(_jsx(TestCombobox, { value: initialValue, onChange: onChange }));
const input = screen.getByRole('combobox');
await userEvent.click(input);
await userEvent.keyboard('{Escape}');
expect(onChange).not.toHaveBeenCalled();
expect(screen.getByText(initialValue.label)).toBeInTheDocument();
});
});
});
//# sourceMappingURL=combobox.test.js.map