const axios = require('axios'); const BASE_URL = 'http://localhost:3000/api'; // Store test data let testData = { guestId: null, sessionToken: null, userId: null, userToken: null }; // Helper function to print test results function printTestResult(testNumber, testName, success, details = '') { const emoji = success ? '✅' : '❌'; console.log(`\n${emoji} Test ${testNumber}: ${testName}`); if (details) console.log(details); } // Helper function to print section header function printSection(title) { console.log('\n' + '='.repeat(60)); console.log(title); console.log('='.repeat(60)); } async function runTests() { console.log('\n╔════════════════════════════════════════════════════════════╗'); console.log('║ Guest to User Conversion Tests (Task 17) ║'); console.log('╚════════════════════════════════════════════════════════════╝\n'); console.log('Make sure the server is running on http://localhost:3000\n'); try { // Test 1: Create a guest session printSection('Test 1: Create guest session for testing'); try { const response = await axios.post(`${BASE_URL}/guest/start-session`, { deviceId: `test_device_${Date.now()}` }); if (response.status === 201 && response.data.success) { testData.guestId = response.data.data.guestId; testData.sessionToken = response.data.data.sessionToken; printTestResult(1, 'Guest session created', true, `Guest ID: ${testData.guestId}\nToken: ${testData.sessionToken.substring(0, 50)}...`); } else { throw new Error('Failed to create session'); } } catch (error) { printTestResult(1, 'Guest session creation', false, `Error: ${error.response?.data?.message || error.message}`); return; } // Test 2: Try conversion without required fields printSection('Test 2: Conversion without required fields (should fail)'); try { const response = await axios.post(`${BASE_URL}/guest/convert`, { username: 'testuser' // Missing email and password }, { headers: { 'X-Guest-Token': testData.sessionToken } }); printTestResult(2, 'Missing required fields', false, 'Should have returned 400 but got: ' + response.status); } catch (error) { if (error.response?.status === 400) { printTestResult(2, 'Missing required fields', true, `Correctly returned 400: ${error.response.data.message}`); } else { printTestResult(2, 'Missing required fields', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } // Test 3: Try conversion with invalid email printSection('Test 3: Conversion with invalid email (should fail)'); try { const response = await axios.post(`${BASE_URL}/guest/convert`, { username: 'testuser', email: 'invalid-email', password: 'Password123' }, { headers: { 'X-Guest-Token': testData.sessionToken } }); printTestResult(3, 'Invalid email format', false, 'Should have returned 400 but got: ' + response.status); } catch (error) { if (error.response?.status === 400) { printTestResult(3, 'Invalid email format', true, `Correctly returned 400: ${error.response.data.message}`); } else { printTestResult(3, 'Invalid email format', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } // Test 4: Try conversion with weak password printSection('Test 4: Conversion with weak password (should fail)'); try { const response = await axios.post(`${BASE_URL}/guest/convert`, { username: 'testuser', email: 'test@example.com', password: 'weak' }, { headers: { 'X-Guest-Token': testData.sessionToken } }); printTestResult(4, 'Weak password', false, 'Should have returned 400 but got: ' + response.status); } catch (error) { if (error.response?.status === 400) { printTestResult(4, 'Weak password', true, `Correctly returned 400: ${error.response.data.message}`); } else { printTestResult(4, 'Weak password', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } // Test 5: Successful conversion printSection('Test 5: Successful guest to user conversion'); const timestamp = Date.now(); const conversionData = { username: `converted${timestamp}`, email: `converted${timestamp}@test.com`, password: 'Password123' }; try { const response = await axios.post(`${BASE_URL}/guest/convert`, conversionData, { headers: { 'X-Guest-Token': testData.sessionToken } }); if (response.status === 201 && response.data.success) { testData.userId = response.data.data.user.id; testData.userToken = response.data.data.token; printTestResult(5, 'Guest to user conversion', true, `User ID: ${testData.userId}\n` + `Username: ${response.data.data.user.username}\n` + `Email: ${response.data.data.user.email}\n` + `Quizzes Transferred: ${response.data.data.migration.quizzesTransferred}\n` + `Token: ${testData.userToken.substring(0, 50)}...`); console.log('\nMigration Stats:'); const stats = response.data.data.migration.stats; console.log(` Total Quizzes: ${stats.totalQuizzes}`); console.log(` Quizzes Passed: ${stats.quizzesPassed}`); console.log(` Questions Answered: ${stats.totalQuestionsAnswered}`); console.log(` Correct Answers: ${stats.correctAnswers}`); console.log(` Accuracy: ${stats.accuracy}%`); } else { throw new Error('Unexpected response'); } } catch (error) { printTestResult(5, 'Guest to user conversion', false, `Error: ${error.response?.data?.message || error.message}`); return; } // Test 6: Try to convert the same guest session again (should fail) printSection('Test 6: Try to convert already converted session (should fail)'); try { const response = await axios.post(`${BASE_URL}/guest/convert`, { username: `another${timestamp}`, email: `another${timestamp}@test.com`, password: 'Password123' }, { headers: { 'X-Guest-Token': testData.sessionToken } }); printTestResult(6, 'Already converted session', false, 'Should have returned 410 but got: ' + response.status); } catch (error) { if (error.response?.status === 410) { printTestResult(6, 'Already converted session', true, `Correctly returned 410: ${error.response.data.message}`); } else { printTestResult(6, 'Already converted session', false, `Wrong status code: ${error.response?.status || 'unknown'}\nMessage: ${error.response?.data?.message}`); } } // Test 7: Try conversion with duplicate email printSection('Test 7: Create new guest and try conversion with duplicate email'); try { // Create new guest session const guestResponse = await axios.post(`${BASE_URL}/guest/start-session`, { deviceId: `test_device_2_${Date.now()}` }); const newGuestToken = guestResponse.data.data.sessionToken; // Try to convert with existing email const response = await axios.post(`${BASE_URL}/guest/convert`, { username: `unique${Date.now()}`, email: conversionData.email, // Use email from Test 5 password: 'Password123' }, { headers: { 'X-Guest-Token': newGuestToken } }); printTestResult(7, 'Duplicate email rejection', false, 'Should have returned 400 but got: ' + response.status); } catch (error) { if (error.response?.status === 400 && error.response.data.message.includes('Email already registered')) { printTestResult(7, 'Duplicate email rejection', true, `Correctly returned 400: ${error.response.data.message}`); } else { printTestResult(7, 'Duplicate email rejection', false, `Wrong status code or message: ${error.response?.status || 'unknown'}`); } } // Test 8: Try conversion with duplicate username printSection('Test 8: Try conversion with duplicate username'); try { // Create new guest session const guestResponse = await axios.post(`${BASE_URL}/guest/start-session`, { deviceId: `test_device_3_${Date.now()}` }); const newGuestToken = guestResponse.data.data.sessionToken; // Try to convert with existing username const response = await axios.post(`${BASE_URL}/guest/convert`, { username: conversionData.username, // Use username from Test 5 email: `unique${Date.now()}@test.com`, password: 'Password123' }, { headers: { 'X-Guest-Token': newGuestToken } }); printTestResult(8, 'Duplicate username rejection', false, 'Should have returned 400 but got: ' + response.status); } catch (error) { if (error.response?.status === 400 && error.response.data.message.includes('Username already taken')) { printTestResult(8, 'Duplicate username rejection', true, `Correctly returned 400: ${error.response.data.message}`); } else { printTestResult(8, 'Duplicate username rejection', false, `Wrong status code or message: ${error.response?.status || 'unknown'}`); } } // Test 9: Verify user can login with new credentials printSection('Test 9: Verify converted user can login'); try { const response = await axios.post(`${BASE_URL}/auth/login`, { email: conversionData.email, password: conversionData.password }); if (response.status === 200 && response.data.success) { printTestResult(9, 'Login with converted credentials', true, `Successfully logged in as: ${response.data.data.user.username}\n` + `User ID matches: ${response.data.data.user.id === testData.userId}`); } else { throw new Error('Login failed'); } } catch (error) { printTestResult(9, 'Login with converted credentials', false, `Error: ${error.response?.data?.message || error.message}`); } // Test 10: Verify conversion without token (should fail) printSection('Test 10: Try conversion without guest token (should fail)'); try { const response = await axios.post(`${BASE_URL}/guest/convert`, { username: `notoken${Date.now()}`, email: `notoken${Date.now()}@test.com`, password: 'Password123' }); printTestResult(10, 'No guest token provided', false, 'Should have returned 401 but got: ' + response.status); } catch (error) { if (error.response?.status === 401) { printTestResult(10, 'No guest token provided', true, `Correctly returned 401: ${error.response.data.message}`); } else { printTestResult(10, 'No guest token provided', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } } catch (error) { console.error('\n❌ Fatal error during testing:', error.message); } console.log('\n╔════════════════════════════════════════════════════════════╗'); console.log('║ Tests Completed ║'); console.log('╚════════════════════════════════════════════════════════════╝\n'); } // Run tests runTests();