Files
tolaria/src/components/SearchPanel.test.tsx

437 lines
14 KiB
TypeScript
Raw Normal View History

feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { SearchPanel } from './SearchPanel'
import type { VaultEntry } from '../types'
// Mock the mock-tauri module (component uses mockInvoke when isTauri() is false)
vi.mock('../mock-tauri', () => ({
mockInvoke: vi.fn(),
isTauri: () => false,
}))
import { mockInvoke } from '../mock-tauri'
const mockInvokeFn = vi.mocked(mockInvoke)
const NOW_TS = Date.now() / 1000
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
const MOCK_ENTRIES: VaultEntry[] = [
{
path: '/vault/essay/ai-apis.md',
filename: 'ai-apis.md',
title: 'How to Design AI-first APIs',
isA: 'Essay',
aliases: [],
belongsTo: [],
relatedTo: [],
status: null,
owner: null,
cadence: null,
archived: false,
trashed: false,
trashedAt: null,
modifiedAt: NOW_TS - 3600,
createdAt: NOW_TS - 86400 * 30,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
fileSize: 500,
snippet: 'A guide to designing APIs for AI',
wordCount: 1240,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
relationships: {},
icon: null,
color: null,
order: null,
outgoingLinks: ['topic/ai', 'topic/apis', 'person/luca'],
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
},
{
path: '/vault/event/retreat.md',
filename: 'retreat.md',
title: 'Refactoring Retreat',
isA: 'Event',
aliases: [],
belongsTo: [],
relatedTo: [],
status: null,
owner: null,
cadence: null,
archived: false,
trashed: false,
trashedAt: null,
modifiedAt: NOW_TS,
createdAt: NOW_TS,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
fileSize: 300,
snippet: 'Team retreat event',
wordCount: 0,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
relationships: {},
icon: null,
color: null,
order: null,
outgoingLinks: [],
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
},
]
describe('SearchPanel', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('renders nothing when closed', () => {
const { container } = render(
<SearchPanel open={false} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
expect(container.innerHTML).toBe('')
})
it('renders search input when open', () => {
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
expect(screen.getByPlaceholderText('Search in all notes...')).toBeInTheDocument()
})
it('shows empty state hint when no query', () => {
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
expect(screen.getByText('Search across all note contents')).toBeInTheDocument()
expect(screen.getByText('Enter to open · Esc to close')).toBeInTheDocument()
})
it('has no keyword/semantic toggle', () => {
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
expect(screen.queryByText('Keyword')).not.toBeInTheDocument()
expect(screen.queryByText('Semantic')).not.toBeInTheDocument()
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
})
it('calls onClose when clicking overlay', () => {
const onClose = vi.fn()
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={onClose} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
const overlay = screen.getByPlaceholderText('Search in all notes...').closest('.fixed')!
fireEvent.click(overlay)
expect(onClose).toHaveBeenCalled()
})
it('calls onClose on Escape key', () => {
const onClose = vi.fn()
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={onClose} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
fireEvent.keyDown(window, { key: 'Escape' })
expect(onClose).toHaveBeenCalled()
})
it('performs unified search with keyword then hybrid', async () => {
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
mockInvokeFn.mockResolvedValue({
results: [
{ title: 'How to Design AI-first APIs', path: '/vault/essay/ai-apis.md', snippet: '...designing APIs for AI...', score: 0.87, note_type: 'Essay' },
],
elapsed_ms: 48,
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
const input = screen.getByPlaceholderText('Search in all notes...')
fireEvent.change(input, { target: { value: 'api design' } })
// Should call keyword search first
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
await waitFor(() => {
expect(mockInvokeFn).toHaveBeenCalledWith('search_vault', {
vaultPath: '/vault',
query: 'api design',
mode: 'keyword',
limit: 20,
})
})
// Results should appear
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
await waitFor(() => {
expect(screen.getByText('How to Design AI-first APIs')).toBeInTheDocument()
})
// Should also call hybrid search
await waitFor(() => {
expect(mockInvokeFn).toHaveBeenCalledWith('search_vault', {
vaultPath: '/vault',
query: 'api design',
mode: 'hybrid',
limit: 20,
})
})
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
})
it('shows no results message when search returns empty', async () => {
mockInvokeFn.mockResolvedValue({ results: [], elapsed_ms: 10 })
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
const input = screen.getByPlaceholderText('Search in all notes...')
fireEvent.change(input, { target: { value: 'xyznonexistent' } })
await waitFor(() => {
expect(screen.getByText('No results found')).toBeInTheDocument()
})
})
it('navigates results with arrow keys', async () => {
mockInvokeFn.mockResolvedValue({
results: [
{ title: 'Result One', path: '/vault/essay/ai-apis.md', snippet: 'First result', score: 0.9, note_type: null },
{ title: 'Result Two', path: '/vault/event/retreat.md', snippet: 'Second result', score: 0.8, note_type: null },
],
elapsed_ms: 20,
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
const input = screen.getByPlaceholderText('Search in all notes...')
fireEvent.change(input, { target: { value: 'test' } })
await waitFor(() => {
expect(screen.getByText('Result One')).toBeInTheDocument()
})
fireEvent.keyDown(window, { key: 'ArrowDown' })
await waitFor(() => {
const resultTwo = screen.getByText('Result Two').closest('[class*="cursor-pointer"]')!
expect(resultTwo.className).toContain('bg-accent')
})
})
it('selects result on Enter and calls onSelectNote', async () => {
mockInvokeFn.mockResolvedValue({
results: [
{ title: 'How to Design AI-first APIs', path: '/vault/essay/ai-apis.md', snippet: 'First', score: 0.9, note_type: null },
],
elapsed_ms: 20,
})
const onSelectNote = vi.fn()
const onClose = vi.fn()
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={onSelectNote} onClose={onClose} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'api' } })
await waitFor(() => {
expect(screen.getByText('How to Design AI-first APIs')).toBeInTheDocument()
})
fireEvent.keyDown(window, { key: 'Enter' })
await waitFor(() => {
expect(onSelectNote).toHaveBeenCalledWith(MOCK_ENTRIES[0])
expect(onClose).toHaveBeenCalled()
})
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
})
it('shows result count and elapsed time', async () => {
mockInvokeFn.mockResolvedValue({
results: [
{ title: 'Result', path: '/vault/essay/ai-apis.md', snippet: 'Content', score: 0.9, note_type: null },
],
elapsed_ms: 123,
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'test' } })
await waitFor(() => {
expect(screen.getByText(/1 result/)).toBeInTheDocument()
expect(screen.getByText(/123ms/)).toBeInTheDocument()
})
})
it('displays note type badge from vault entries', async () => {
mockInvokeFn.mockResolvedValue({
results: [
{ title: 'How to Design AI-first APIs', path: '/vault/essay/ai-apis.md', snippet: 'Content', score: 0.9, note_type: null },
],
elapsed_ms: 20,
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'api' } })
await waitFor(() => {
expect(screen.getByText('Essay')).toBeInTheDocument()
})
})
it('shows loading spinner while searching', async () => {
const resolvers: ((v: unknown) => void)[] = []
mockInvokeFn.mockImplementation(
() => new Promise(resolve => { resolvers.push(resolve) }),
)
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'test' } })
// Spinner appears when keyword search starts (after debounce)
await waitFor(() => {
expect(screen.getByTestId('search-spinner')).toBeInTheDocument()
})
// Resolve keyword search
resolvers[0]({
results: [{ title: 'Result', path: '/vault/essay/ai-apis.md', snippet: '', score: 0.9, note_type: null }],
elapsed_ms: 30,
})
// Keyword results appear, spinner still visible (hybrid in progress)
await waitFor(() => {
expect(screen.getByText('Result')).toBeInTheDocument()
expect(screen.getByTestId('search-spinner')).toBeInTheDocument()
})
// Wait for hybrid call then resolve it
await waitFor(() => { expect(resolvers).toHaveLength(2) })
resolvers[1]({
results: [{ title: 'Result', path: '/vault/essay/ai-apis.md', snippet: '', score: 0.9, note_type: null }],
elapsed_ms: 150,
})
// Spinner disappears after hybrid completes
await waitFor(() => {
expect(screen.queryByTestId('search-spinner')).not.toBeInTheDocument()
})
})
it('discards stale results when query changes rapidly', async () => {
mockInvokeFn.mockImplementation(async (_cmd: string, args?: Record<string, unknown>) => {
const q = (args as Record<string, string>)?.query
if (q === 'second') {
return {
results: [{ title: 'Second Result', path: '/vault/event/retreat.md', snippet: '', score: 0.9, note_type: null }],
elapsed_ms: 30,
}
}
return { results: [], elapsed_ms: 0 }
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
const input = screen.getByPlaceholderText('Search in all notes...')
// Type first query, then immediately change to second (within debounce)
fireEvent.change(input, { target: { value: 'first' } })
fireEvent.change(input, { target: { value: 'second' } })
// Only second query results should appear
await waitFor(() => {
expect(screen.getByText('Second Result')).toBeInTheDocument()
})
})
it('keeps keyword results when hybrid search fails', async () => {
mockInvokeFn.mockImplementation(async (_cmd: string, args?: Record<string, unknown>) => {
const mode = (args as Record<string, string>)?.mode
if (mode === 'keyword') {
return {
results: [{ title: 'Keyword Only', path: '/vault/essay/ai-apis.md', snippet: '', score: 0.9, note_type: null }],
elapsed_ms: 30,
}
}
throw new Error('qmd unavailable')
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'test' } })
// Keyword results appear
await waitFor(() => {
expect(screen.getByText('Keyword Only')).toBeInTheDocument()
})
// Spinner disappears after hybrid fails
await waitFor(() => {
expect(screen.queryByTestId('search-spinner')).not.toBeInTheDocument()
})
// Keyword results remain
expect(screen.getByText('Keyword Only')).toBeInTheDocument()
})
feat: status property — Notion-style dropdown with color chips (#97) * fix: resolve search panel freeze by making search_vault async The search_vault Tauri command was synchronous (fn, not async fn), blocking the main thread for 30+ seconds during hybrid/semantic search on large vaults (9200+ files). This caused the macOS beachball. Changes: - Make search_vault async with tokio::spawn_blocking (runs qmd off main thread) - Cache collection name per vault path (avoid repeated qmd collection list calls) - Cancel inflight searches and debounce timers when panel closes - Add regression test for stale result cancellation on panel close Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * design: add status property dropdown wireframes Three frames: closed pill state, open dropdown with suggested/vault statuses, and custom status creation flow. Also bump flaky NoteList 9000-entry test timeout from 15s to 30s. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: replace status text edit with Notion-style dropdown - Extract STATUS_STYLES to shared statusStyles.ts utility - New StatusDropdown component: filterable popover with colored pills - StatusPill reusable component for consistent status chip rendering - Vault-wide status aggregation from entries prop - Dropdown shows "From vault" and "Suggested" sections - Custom status creation via type-and-Enter - Escape/backdrop click cancels without saving - Keyboard navigation (ArrowUp/Down + Enter) - 22 new tests covering dropdown behavior + integration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: cargo fmt --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:40:27 +01:00
it('shows metadata subtitle on search results', async () => {
mockInvokeFn.mockResolvedValue({
results: [
{ title: 'How to Design AI-first APIs', path: '/vault/essay/ai-apis.md', snippet: 'API content', score: 0.9, note_type: 'Essay' },
],
elapsed_ms: 50,
})
render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'api' } })
await waitFor(() => {
const meta = screen.getByTestId('search-result-meta')
expect(meta).toBeInTheDocument()
expect(meta.textContent).toContain('words')
expect(meta.textContent).toContain('3 links')
expect(meta.textContent).toContain('Created')
})
})
feat: status property — Notion-style dropdown with color chips (#97) * fix: resolve search panel freeze by making search_vault async The search_vault Tauri command was synchronous (fn, not async fn), blocking the main thread for 30+ seconds during hybrid/semantic search on large vaults (9200+ files). This caused the macOS beachball. Changes: - Make search_vault async with tokio::spawn_blocking (runs qmd off main thread) - Cache collection name per vault path (avoid repeated qmd collection list calls) - Cancel inflight searches and debounce timers when panel closes - Add regression test for stale result cancellation on panel close Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * design: add status property dropdown wireframes Three frames: closed pill state, open dropdown with suggested/vault statuses, and custom status creation flow. Also bump flaky NoteList 9000-entry test timeout from 15s to 30s. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: replace status text edit with Notion-style dropdown - Extract STATUS_STYLES to shared statusStyles.ts utility - New StatusDropdown component: filterable popover with colored pills - StatusPill reusable component for consistent status chip rendering - Vault-wide status aggregation from entries prop - Dropdown shows "From vault" and "Suggested" sections - Custom status creation via type-and-Enter - Escape/backdrop click cancels without saving - Keyboard navigation (ArrowUp/Down + Enter) - 22 new tests covering dropdown behavior + integration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: cargo fmt --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:40:27 +01:00
it('cancels inflight searches when panel closes', async () => {
const resolvers: ((v: unknown) => void)[] = []
mockInvokeFn.mockImplementation(
() => new Promise(resolve => { resolvers.push(resolve) }),
)
const { rerender } = render(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
fireEvent.change(screen.getByPlaceholderText('Search in all notes...'), { target: { value: 'slow query' } })
// Wait for keyword search to start
await waitFor(() => {
expect(resolvers).toHaveLength(1)
})
// Close the panel while search is inflight
rerender(
<SearchPanel open={false} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
// Resolve the inflight keyword search — should be discarded (stale generation)
resolvers[0]({
results: [{ title: 'Stale Result', path: '/vault/essay/ai-apis.md', snippet: '', score: 0.9, note_type: null }],
elapsed_ms: 30,
})
// Reopen panel
rerender(
<SearchPanel open={true} vaultPath="/vault" entries={MOCK_ENTRIES} onSelectNote={vi.fn()} onClose={vi.fn()} />,
)
// Should NOT show the stale result — panel was reset
expect(screen.queryByText('Stale Result')).not.toBeInTheDocument()
expect(screen.getByText('Search across all note contents')).toBeInTheDocument()
})
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64) * feat: add search backend (qmd CLI) and design file - Add search.rs: qmd integration for keyword (BM25), semantic (vsearch), and hybrid search modes via CLI JSON output - Register search_vault Tauri command in lib.rs - Design file with 3 frames: empty, results, no-results states - Fix pre-existing test failures: install @tauri-apps/plugin-opener, add mock in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add SearchPanel UI with Cmd+Shift+F shortcut - SearchPanel component: full-text search overlay with keyword/semantic mode toggle, debounced search (200ms), arrow key navigation, result count + elapsed time display, note type badges from vault entries - Cmd+Shift+F shortcut registered in useAppKeyboard - Mock search_vault handler in mock-tauri for browser dev mode - SearchResult/SearchResponse types in types.ts - Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut - scrollIntoView mock in test setup for jsdom compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct SearchPanel imports for Tauri/browser dual-mode Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri with a searchCall wrapper, fixing the TypeScript build error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: make test_detect_collection_fallback robust when qmd not installed * fix: reset localStorage between App tests to prevent view mode state leak --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
})