diff --git a/package.json b/package.json
index 12b94b8..e73c28f 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"lint": "npx eslint",
"format": "npx prettier --write .",
"prisma:migrate": "npx prisma migrate dev",
- "test": "jest"
+ "test": "npx jest"
},
"dependencies": {
"@eslint/js": "^9.37.0",
diff --git a/src/__tests__/BasicSelect.test.tsx b/src/__tests__/BasicSelect.test.tsx
new file mode 100644
index 0000000..9176a8f
--- /dev/null
+++ b/src/__tests__/BasicSelect.test.tsx
@@ -0,0 +1,114 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { BasicSelect } from '../components/common/BasicSelect';
+
+describe('BasicSelect', () => {
+ const mockItems = [
+ { label: 'Option 1', value: '1' },
+ { label: 'Option 2', value: '2' },
+ { label: 'Option 3', value: '3' },
+ ];
+
+ const mockOnChange = jest.fn();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders with placeholder and opens on click', async () => {
+ render(
+
+ );
+
+ expect(screen.getByText('Select an option')).toBeInTheDocument();
+
+ await userEvent.click(screen.getByRole('combobox'));
+ expect(screen.getByText('Option 1')).toBeInTheDocument();
+ expect(screen.getByText('Option 2')).toBeInTheDocument();
+ expect(screen.getByText('Option 3')).toBeInTheDocument();
+ });
+
+ it('allows selecting an option with click', async () => {
+ render(
+
+ );
+
+ await userEvent.click(screen.getByRole('combobox'));
+ await userEvent.click(screen.getByText('Option 2'));
+
+ expect(mockOnChange).toHaveBeenCalledWith('2');
+ expect(screen.queryByText('Option 1')).not.toBeInTheDocument(); // Menu should close
+ expect(screen.getByText('Option 2')).toBeInTheDocument(); // Selected value
+ });
+
+ it('navigates options with arrow keys and selects with Enter', async () => {
+ render(
+
+ );
+
+ const combobox = screen.getByRole('combobox');
+ await userEvent.click(combobox); // Open the select
+
+ // Navigate down to Option 2
+ fireEvent.keyDown(combobox, { key: 'ArrowDown' }); // Focus Option 1
+ fireEvent.keyDown(combobox, { key: 'ArrowDown' }); // Focus Option 2
+
+ // Select Option 2 with Enter
+ fireEvent.keyDown(combobox, { key: 'Enter' });
+
+ expect(mockOnChange).toHaveBeenCalledWith('2');
+ expect(screen.queryByText('Option 1')).not.toBeInTheDocument(); // Menu should close
+ expect(screen.getByText('Option 2')).toBeInTheDocument(); // Selected value
+ });
+
+ it('closes the select with Escape key', async () => {
+ render(
+
+ );
+
+ const combobox = screen.getByRole('combobox');
+ await userEvent.click(combobox); // Open the select
+
+ expect(screen.getByText('Option 1')).toBeInTheDocument(); // Menu is open
+
+ fireEvent.keyDown(combobox, { key: 'Escape' });
+
+ expect(screen.queryByText('Option 1')).not.toBeInTheDocument(); // Menu should close
+ });
+
+ it('should clear selection when allowEmpty is true and clear button is clicked', async () => {
+ render(
+
+ );
+
+ expect(screen.getByText('Option 1')).toBeInTheDocument();
+
+ const clearButton = screen.getByRole('button', { name: /clear/i });
+ await userEvent.click(clearButton);
+
+ expect(mockOnChange).toHaveBeenCalledWith(null);
+ expect(screen.getByText('Select an option')).toBeInTheDocument();
+ });
+});
\ No newline at end of file
diff --git a/src/components/common/BasicSelect.tsx b/src/components/common/BasicSelect.tsx
index d8bb5f5..9e92a22 100755
--- a/src/components/common/BasicSelect.tsx
+++ b/src/components/common/BasicSelect.tsx
@@ -42,52 +42,53 @@ export function BasicSelect({
)}
{helperText && {helperText}}
-
- {allowEmpty && hasValue && (
-
);