Files
bookmarksite/tests/test_advanced_search.html
Rainer Koschnick 0abee5b794 Add comprehensive database setup and user management system
- Implement PostgreSQL database schema with users and bookmarks tables
- Add database connection pooling with retry logic and error handling
- Create migration system with automatic schema initialization
- Add database CLI tools for management (init, status, validate, etc.)
- Include comprehensive error handling and diagnostics
- Add development seed data and testing utilities
- Implement health monitoring and connection pool statistics
- Create detailed documentation and troubleshooting guide

Database features:
- Users table with authentication fields and email verification
- Bookmarks table with user association and metadata
- Proper indexes for performance optimization
- Automatic timestamp triggers
- Transaction support with rollback handling
- Connection pooling (20 max connections, 30s idle timeout)
- Graceful shutdown handling

CLI commands available:
- npm run db:init - Initialize database
- npm run db:status - Check database status
- npm run db:validate - Validate schema
- npm run db:test - Run database tests
- npm run db:diagnostics - Full diagnostics
2025-07-19 23:21:50 +02:00

309 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Search Test</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.test-section { margin: 20px 0; padding: 15px; border: 1px solid #ddd; }
.test-result { margin: 10px 0; padding: 10px; }
.pass { background-color: #d4edda; color: #155724; }
.fail { background-color: #f8d7da; color: #721c24; }
button { margin: 5px; padding: 10px 15px; }
</style>
</head>
<body>
<h1>Advanced Search Functionality Test</h1>
<div class="test-section">
<h2>Test 1: Search within specific folders</h2>
<button onclick="testFolderSearch()">Test Folder Search</button>
<div id="folderSearchResult" class="test-result"></div>
</div>
<div class="test-section">
<h2>Test 2: Date-based filtering</h2>
<button onclick="testDateFiltering()">Test Date Filtering</button>
<div id="dateFilterResult" class="test-result"></div>
</div>
<div class="test-section">
<h2>Test 3: Search suggestions</h2>
<button onclick="testSearchSuggestions()">Test Search Suggestions</button>
<div id="suggestionsResult" class="test-result"></div>
</div>
<div class="test-section">
<h2>Test 4: Search history</h2>
<button onclick="testSearchHistory()">Test Search History</button>
<div id="historyResult" class="test-result"></div>
</div>
<div class="test-section">
<h2>Test 5: Saved searches</h2>
<button onclick="testSavedSearches()">Test Saved Searches</button>
<div id="savedSearchResult" class="test-result"></div>
</div>
<script>
// Mock BookmarkManager for testing
class MockBookmarkManager {
constructor() {
this.bookmarks = [
{
id: 1,
title: 'Google',
url: 'https://google.com',
folder: 'Search Engines',
addDate: Date.now() - 86400000, // 1 day ago
status: 'valid'
},
{
id: 2,
title: 'GitHub',
url: 'https://github.com',
folder: 'Development',
addDate: Date.now() - 604800000, // 1 week ago
status: 'valid'
},
{
id: 3,
title: 'Stack Overflow',
url: 'https://stackoverflow.com',
folder: 'Development',
addDate: Date.now() - 2592000000, // 1 month ago
status: 'valid'
}
];
this.searchHistory = [];
this.savedSearches = [];
}
// Test folder search functionality
executeAdvancedSearch(criteria) {
let results = [...this.bookmarks];
if (criteria.query) {
const lowerQuery = criteria.query.toLowerCase();
results = results.filter(bookmark => {
return bookmark.title.toLowerCase().includes(lowerQuery) ||
bookmark.url.toLowerCase().includes(lowerQuery) ||
(bookmark.folder && bookmark.folder.toLowerCase().includes(lowerQuery));
});
}
if (criteria.folder) {
results = results.filter(bookmark => bookmark.folder === criteria.folder);
}
if (criteria.dateFilter) {
results = this.applyDateFilter(results, criteria);
}
if (criteria.status) {
results = results.filter(bookmark => bookmark.status === criteria.status);
}
return results;
}
applyDateFilter(bookmarks, criteria) {
const now = new Date();
let startDate, endDate;
switch (criteria.dateFilter) {
case 'today':
startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
break;
case 'week':
const weekStart = new Date(now);
weekStart.setDate(now.getDate() - now.getDay());
weekStart.setHours(0, 0, 0, 0);
startDate = weekStart;
endDate = new Date(weekStart);
endDate.setDate(weekStart.getDate() + 7);
break;
case 'month':
startDate = new Date(now.getFullYear(), now.getMonth(), 1);
endDate = new Date(now.getFullYear(), now.getMonth() + 1, 1);
break;
default:
return bookmarks;
}
return bookmarks.filter(bookmark => {
const bookmarkDate = new Date(bookmark.addDate);
const afterStart = !startDate || bookmarkDate >= startDate;
const beforeEnd = !endDate || bookmarkDate < endDate;
return afterStart && beforeEnd;
});
}
generateSearchSuggestions(query) {
const lowerQuery = query.toLowerCase();
const suggestions = new Set();
this.bookmarks.forEach(bookmark => {
if (bookmark.title.toLowerCase().includes(lowerQuery)) {
suggestions.add(bookmark.title);
}
if (bookmark.folder && bookmark.folder.toLowerCase().includes(lowerQuery)) {
suggestions.add(bookmark.folder);
}
});
return Array.from(suggestions).slice(0, 10);
}
addToSearchHistory(criteria) {
this.searchHistory.unshift(criteria);
if (this.searchHistory.length > 20) {
this.searchHistory = this.searchHistory.slice(0, 20);
}
}
saveSearch(name, criteria) {
const savedSearch = {
id: Date.now(),
name: name,
criteria: criteria,
createdAt: Date.now()
};
this.savedSearches.push(savedSearch);
return savedSearch;
}
}
const mockManager = new MockBookmarkManager();
function testFolderSearch() {
const result = document.getElementById('folderSearchResult');
try {
// Test searching within Development folder
const criteria = { folder: 'Development' };
const results = mockManager.executeAdvancedSearch(criteria);
const expectedCount = 2; // GitHub and Stack Overflow
const actualCount = results.length;
if (actualCount === expectedCount) {
result.className = 'test-result pass';
result.innerHTML = `✓ PASS: Found ${actualCount} bookmarks in Development folder (expected ${expectedCount})`;
} else {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Found ${actualCount} bookmarks in Development folder (expected ${expectedCount})`;
}
} catch (error) {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Error during folder search test: ${error.message}`;
}
}
function testDateFiltering() {
const result = document.getElementById('dateFilterResult');
try {
// Test filtering by this week
const criteria = { dateFilter: 'week' };
const results = mockManager.executeAdvancedSearch(criteria);
// Should find Google (1 day ago) and GitHub (1 week ago)
const expectedCount = 2;
const actualCount = results.length;
if (actualCount === expectedCount) {
result.className = 'test-result pass';
result.innerHTML = `✓ PASS: Found ${actualCount} bookmarks from this week (expected ${expectedCount})`;
} else {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Found ${actualCount} bookmarks from this week (expected ${expectedCount})`;
}
} catch (error) {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Error during date filtering test: ${error.message}`;
}
}
function testSearchSuggestions() {
const result = document.getElementById('suggestionsResult');
try {
const suggestions = mockManager.generateSearchSuggestions('dev');
const expectedSuggestions = ['Development'];
const hasExpectedSuggestion = suggestions.includes('Development');
if (hasExpectedSuggestion) {
result.className = 'test-result pass';
result.innerHTML = `✓ PASS: Generated suggestions: ${suggestions.join(', ')}`;
} else {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Expected 'Development' in suggestions, got: ${suggestions.join(', ')}`;
}
} catch (error) {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Error during search suggestions test: ${error.message}`;
}
}
function testSearchHistory() {
const result = document.getElementById('historyResult');
try {
const criteria = { query: 'test search', folder: 'Development' };
mockManager.addToSearchHistory(criteria);
const historyCount = mockManager.searchHistory.length;
const latestSearch = mockManager.searchHistory[0];
if (historyCount === 1 && latestSearch.query === 'test search') {
result.className = 'test-result pass';
result.innerHTML = `✓ PASS: Search history working correctly (${historyCount} items)`;
} else {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Search history not working correctly`;
}
} catch (error) {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Error during search history test: ${error.message}`;
}
}
function testSavedSearches() {
const result = document.getElementById('savedSearchResult');
try {
const criteria = { query: 'saved search', folder: 'Development' };
const savedSearch = mockManager.saveSearch('My Test Search', criteria);
const savedCount = mockManager.savedSearches.length;
if (savedCount === 1 && savedSearch.name === 'My Test Search') {
result.className = 'test-result pass';
result.innerHTML = `✓ PASS: Saved searches working correctly (${savedCount} saved)`;
} else {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Saved searches not working correctly`;
}
} catch (error) {
result.className = 'test-result fail';
result.innerHTML = `✗ FAIL: Error during saved searches test: ${error.message}`;
}
}
// Run all tests automatically
window.onload = function() {
setTimeout(() => {
testFolderSearch();
testDateFiltering();
testSearchSuggestions();
testSearchHistory();
testSavedSearches();
}, 100);
};
</script>
</body>
</html>