import { describe, test, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import AdvancedSearchPanel from '../AdvancedSearchPanel';
const mockSettings = {
useEnhancedSearch: true,
searchMode: 'simple' as const,
includeSnippets: true,
snippetLength: 200,
fuzzyThreshold: 0.8,
resultLimit: 100,
includeOcrText: true,
includeFileContent: true,
includeFilenames: true,
boostRecentDocs: false,
enableAutoCorrect: true,
};
const mockPresets = [
{
name: 'Fast Search',
settings: {
...mockSettings,
includeSnippets: false,
resultLimit: 50,
},
},
{
name: 'Detailed Search',
settings: {
...mockSettings,
snippetLength: 400,
resultLimit: 200,
},
},
];
describe('AdvancedSearchPanel', () => {
const mockOnSettingsChange = vi.fn();
const mockOnExpandedChange = vi.fn();
const mockOnSavePreset = vi.fn();
const mockOnLoadPreset = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
});
test('renders collapsed state by default', () => {
render(
);
expect(screen.getByText('Advanced Search Options')).toBeInTheDocument();
expect(screen.getByText('Customize search behavior and result display')).toBeInTheDocument();
expect(screen.getByText('SIMPLE')).toBeInTheDocument();
expect(screen.queryByText('Search Behavior')).not.toBeInTheDocument();
});
test('expands when expanded prop is true', () => {
render(
);
expect(screen.getByText('Search Behavior')).toBeInTheDocument();
expect(screen.getByText('Results Display')).toBeInTheDocument();
expect(screen.getByText('Performance')).toBeInTheDocument();
expect(screen.getByText('Content Sources')).toBeInTheDocument();
});
test('calls onExpandedChange when header is clicked', async () => {
const user = userEvent.setup();
render(
);
const header = screen.getByText('Advanced Search Options').closest('div');
await user.click(header!);
expect(mockOnExpandedChange).toHaveBeenCalledWith(true);
});
test('displays search behavior section by default when expanded', () => {
render(
);
expect(screen.getByText('These settings control how your search queries are interpreted and matched against documents.')).toBeInTheDocument();
expect(screen.getByDisplayValue('simple')).toBeInTheDocument();
expect(screen.getByLabelText('Enhanced Search Engine')).toBeInTheDocument();
});
test('switches between sections correctly', async () => {
const user = userEvent.setup();
render(
);
// Click on Results Display section
await user.click(screen.getByText('Results Display'));
expect(screen.getByText('Control how search results are presented and what information is shown.')).toBeInTheDocument();
expect(screen.getByLabelText('Show Text Snippets')).toBeInTheDocument();
});
test('changes search mode setting', async () => {
const user = userEvent.setup();
render(
);
const searchModeSelect = screen.getByDisplayValue('simple');
await user.click(searchModeSelect);
const fuzzyOption = screen.getByText('Fuzzy Search');
await user.click(fuzzyOption);
expect(mockOnSettingsChange).toHaveBeenCalledWith({ searchMode: 'fuzzy' });
});
test('toggles enhanced search setting', async () => {
const user = userEvent.setup();
render(
);
const enhancedSearchSwitch = screen.getByLabelText('Enhanced Search Engine');
await user.click(enhancedSearchSwitch);
expect(mockOnSettingsChange).toHaveBeenCalledWith({ useEnhancedSearch: false });
});
test('adjusts fuzzy threshold when in fuzzy mode', async () => {
const user = userEvent.setup();
const fuzzySettings = { ...mockSettings, searchMode: 'fuzzy' as const };
render(
);
const fuzzySlider = screen.getByRole('slider', { name: /fuzzy match threshold/i });
expect(fuzzySlider).not.toHaveAttribute('disabled');
});
test('disables fuzzy threshold when not in fuzzy mode', () => {
render(
);
const fuzzySlider = screen.getByRole('slider', { name: /fuzzy match threshold/i });
expect(fuzzySlider).toHaveAttribute('disabled');
});
test('shows results display settings correctly', async () => {
const user = userEvent.setup();
render(
);
await user.click(screen.getByText('Results Display'));
expect(screen.getByLabelText('Show Text Snippets')).toBeChecked();
expect(screen.getByDisplayValue('200')).toBeInTheDocument(); // Snippet length
expect(screen.getByDisplayValue('100')).toBeInTheDocument(); // Results per page
});
test('disables snippet length when snippets are disabled', async () => {
const user = userEvent.setup();
const settingsWithoutSnippets = { ...mockSettings, includeSnippets: false };
render(
);
await user.click(screen.getByText('Results Display'));
const snippetLengthSelect = screen.getByLabelText('Snippet Length');
expect(snippetLengthSelect.closest('div')).toHaveClass('Mui-disabled');
});
test('shows content sources settings', async () => {
const user = userEvent.setup();
render(
);
await user.click(screen.getByText('Content Sources'));
expect(screen.getByLabelText('Document Content')).toBeChecked();
expect(screen.getByLabelText('OCR Extracted Text')).toBeChecked();
expect(screen.getByLabelText('Filenames')).toBeChecked();
});
test('shows performance settings with warning', async () => {
const user = userEvent.setup();
render(
);
await user.click(screen.getByText('Performance'));
expect(screen.getByText('These settings can affect search speed. Use with caution for large document collections.')).toBeInTheDocument();
expect(screen.getByRole('slider', { name: /maximum results/i })).toBeInTheDocument();
});
test('resets to defaults when reset button is clicked', async () => {
const user = userEvent.setup();
render(
);
const resetButton = screen.getByText('Reset to Defaults');
await user.click(resetButton);
expect(mockOnSettingsChange).toHaveBeenCalledWith({
useEnhancedSearch: true,
searchMode: 'simple',
includeSnippets: true,
snippetLength: 200,
fuzzyThreshold: 0.8,
resultLimit: 100,
includeOcrText: true,
includeFileContent: true,
includeFilenames: true,
boostRecentDocs: false,
enableAutoCorrect: true,
});
});
test('shows save preset dialog when save preset is clicked', async () => {
const user = userEvent.setup();
render(
);
const saveButton = screen.getByText('Save Preset');
await user.click(saveButton);
expect(screen.getByText('Save Current Settings as Preset')).toBeInTheDocument();
expect(screen.getByLabelText('Preset Name')).toBeInTheDocument();
});
test('saves preset with valid name', async () => {
const user = userEvent.setup();
render(
);
await user.click(screen.getByText('Save Preset'));
const nameInput = screen.getByLabelText('Preset Name');
await user.type(nameInput, 'My Custom Preset');
const saveButton = screen.getByRole('button', { name: 'Save' });
await user.click(saveButton);
expect(mockOnSavePreset).toHaveBeenCalledWith('My Custom Preset', mockSettings);
});
test('shows preset selector when presets are available', () => {
render(
);
expect(screen.getByLabelText('Load Preset')).toBeInTheDocument();
});
test('loads preset when selected', async () => {
const user = userEvent.setup();
render(
);
const presetSelect = screen.getByLabelText('Load Preset');
await user.click(presetSelect);
const fastSearchOption = screen.getByText('Fast Search');
await user.click(fastSearchOption);
expect(mockOnLoadPreset).toHaveBeenCalledWith(mockPresets[0].settings);
});
test('shows enhanced search badge when enabled', () => {
render(
);
// Badge should be visible (not invisible) when enhanced search is enabled
const badge = screen.getByText('Advanced Search Options').closest('div')?.querySelector('[class*="MuiBadge"]');
expect(badge).toBeInTheDocument();
});
test('hides badge when enhanced search is disabled', () => {
const settingsWithoutEnhanced = { ...mockSettings, useEnhancedSearch: false };
render(
);
// Badge should be invisible when enhanced search is disabled
const badge = screen.getByText('Advanced Search Options').closest('div')?.querySelector('[class*="MuiBadge"]');
expect(badge).toBeInTheDocument(); // Badge element exists but should be invisible
});
test('cancels preset save when cancel is clicked', async () => {
const user = userEvent.setup();
render(
);
await user.click(screen.getByText('Save Preset'));
const cancelButton = screen.getByText('Cancel');
await user.click(cancelButton);
expect(screen.queryByText('Save Current Settings as Preset')).not.toBeInTheDocument();
});
test('shows correct search mode descriptions', () => {
render(
);
expect(screen.getByText('Basic keyword matching with stemming')).toBeInTheDocument();
});
});