/** * Manual Test Script for Guest Session Endpoints * Task 15: Guest Session Creation * * Run this script with: node test-guest-endpoints.js * Make sure the server is running on http://localhost:3000 */ const axios = require('axios'); const API_BASE = 'http://localhost:3000/api'; let testGuestId = null; let testSessionToken = null; // Helper function for test output function logTest(testNumber, description) { console.log(`\n${'='.repeat(60)}`); console.log(`${testNumber} Testing ${description}`); console.log('='.repeat(60)); } function logSuccess(message) { console.log(`✅ SUCCESS: ${message}`); } function logError(message, error = null) { console.log(`❌ ERROR: ${message}`); if (error) { if (error.response && error.response.data) { console.log(`Response status: ${error.response.status}`); console.log(`Response data:`, JSON.stringify(error.response.data, null, 2)); } else if (error.message) { console.log(`Error details: ${error.message}`); } else { console.log(`Error:`, error); } } } // Test 1: Start a guest session async function test1_StartGuestSession() { logTest('1️⃣', 'POST /api/guest/start-session - Create guest session'); try { const requestData = { deviceId: `device_${Date.now()}` }; console.log('Request:', JSON.stringify(requestData, null, 2)); const response = await axios.post(`${API_BASE}/guest/start-session`, requestData); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success && response.data.data.guestId && response.data.data.sessionToken) { testGuestId = response.data.data.guestId; testSessionToken = response.data.data.sessionToken; logSuccess('Guest session created successfully'); console.log('Guest ID:', testGuestId); console.log('Session Token:', testSessionToken.substring(0, 50) + '...'); console.log('Expires In:', response.data.data.expiresIn); console.log('Max Quizzes:', response.data.data.restrictions.maxQuizzes); console.log('Quizzes Remaining:', response.data.data.restrictions.quizzesRemaining); console.log('Available Categories:', response.data.data.availableCategories.length); // Check restrictions const features = response.data.data.restrictions.features; console.log('\nFeatures:'); console.log(' - Can Take Quizzes:', features.canTakeQuizzes ? '✅' : '❌'); console.log(' - Can View Results:', features.canViewResults ? '✅' : '❌'); console.log(' - Can Bookmark Questions:', features.canBookmarkQuestions ? '✅' : '❌'); console.log(' - Can Track Progress:', features.canTrackProgress ? '✅' : '❌'); console.log(' - Can Earn Achievements:', features.canEarnAchievements ? '✅' : '❌'); } else { logError('Unexpected response format'); } } catch (error) { logError('Failed to create guest session', error); } } // Test 2: Get guest session details async function test2_GetGuestSession() { logTest('2️⃣', 'GET /api/guest/session/:guestId - Get session details'); if (!testGuestId) { logError('No guest ID available. Skipping test.'); return; } try { const response = await axios.get(`${API_BASE}/guest/session/${testGuestId}`); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success && response.data.data) { logSuccess('Guest session retrieved successfully'); console.log('Guest ID:', response.data.data.guestId); console.log('Expires In:', response.data.data.expiresIn); console.log('Is Expired:', response.data.data.isExpired); console.log('Quizzes Attempted:', response.data.data.restrictions.quizzesAttempted); console.log('Quizzes Remaining:', response.data.data.restrictions.quizzesRemaining); console.log('Can Take Quizzes:', response.data.data.restrictions.features.canTakeQuizzes); } else { logError('Unexpected response format'); } } catch (error) { logError('Failed to get guest session', error); } } // Test 3: Get non-existent guest session async function test3_GetNonExistentSession() { logTest('3️⃣', 'GET /api/guest/session/:guestId - Non-existent session (should fail)'); try { const response = await axios.get(`${API_BASE}/guest/session/guest_nonexistent_12345`); console.log('Response:', JSON.stringify(response.data, null, 2)); logError('Should have returned 404 for non-existent session'); } catch (error) { if (error.response && error.response.status === 404) { console.log('Response:', JSON.stringify(error.response.data, null, 2)); logSuccess('Correctly returned 404 for non-existent session'); } else { logError('Unexpected error', error); } } } // Test 4: Start guest session without deviceId (optional field) async function test4_StartSessionWithoutDeviceId() { logTest('4️⃣', 'POST /api/guest/start-session - Without deviceId'); try { const response = await axios.post(`${API_BASE}/guest/start-session`, {}); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success && response.data.data.guestId) { logSuccess('Guest session created without deviceId (optional field)'); console.log('Guest ID:', response.data.data.guestId); } else { logError('Unexpected response format'); } } catch (error) { logError('Failed to create guest session', error); } } // Test 5: Verify guest-accessible categories async function test5_VerifyGuestCategories() { logTest('5️⃣', 'Verify guest-accessible categories'); if (!testGuestId) { logError('No guest ID available. Skipping test.'); return; } try { const response = await axios.get(`${API_BASE}/guest/session/${testGuestId}`); const categories = response.data.data.availableCategories; console.log(`Found ${categories.length} guest-accessible categories:`); categories.forEach((cat, index) => { console.log(` ${index + 1}. ${cat.name} (${cat.question_count} questions)`); }); if (categories.length > 0) { logSuccess(`${categories.length} guest-accessible categories available`); // Expected categories from seeder: JavaScript, Angular, React const expectedCategories = ['JavaScript', 'Angular', 'React']; const foundCategories = categories.map(c => c.name); console.log('\nExpected guest-accessible categories:', expectedCategories.join(', ')); console.log('Found categories:', foundCategories.join(', ')); const allFound = expectedCategories.every(cat => foundCategories.includes(cat)); if (allFound) { logSuccess('All expected categories are accessible to guests'); } else { logError('Some expected categories are missing'); } } else { logError('No guest-accessible categories found (check seeder data)'); } } catch (error) { logError('Failed to verify categories', error); } } // Test 6: Verify session restrictions async function test6_VerifySessionRestrictions() { logTest('6️⃣', 'Verify guest session restrictions'); if (!testGuestId) { logError('No guest ID available. Skipping test.'); return; } try { const response = await axios.get(`${API_BASE}/guest/session/${testGuestId}`); const restrictions = response.data.data.restrictions; const features = restrictions.features; console.log('Quiz Restrictions:'); console.log(' - Max Quizzes:', restrictions.maxQuizzes); console.log(' - Quizzes Attempted:', restrictions.quizzesAttempted); console.log(' - Quizzes Remaining:', restrictions.quizzesRemaining); console.log('\nFeature Restrictions:'); console.log(' - Can Take Quizzes:', features.canTakeQuizzes ? '✅ Yes' : '❌ No'); console.log(' - Can View Results:', features.canViewResults ? '✅ Yes' : '❌ No'); console.log(' - Can Bookmark Questions:', features.canBookmarkQuestions ? '✅ Yes' : '❌ No'); console.log(' - Can Track Progress:', features.canTrackProgress ? '✅ Yes' : '❌ No'); console.log(' - Can Earn Achievements:', features.canEarnAchievements ? '✅ Yes' : '❌ No'); // Verify expected restrictions const expectedRestrictions = { maxQuizzes: 3, canTakeQuizzes: true, canViewResults: true, canBookmarkQuestions: false, canTrackProgress: false, canEarnAchievements: false }; const allCorrect = restrictions.maxQuizzes === expectedRestrictions.maxQuizzes && features.canTakeQuizzes === expectedRestrictions.canTakeQuizzes && features.canViewResults === expectedRestrictions.canViewResults && features.canBookmarkQuestions === expectedRestrictions.canBookmarkQuestions && features.canTrackProgress === expectedRestrictions.canTrackProgress && features.canEarnAchievements === expectedRestrictions.canEarnAchievements; if (allCorrect) { logSuccess('All restrictions are correctly configured'); } else { logError('Some restrictions do not match expected values'); } } catch (error) { logError('Failed to verify restrictions', error); } } // Test 7: Verify session token is valid JWT async function test7_VerifySessionToken() { logTest('7️⃣', 'Verify session token format'); if (!testSessionToken) { logError('No session token available. Skipping test.'); return; } try { // JWT tokens have 3 parts separated by dots const parts = testSessionToken.split('.'); console.log('Token parts:', parts.length); console.log('Header:', parts[0].substring(0, 20) + '...'); console.log('Payload:', parts[1].substring(0, 20) + '...'); console.log('Signature:', parts[2].substring(0, 20) + '...'); if (parts.length === 3) { logSuccess('Session token is in valid JWT format (3 parts)'); // Decode payload (base64) try { const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString()); console.log('\nDecoded payload:'); console.log(' - Guest ID:', payload.guestId); console.log(' - Issued At:', new Date(payload.iat * 1000).toISOString()); console.log(' - Expires At:', new Date(payload.exp * 1000).toISOString()); if (payload.guestId === testGuestId) { logSuccess('Token contains correct guest ID'); } else { logError('Token guest ID does not match session guest ID'); } } catch (decodeError) { logError('Failed to decode token payload', decodeError); } } else { logError('Session token is not in valid JWT format'); } } catch (error) { logError('Failed to verify token', error); } } // Run all tests async function runAllTests() { console.log('\n'); console.log('╔════════════════════════════════════════════════════════════╗'); console.log('║ Guest Session Creation Tests (Task 15) ║'); console.log('╚════════════════════════════════════════════════════════════╝'); console.log('\nMake sure the server is running on http://localhost:3000\n'); await test1_StartGuestSession(); await new Promise(resolve => setTimeout(resolve, 500)); await test2_GetGuestSession(); await new Promise(resolve => setTimeout(resolve, 500)); await test3_GetNonExistentSession(); await new Promise(resolve => setTimeout(resolve, 500)); await test4_StartSessionWithoutDeviceId(); await new Promise(resolve => setTimeout(resolve, 500)); await test5_VerifyGuestCategories(); await new Promise(resolve => setTimeout(resolve, 500)); await test6_VerifySessionRestrictions(); await new Promise(resolve => setTimeout(resolve, 500)); await test7_VerifySessionToken(); console.log('\n'); console.log('╔════════════════════════════════════════════════════════════╗'); console.log('║ All Tests Completed ║'); console.log('╚════════════════════════════════════════════════════════════╝'); console.log('\n'); } // Run tests runAllTests().catch(error => { console.error('\n❌ Fatal error running tests:', error); process.exit(1); });