This commit is contained in:
2025-07-20 20:43:06 +02:00
parent 0abee5b794
commit 29592c7fc8
93 changed files with 23400 additions and 131 deletions

View File

@ -0,0 +1,442 @@
// 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);