import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import '@testing-library/jest-dom'; import SearchBar from '../SearchBar'; // Mock useLocalize hook jest.mock('~/hooks/useLocalize', () => () => (key: string) => key); // Mock useDebounce hook jest.mock('~/hooks', () => ({ useDebounce: (value: string, delay: number) => value, // Return value immediately for testing })); describe('SearchBar', () => { const mockOnSearch = jest.fn(); const user = userEvent.setup(); beforeEach(() => { mockOnSearch.mockClear(); }); it('renders with correct placeholder', () => { render(); const input = screen.getByRole('textbox'); expect(input).toBeInTheDocument(); expect(input).toHaveAttribute('placeholder', 'com_agents_search_placeholder'); }); it('displays the provided value', () => { render(); const input = screen.getByDisplayValue('test query'); expect(input).toBeInTheDocument(); }); it('calls onSearch when user types', async () => { render(); const input = screen.getByRole('textbox'); await user.type(input, 'test'); // Should call onSearch for each character due to debounce mock expect(mockOnSearch).toHaveBeenCalled(); }); it('shows clear button when there is text', () => { render(); const clearButton = screen.getByRole('button', { name: 'com_agents_clear_search' }); expect(clearButton).toBeInTheDocument(); }); it('does not show clear button when text is empty', () => { render(); const clearButton = screen.queryByRole('button', { name: 'com_agents_clear_search' }); expect(clearButton).not.toBeInTheDocument(); }); it('clears search when clear button is clicked', async () => { render(); const input = screen.getByRole('textbox'); const clearButton = screen.getByRole('button', { name: 'com_agents_clear_search' }); // Verify initial state expect(input).toHaveValue('test'); await user.click(clearButton); // Verify onSearch is called and input is cleared expect(mockOnSearch).toHaveBeenCalledWith(''); expect(input).toHaveValue(''); }); it('updates internal state when value prop changes', () => { const { rerender } = render(); expect(screen.getByDisplayValue('initial')).toBeInTheDocument(); rerender(); expect(screen.getByDisplayValue('updated')).toBeInTheDocument(); }); it('has proper accessibility attributes', () => { render(); const input = screen.getByRole('textbox'); expect(input).toHaveAttribute('aria-label', 'com_agents_search_aria'); }); it('applies custom className', () => { render(); const container = screen.getByRole('textbox').closest('div'); expect(container).toHaveClass('custom-class'); }); it('prevents form submission on clear button click', async () => { const handleSubmit = jest.fn(); render(
, ); const clearButton = screen.getByRole('button', { name: 'com_agents_clear_search' }); await user.click(clearButton); expect(handleSubmit).not.toHaveBeenCalled(); }); it('handles rapid typing correctly', async () => { render(); const input = screen.getByRole('textbox'); // Type multiple characters quickly await user.type(input, 'quick'); // Should handle all characters expect(input).toHaveValue('quick'); }); it('maintains focus after clear button click', async () => { render(); const input = screen.getByRole('textbox'); const clearButton = screen.getByRole('button', { name: 'com_agents_clear_search' }); input.focus(); await user.click(clearButton); // Input should still be in the document and ready for new input expect(input).toBeInTheDocument(); }); });