From f30c7880f67ae9351c0b5ebd7da9d054b8e675c9 Mon Sep 17 00:00:00 2001 From: FragginWagon Date: Thu, 29 Jan 2026 03:51:06 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Update=20progress=20documentation?= =?UTF-8?q?=20to=20reflect=20completed=20SearchBar=20component=20and=20add?= =?UTF-8?q?itional=20passing=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/gamemaster/SearchBar.vue | 206 ++++++++++++++++++ .../components/gamemaster/SearchBar.test.js | 154 +++++++++++++ docs/projects/Pokedex.Online/PROGRESS.md | 20 +- 3 files changed, 370 insertions(+), 10 deletions(-) create mode 100644 code/websites/pokedex.online/src/components/gamemaster/SearchBar.vue create mode 100644 code/websites/pokedex.online/tests/unit/components/gamemaster/SearchBar.test.js diff --git a/code/websites/pokedex.online/src/components/gamemaster/SearchBar.vue b/code/websites/pokedex.online/src/components/gamemaster/SearchBar.vue new file mode 100644 index 0000000..f281cff --- /dev/null +++ b/code/websites/pokedex.online/src/components/gamemaster/SearchBar.vue @@ -0,0 +1,206 @@ + + + + + diff --git a/code/websites/pokedex.online/tests/unit/components/gamemaster/SearchBar.test.js b/code/websites/pokedex.online/tests/unit/components/gamemaster/SearchBar.test.js new file mode 100644 index 0000000..396e2de --- /dev/null +++ b/code/websites/pokedex.online/tests/unit/components/gamemaster/SearchBar.test.js @@ -0,0 +1,154 @@ +/** + * 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'); + }); +}); diff --git a/docs/projects/Pokedex.Online/PROGRESS.md b/docs/projects/Pokedex.Online/PROGRESS.md index 0119902..a28d1ce 100644 --- a/docs/projects/Pokedex.Online/PROGRESS.md +++ b/docs/projects/Pokedex.Online/PROGRESS.md @@ -7,9 +7,9 @@ Last Updated: January 28, 2026 **Total Phases:** 12 **Completed Phases:** 4 ✅ **Total Steps:** 68 -**Completed Steps:** 22 / 68 (32.4%) +**Completed Steps:** 23 / 68 (33.8%) -**Test Suite:** 283 tests passing ✅ +**Test Suite:** 290 tests passing ✅ --- @@ -123,7 +123,7 @@ Last Updated: January 28, 2026 --- -## Phase 5: GamemasterExplorer Refactoring (4/9 complete) +## Phase 5: GamemasterExplorer Refactoring (5/9 complete) **Duration**: 5-7 days **Status**: In Progress **Target**: Reduce from 1627 lines → ~400 lines (76% reduction) @@ -168,13 +168,13 @@ Last Updated: January 28, 2026 - Statistics calculation - Edge cases (circular refs, arrays, unicode) -### ⏳ Step 17: Create SearchBar Component -- [ ] Create `src/components/gamemaster/SearchBar.vue` -- [ ] Use `useGamemasterSearch` composable -- [ ] Implement search input with result counter -- [ ] Add next/previous result navigation -- [ ] Add clear/reset functionality -- [ ] Write component tests +### ✅ Step 17: Create SearchBar Component +- [x] Create `src/components/gamemaster/SearchBar.vue` +- [x] Use `useGamemasterSearch` composable +- [x] Implement search input with result counter +- [x] Add next/previous result navigation +- [x] Add clear/reset functionality +- [x] Write component tests - 7 tests passing ✅ ### ⏳ Step 18: Create FileSelector Component - [ ] Create `src/components/gamemaster/FileSelector.vue`