193 lines
5.8 KiB
Markdown
193 lines
5.8 KiB
Markdown
# Agent 2: Search Debounce Test Plan
|
|
|
|
## Manual Testing Steps
|
|
|
|
### Test 1: Basic Debounce
|
|
1. Open any document in NaviDocs
|
|
2. Type "engine" in search box
|
|
3. **Expected**: See loading spinner appear after typing stops
|
|
4. **Expected**: Search executes 300ms after last keystroke
|
|
5. **Expected**: Results appear highlighted in document
|
|
|
|
### Test 2: Cancellation on New Input
|
|
1. Type "eng"
|
|
2. Wait 200ms (before search triggers)
|
|
3. Continue typing "ine"
|
|
4. **Expected**: Previous pending search is cancelled
|
|
5. **Expected**: New 300ms timer starts
|
|
6. **Expected**: Only one search executes (for "engine")
|
|
|
|
### Test 3: Minimum Query Length
|
|
1. Type "e" (1 character)
|
|
2. **Expected**: No search executes
|
|
3. **Expected**: No loading spinner
|
|
4. Type "n" (now "en", 2 characters)
|
|
5. **Expected**: Search triggers after 300ms
|
|
6. **Expected**: Results appear
|
|
|
|
### Test 4: Clear Search
|
|
1. Type "engine" and wait for results
|
|
2. Click the X (clear) button
|
|
3. **Expected**: Input clears immediately
|
|
4. **Expected**: Results clear immediately
|
|
5. **Expected**: No highlights remain
|
|
|
|
### Test 5: Backspace to < 2 Characters
|
|
1. Type "engine" and wait for results
|
|
2. Backspace to "en"
|
|
3. **Expected**: New search executes after 300ms
|
|
4. Backspace to "e"
|
|
5. **Expected**: Results clear immediately
|
|
6. **Expected**: No search executes
|
|
|
|
### Test 6: Loading Indicator
|
|
1. Type "engine"
|
|
2. **Expected**: Search button shows spinning icon
|
|
3. **Expected**: Button is disabled during search
|
|
4. **Expected**: Tooltip shows "Searching..."
|
|
5. Wait for search to complete
|
|
6. **Expected**: Search icon returns
|
|
7. **Expected**: Tooltip shows "Search"
|
|
|
|
### Test 7: Rapid Typing
|
|
1. Type "abcdefghijklmnop" quickly without pausing
|
|
2. **Expected**: Loading state appears
|
|
3. **Expected**: Only ONE search executes (after typing stops)
|
|
4. **Expected**: No multiple searches for intermediate strings
|
|
|
|
### Test 8: Enter Key Override
|
|
1. Type "eng" (3 characters)
|
|
2. Press Enter immediately (don't wait for debounce)
|
|
3. **Expected**: Search executes immediately
|
|
4. **Expected**: Debounce timer is bypassed
|
|
|
|
### Test 9: Multiple Cancel Operations
|
|
1. Type "test"
|
|
2. Before search executes, type "search"
|
|
3. Before that executes, clear input
|
|
4. **Expected**: No errors in console
|
|
5. **Expected**: All abort controllers cleaned up properly
|
|
|
|
### Test 10: Cross-Page Search Integration
|
|
1. Type "engine" and wait for results
|
|
2. **Expected**: Current page highlights appear
|
|
3. **Expected**: Background cross-page search starts
|
|
4. **Expected**: Total match count includes all pages
|
|
5. Navigate to next/previous match
|
|
6. **Expected**: Navigation works correctly
|
|
|
|
## Automated Test Scenarios (for future implementation)
|
|
|
|
```javascript
|
|
describe('Search Debounce', () => {
|
|
it('should debounce search by 300ms', async () => {
|
|
// Type characters
|
|
await typeText('engine')
|
|
|
|
// Verify search hasn't executed yet
|
|
expect(performSearch).not.toHaveBeenCalled()
|
|
|
|
// Wait 300ms
|
|
await delay(300)
|
|
|
|
// Verify search executed
|
|
expect(performSearch).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('should cancel previous search on new input', async () => {
|
|
await typeText('eng')
|
|
await delay(200)
|
|
await typeText('ine')
|
|
|
|
// Only one search should execute
|
|
await delay(300)
|
|
expect(performSearch).toHaveBeenCalledTimes(1)
|
|
expect(performSearch).toHaveBeenCalledWith('engine')
|
|
})
|
|
|
|
it('should not search for queries < 2 chars', async () => {
|
|
await typeText('e')
|
|
await delay(300)
|
|
|
|
expect(performSearch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('should show loading indicator', async () => {
|
|
await typeText('engine')
|
|
|
|
expect(isSearching.value).toBe(true)
|
|
expect(searchButton.querySelector('.animate-spin')).toBeInTheDocument()
|
|
|
|
await delay(300)
|
|
await waitFor(() => expect(isSearching.value).toBe(false))
|
|
})
|
|
})
|
|
```
|
|
|
|
## Performance Verification
|
|
|
|
### Metrics to Check
|
|
- **Debounce delay**: Should be exactly 300ms
|
|
- **Search cancellation**: Previous searches should abort properly
|
|
- **Memory leaks**: No timers or controllers left hanging
|
|
- **UI responsiveness**: No lag during typing
|
|
- **Search execution**: Only one search per debounce period
|
|
|
|
### Console Checks
|
|
```javascript
|
|
// Should see ONE log after typing "engine":
|
|
console.log("Found X matches across Y pages")
|
|
|
|
// Should NOT see:
|
|
console.error("Search error:")
|
|
console.warn("Failed to abort search")
|
|
```
|
|
|
|
## Edge Cases
|
|
|
|
### Concurrent Operations
|
|
- ✅ Typing while previous search is running
|
|
- ✅ Clearing input while search is running
|
|
- ✅ Navigating away while search is running
|
|
- ✅ Closing document while search is running
|
|
|
|
### Boundary Conditions
|
|
- ✅ Empty string → No search
|
|
- ✅ 1 character → No search
|
|
- ✅ 2 characters → Search executes
|
|
- ✅ Very long query → Search executes normally
|
|
|
|
### State Cleanup
|
|
- ✅ Timer cleared on new input
|
|
- ✅ Abort controller cleared on completion
|
|
- ✅ Loading state reset on error
|
|
- ✅ All state reset on clear
|
|
|
|
## Success Criteria
|
|
|
|
✅ Search executes 300ms after user stops typing
|
|
✅ Loading indicator shows during search
|
|
✅ Previous searches cancel when new input arrives
|
|
✅ Results update in real-time
|
|
✅ Clearing input clears results immediately
|
|
✅ Queries < 2 characters don't trigger search
|
|
✅ No console errors
|
|
✅ No memory leaks
|
|
✅ Smooth user experience
|
|
|
|
## Known Limitations
|
|
|
|
1. **Debounce timing**: 300ms is hardcoded (could be configurable)
|
|
2. **Minimum query length**: 2 characters is hardcoded (could be configurable)
|
|
3. **No search history**: Previous searches not saved
|
|
4. **No smart cancellation**: Cancels even if query prefix matches
|
|
|
|
## Future Enhancements
|
|
|
|
1. Make debounce delay configurable via settings
|
|
2. Add search history dropdown
|
|
3. Implement smart cancellation (don't cancel if new query starts with old)
|
|
4. Add search suggestions/autocomplete
|
|
5. Persist search state across page navigation
|
|
6. Add keyboard shortcuts (Cmd+G for next match)
|
|
7. Add search within results filtering
|