155 lines
4.2 KiB
JavaScript
155 lines
4.2 KiB
JavaScript
/**
|
|
* SearchBar Component Tests
|
|
* Verifies search UI rendering and interactions
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { mount } from '@vue/test-utils';
|
|
import { ref } from 'vue';
|
|
import SearchBar from '../../../../src/components/gamemaster/SearchBar.vue';
|
|
import { useGamemasterSearch } from '../../../../src/composables/useGamemasterSearch.js';
|
|
|
|
vi.mock('../../../../src/composables/useGamemasterSearch.js', () => ({
|
|
useGamemasterSearch: vi.fn()
|
|
}));
|
|
|
|
const createSearchMock = overrides => ({
|
|
searchQuery: ref(''),
|
|
searchResults: ref([]),
|
|
currentResultIndex: ref(0),
|
|
isSearching: ref(false),
|
|
searchError: ref(null),
|
|
searchHistory: { history: ref([]) },
|
|
clearSearch: vi.fn(),
|
|
goToNextResult: vi.fn(),
|
|
goToPrevResult: vi.fn(),
|
|
applyHistoryItem: vi.fn(),
|
|
currentResultLineNumber: ref(null),
|
|
resultCountDisplay: ref('0 results'),
|
|
hasSearchResults: ref(false),
|
|
...overrides
|
|
});
|
|
|
|
describe('SearchBar Component', () => {
|
|
let mockSearch;
|
|
|
|
beforeEach(() => {
|
|
mockSearch = createSearchMock();
|
|
useGamemasterSearch.mockReturnValue(mockSearch);
|
|
});
|
|
|
|
it('renders the search input', () => {
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: ['line one'],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
const input = wrapper.find('input.search-input');
|
|
expect(input.exists()).toBe(true);
|
|
expect(input.attributes('placeholder')).toContain('Search in file');
|
|
});
|
|
|
|
it('disables input when fileLines are empty', () => {
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: [],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
const input = wrapper.find('input.search-input');
|
|
expect(input.attributes('disabled')).toBeDefined();
|
|
});
|
|
|
|
it('shows clear button when searchQuery is not empty', async () => {
|
|
mockSearch.searchQuery.value = 'Pikachu';
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: ['line one'],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
const clearButton = wrapper.find('button.btn-clear');
|
|
expect(clearButton.exists()).toBe(true);
|
|
|
|
await clearButton.trigger('click');
|
|
expect(mockSearch.clearSearch).toHaveBeenCalled();
|
|
});
|
|
|
|
it('renders search results summary and line number', () => {
|
|
mockSearch.hasSearchResults.value = true;
|
|
mockSearch.resultCountDisplay.value = '2 / 5';
|
|
mockSearch.currentResultLineNumber.value = 42;
|
|
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: ['line one'],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
const results = wrapper.find('.search-results');
|
|
expect(results.exists()).toBe(true);
|
|
expect(results.text()).toContain('2 / 5');
|
|
expect(results.text()).toContain('Line 42');
|
|
|
|
const titleSpan = results.find('span');
|
|
expect(titleSpan.attributes('title')).toBe('Line 42');
|
|
});
|
|
|
|
it('triggers next/previous navigation', async () => {
|
|
mockSearch.hasSearchResults.value = true;
|
|
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: ['line one'],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
const buttons = wrapper.findAll('button.btn-nav');
|
|
expect(buttons.length).toBe(2);
|
|
|
|
await buttons[0].trigger('click');
|
|
await buttons[1].trigger('click');
|
|
|
|
expect(mockSearch.goToPrevResult).toHaveBeenCalled();
|
|
expect(mockSearch.goToNextResult).toHaveBeenCalled();
|
|
});
|
|
|
|
it('renders search history items and applies selection', async () => {
|
|
mockSearch.searchHistory.history.value = ['Pikachu', 'Charizard'];
|
|
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: ['line one'],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
const historyButtons = wrapper.findAll('button.history-item');
|
|
expect(historyButtons.length).toBe(2);
|
|
|
|
await historyButtons[0].trigger('click');
|
|
expect(mockSearch.applyHistoryItem).toHaveBeenCalledWith('Pikachu');
|
|
});
|
|
|
|
it('shows error and searching status', () => {
|
|
mockSearch.searchError.value = 'Worker failed';
|
|
mockSearch.isSearching.value = true;
|
|
|
|
const wrapper = mount(SearchBar, {
|
|
props: {
|
|
fileLines: ['line one'],
|
|
displayLines: []
|
|
}
|
|
});
|
|
|
|
expect(wrapper.find('.search-error').text()).toContain('Worker failed');
|
|
expect(wrapper.find('.search-status').text()).toContain('Searching');
|
|
});
|
|
});
|