// Test script for bookmark API endpoints const axios = require('axios'); const BASE_URL = 'http://localhost:3001'; // Test data const testUser = { email: 'bookmarktest@example.com', password: 'TestPassword123!' }; const testBookmarks = [ { title: 'Google', url: 'https://www.google.com', folder: 'Search Engines', status: 'valid' }, { title: 'GitHub', url: 'https://github.com', folder: 'Development', status: 'valid' }, { title: 'Stack Overflow', url: 'https://stackoverflow.com', folder: 'Development', status: 'valid' } ]; let authToken = null; let createdBookmarkIds = []; async function testEndpoint(name, testFn) { try { console.log(`\n๐Ÿงช Testing: ${name}`); await testFn(); console.log(`โœ… ${name} - PASSED`); } catch (error) { console.log(`โŒ ${name} - FAILED`); if (error.response) { console.log(` Status: ${error.response.status}`); console.log(` Error: ${JSON.stringify(error.response.data, null, 2)}`); } else { console.log(` Error: ${error.message}`); } } } async function setupTestUser() { try { // Try to register user (might fail if already exists) await axios.post(`${BASE_URL}/api/auth/register`, testUser); } catch (error) { // User might already exist, that's okay } // Login to get token const response = await axios.post(`${BASE_URL}/api/auth/login`, testUser); const cookies = response.headers['set-cookie']; if (cookies) { const authCookie = cookies.find(cookie => cookie.startsWith('authToken=')); if (authCookie) { authToken = authCookie.split('=')[1].split(';')[0]; } } if (!authToken) { throw new Error('Failed to get auth token'); } console.log(`โœ… Test user logged in successfully`); } async function testCreateBookmark() { const response = await axios.post(`${BASE_URL}/api/bookmarks`, testBookmarks[0], { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 201) { throw new Error(`Expected status 201, got ${response.status}`); } if (!response.data.bookmark || !response.data.bookmark.id) { throw new Error('Response should contain bookmark with ID'); } createdBookmarkIds.push(response.data.bookmark.id); console.log(` Created bookmark: ${response.data.bookmark.title}`); } async function testGetBookmarks() { const response = await axios.get(`${BASE_URL}/api/bookmarks`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } if (!response.data.bookmarks || !Array.isArray(response.data.bookmarks)) { throw new Error('Response should contain bookmarks array'); } if (!response.data.pagination) { throw new Error('Response should contain pagination info'); } console.log(` Retrieved ${response.data.bookmarks.length} bookmarks`); console.log(` Pagination: page ${response.data.pagination.page} of ${response.data.pagination.totalPages}`); } async function testGetBookmarkById() { if (createdBookmarkIds.length === 0) { throw new Error('No bookmarks created to test'); } const bookmarkId = createdBookmarkIds[0]; const response = await axios.get(`${BASE_URL}/api/bookmarks/${bookmarkId}`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } if (!response.data.bookmark || response.data.bookmark.id !== bookmarkId) { throw new Error('Response should contain correct bookmark'); } console.log(` Retrieved bookmark: ${response.data.bookmark.title}`); } async function testUpdateBookmark() { if (createdBookmarkIds.length === 0) { throw new Error('No bookmarks created to test'); } const bookmarkId = createdBookmarkIds[0]; const updates = { title: 'Updated Google', folder: 'Updated Folder' }; const response = await axios.put(`${BASE_URL}/api/bookmarks/${bookmarkId}`, updates, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } if (response.data.bookmark.title !== updates.title) { throw new Error('Bookmark title should be updated'); } console.log(` Updated bookmark: ${response.data.bookmark.title}`); } async function testBulkCreateBookmarks() { const response = await axios.post(`${BASE_URL}/api/bookmarks/bulk`, { bookmarks: testBookmarks.slice(1) // Create remaining test bookmarks }, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 201) { throw new Error(`Expected status 201, got ${response.status}`); } if (!response.data.bookmarks || response.data.bookmarks.length !== 2) { throw new Error('Should create 2 bookmarks'); } // Store created bookmark IDs response.data.bookmarks.forEach(bookmark => { createdBookmarkIds.push(bookmark.id); }); console.log(` Bulk created ${response.data.count} bookmarks`); } async function testGetFolders() { const response = await axios.get(`${BASE_URL}/api/bookmarks/folders`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } if (!response.data.folders || !Array.isArray(response.data.folders)) { throw new Error('Response should contain folders array'); } console.log(` Retrieved ${response.data.folders.length} folders`); response.data.folders.forEach(folder => { console.log(` - ${folder.folder}: ${folder.count} bookmarks`); }); } async function testGetStats() { const response = await axios.get(`${BASE_URL}/api/bookmarks/stats`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } if (!response.data.stats) { throw new Error('Response should contain stats'); } console.log(` Stats: ${response.data.stats.totalBookmarks} total, ${response.data.stats.totalFolders} folders`); } async function testBookmarkFiltering() { // Test filtering by folder const response = await axios.get(`${BASE_URL}/api/bookmarks?folder=Development`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } const developmentBookmarks = response.data.bookmarks.filter(b => b.folder === 'Development'); if (developmentBookmarks.length !== response.data.bookmarks.length) { throw new Error('All returned bookmarks should be in Development folder'); } console.log(` Filtered ${response.data.bookmarks.length} bookmarks in Development folder`); } async function testBookmarkSearch() { // Test search functionality const response = await axios.get(`${BASE_URL}/api/bookmarks?search=GitHub`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } const hasGitHub = response.data.bookmarks.some(b => b.title.toLowerCase().includes('github') || b.url.toLowerCase().includes('github') ); if (!hasGitHub) { throw new Error('Search should return bookmarks containing "GitHub"'); } console.log(` Search returned ${response.data.bookmarks.length} bookmarks`); } async function testExportBookmarks() { const response = await axios.post(`${BASE_URL}/api/bookmarks/export`, { format: 'json' }, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } if (!response.data.bookmarks || !Array.isArray(response.data.bookmarks)) { throw new Error('Export should contain bookmarks array'); } console.log(` Exported ${response.data.count} bookmarks`); } async function testDeleteBookmark() { if (createdBookmarkIds.length === 0) { throw new Error('No bookmarks created to test'); } const bookmarkId = createdBookmarkIds[0]; const response = await axios.delete(`${BASE_URL}/api/bookmarks/${bookmarkId}`, { headers: { 'Cookie': `authToken=${authToken}` } }); if (response.status !== 200) { throw new Error(`Expected status 200, got ${response.status}`); } // Remove from our tracking array createdBookmarkIds = createdBookmarkIds.filter(id => id !== bookmarkId); console.log(` Deleted bookmark successfully`); } async function testUnauthorizedAccess() { try { await axios.get(`${BASE_URL}/api/bookmarks`); throw new Error('Should have failed without authentication'); } catch (error) { if (error.response && error.response.status === 401) { console.log(` Unauthorized access correctly rejected`); } else { throw error; } } } async function testDataIsolation() { // Create a second user to test data isolation const testUser2 = { email: 'isolation@example.com', password: 'TestPassword123!' }; try { await axios.post(`${BASE_URL}/api/auth/register`, testUser2); } catch (error) { // User might already exist } const loginResponse = await axios.post(`${BASE_URL}/api/auth/login`, testUser2); const cookies = loginResponse.headers['set-cookie']; let user2Token = null; if (cookies) { const authCookie = cookies.find(cookie => cookie.startsWith('authToken=')); if (authCookie) { user2Token = authCookie.split('=')[1].split(';')[0]; } } // Get bookmarks for user2 (should be empty) const bookmarksResponse = await axios.get(`${BASE_URL}/api/bookmarks`, { headers: { 'Cookie': `authToken=${user2Token}` } }); if (bookmarksResponse.data.bookmarks.length > 0) { throw new Error('User2 should not see user1 bookmarks'); } console.log(` Data isolation verified - user2 sees 0 bookmarks`); } async function cleanup() { // Delete remaining test bookmarks for (const bookmarkId of createdBookmarkIds) { try { await axios.delete(`${BASE_URL}/api/bookmarks/${bookmarkId}`, { headers: { 'Cookie': `authToken=${authToken}` } }); } catch (error) { // Ignore cleanup errors } } console.log(`โœ… Cleanup completed`); } async function runTests() { console.log('๐Ÿš€ Starting Bookmark API Tests'); console.log('=============================='); // Setup await testEndpoint('Setup Test User', setupTestUser); // Basic CRUD operations await testEndpoint('Create Bookmark', testCreateBookmark); await testEndpoint('Get Bookmarks', testGetBookmarks); await testEndpoint('Get Bookmark by ID', testGetBookmarkById); await testEndpoint('Update Bookmark', testUpdateBookmark); // Bulk operations await testEndpoint('Bulk Create Bookmarks', testBulkCreateBookmarks); // Additional endpoints await testEndpoint('Get Folders', testGetFolders); await testEndpoint('Get Statistics', testGetStats); await testEndpoint('Export Bookmarks', testExportBookmarks); // Filtering and search await testEndpoint('Filter by Folder', testBookmarkFiltering); await testEndpoint('Search Bookmarks', testBookmarkSearch); // Security tests await testEndpoint('Unauthorized Access', testUnauthorizedAccess); await testEndpoint('Data Isolation', testDataIsolation); // Cleanup await testEndpoint('Delete Bookmark', testDeleteBookmark); await testEndpoint('Cleanup', cleanup); console.log('\n๐ŸŽ‰ All bookmark API tests completed!'); } // Check if server is running async function checkServer() { try { await axios.get(`${BASE_URL}/health`); console.log('โœ… Server is running'); return true; } catch (error) { console.log('โŒ Server is not running. Please start the server first with: npm start'); return false; } } async function main() { const serverRunning = await checkServer(); if (serverRunning) { await runTests(); } } main().catch(console.error);