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
This commit is contained in:
167
tests/test_performance.html
Normal file
167
tests/test_performance.html
Normal file
@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Performance Test - Bookmark Manager</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Performance Test</h1>
|
||||
<p>This page tests the performance optimizations for large bookmark collections.</p>
|
||||
|
||||
<div class="test-controls">
|
||||
<button id="generateLargeCollection" class="btn btn-primary">Generate 500 Test Bookmarks</button>
|
||||
<button id="testSearch" class="btn btn-secondary">Test Debounced Search</button>
|
||||
<button id="testVirtualScroll" class="btn btn-info">Test Virtual Scrolling</button>
|
||||
<button id="clearBookmarks" class="btn btn-danger">Clear All Bookmarks</button>
|
||||
</div>
|
||||
|
||||
<div id="testResults" class="test-results">
|
||||
<h3>Test Results:</h3>
|
||||
<div id="results"></div>
|
||||
</div>
|
||||
|
||||
<!-- Include the main bookmark manager interface -->
|
||||
<div id="bookmarksList" class="bookmarks-list"></div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
<script>
|
||||
// Performance testing script
|
||||
const bookmarkManager = new BookmarkManager();
|
||||
|
||||
document.getElementById('generateLargeCollection').addEventListener('click', () => {
|
||||
generateLargeCollection();
|
||||
});
|
||||
|
||||
document.getElementById('testSearch').addEventListener('click', () => {
|
||||
testDebouncedSearch();
|
||||
});
|
||||
|
||||
document.getElementById('testVirtualScroll').addEventListener('click', () => {
|
||||
testVirtualScrolling();
|
||||
});
|
||||
|
||||
document.getElementById('clearBookmarks').addEventListener('click', () => {
|
||||
if (confirm('Clear all test bookmarks?')) {
|
||||
bookmarkManager.clearAllBookmarks();
|
||||
document.getElementById('results').innerHTML = '<p>All bookmarks cleared.</p>';
|
||||
}
|
||||
});
|
||||
|
||||
function generateLargeCollection() {
|
||||
const results = document.getElementById('results');
|
||||
results.innerHTML = '<p>Generating 500 test bookmarks...</p>';
|
||||
|
||||
const startTime = performance.now();
|
||||
|
||||
// Generate test bookmarks
|
||||
const testBookmarks = [];
|
||||
const folders = ['Development', 'News', 'Social Media', 'Shopping', 'Entertainment', 'Education', 'Tools', 'Reference'];
|
||||
|
||||
for (let i = 0; i < 500; i++) {
|
||||
const folder = folders[i % folders.length];
|
||||
const bookmark = {
|
||||
id: Date.now() + Math.random() + i,
|
||||
title: `Test Bookmark ${i + 1}`,
|
||||
url: `https://example${i}.com`,
|
||||
folder: folder,
|
||||
addDate: Date.now() - (i * 1000),
|
||||
icon: '',
|
||||
status: i % 4 === 0 ? 'valid' : i % 4 === 1 ? 'invalid' : i % 4 === 2 ? 'duplicate' : 'unknown'
|
||||
};
|
||||
testBookmarks.push(bookmark);
|
||||
}
|
||||
|
||||
bookmarkManager.bookmarks = testBookmarks;
|
||||
bookmarkManager.saveBookmarksToStorage();
|
||||
|
||||
const renderStart = performance.now();
|
||||
bookmarkManager.renderBookmarks();
|
||||
const renderEnd = performance.now();
|
||||
|
||||
bookmarkManager.updateStats();
|
||||
|
||||
const endTime = performance.now();
|
||||
|
||||
results.innerHTML = `
|
||||
<p><strong>✓ Generated 500 test bookmarks</strong></p>
|
||||
<p>Total time: ${(endTime - startTime).toFixed(2)}ms</p>
|
||||
<p>Render time: ${(renderEnd - renderStart).toFixed(2)}ms</p>
|
||||
<p>Virtual scrolling threshold: ${bookmarkManager.virtualScrollThreshold}</p>
|
||||
<p>Should use virtual scrolling: ${testBookmarks.length > bookmarkManager.virtualScrollThreshold ? 'Yes' : 'No'}</p>
|
||||
`;
|
||||
}
|
||||
|
||||
function testDebouncedSearch() {
|
||||
const results = document.getElementById('results');
|
||||
results.innerHTML = '<p>Testing debounced search...</p>';
|
||||
|
||||
let searchCount = 0;
|
||||
const originalSearch = bookmarkManager.searchBookmarks;
|
||||
|
||||
// Override search method to count calls
|
||||
bookmarkManager.searchBookmarks = function(query) {
|
||||
searchCount++;
|
||||
return originalSearch.call(this, query);
|
||||
};
|
||||
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
if (!searchInput) {
|
||||
results.innerHTML = '<p>Error: Search input not found. Please use the main bookmark manager page.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate rapid typing
|
||||
const testQuery = 'test';
|
||||
searchInput.value = '';
|
||||
|
||||
for (let i = 0; i < testQuery.length; i++) {
|
||||
searchInput.value = testQuery.substring(0, i + 1);
|
||||
searchInput.dispatchEvent(new Event('input'));
|
||||
}
|
||||
|
||||
// Wait for debounce to complete
|
||||
setTimeout(() => {
|
||||
results.innerHTML = `
|
||||
<p><strong>✓ Debounced search test completed</strong></p>
|
||||
<p>Characters typed: ${testQuery.length}</p>
|
||||
<p>Search calls made: ${searchCount}</p>
|
||||
<p>Debounce working: ${searchCount === 1 ? 'Yes' : 'No'}</p>
|
||||
<p>Expected: 1 call after 300ms delay</p>
|
||||
`;
|
||||
|
||||
// Restore original method
|
||||
bookmarkManager.searchBookmarks = originalSearch;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function testVirtualScrolling() {
|
||||
const results = document.getElementById('results');
|
||||
|
||||
if (bookmarkManager.bookmarks.length < bookmarkManager.virtualScrollThreshold) {
|
||||
results.innerHTML = `
|
||||
<p><strong>⚠ Virtual scrolling test</strong></p>
|
||||
<p>Current bookmarks: ${bookmarkManager.bookmarks.length}</p>
|
||||
<p>Threshold: ${bookmarkManager.virtualScrollThreshold}</p>
|
||||
<p>Generate more bookmarks to test virtual scrolling.</p>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
const startTime = performance.now();
|
||||
bookmarkManager.renderBookmarks();
|
||||
const endTime = performance.now();
|
||||
|
||||
results.innerHTML = `
|
||||
<p><strong>✓ Virtual scrolling test completed</strong></p>
|
||||
<p>Bookmarks: ${bookmarkManager.bookmarks.length}</p>
|
||||
<p>Render time: ${(endTime - startTime).toFixed(2)}ms</p>
|
||||
<p>Virtual scrolling active: ${bookmarkManager.bookmarks.length > bookmarkManager.virtualScrollThreshold ? 'Yes' : 'No'}</p>
|
||||
`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user