const axios = require('axios'); const BASE_URL = 'http://localhost:3000/api'; // Store session data for testing let testSession = { guestId: null, sessionToken: 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 Quiz Limit Tests (Task 16) ║'); console.log('╚════════════════════════════════════════════════════════════╝\n'); console.log('Make sure the server is running on http://localhost:3000\n'); try { // Test 1: Create a guest session first 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) { testSession.guestId = response.data.data.guestId; testSession.sessionToken = response.data.data.sessionToken; printTestResult(1, 'Guest session created', true, `Guest ID: ${testSession.guestId}\nToken: ${testSession.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; // Can't continue without session } // Test 2: Check quiz limit with valid token (should have 3 remaining) printSection('Test 2: Check quiz limit with valid token'); try { const response = await axios.get(`${BASE_URL}/guest/quiz-limit`, { headers: { 'X-Guest-Token': testSession.sessionToken } }); if (response.status === 200 && response.data.success) { const { quizLimit, session } = response.data.data; printTestResult(2, 'Quiz limit check with valid token', true, `Max Quizzes: ${quizLimit.maxQuizzes}\n` + `Quizzes Attempted: ${quizLimit.quizzesAttempted}\n` + `Quizzes Remaining: ${quizLimit.quizzesRemaining}\n` + `Has Reached Limit: ${quizLimit.hasReachedLimit}\n` + `Time Remaining: ${session.timeRemaining}`); } else { throw new Error('Unexpected response'); } } catch (error) { printTestResult(2, 'Quiz limit check with valid token', false, `Error: ${error.response?.data?.message || error.message}`); } // Test 3: Check quiz limit without token (should fail) printSection('Test 3: Check quiz limit without token (should fail with 401)'); try { const response = await axios.get(`${BASE_URL}/guest/quiz-limit`); printTestResult(3, 'No token provided', false, 'Should have returned 401 but got: ' + response.status); } catch (error) { if (error.response?.status === 401) { printTestResult(3, 'No token provided', true, `Correctly returned 401: ${error.response.data.message}`); } else { printTestResult(3, 'No token provided', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } // Test 4: Check quiz limit with invalid token (should fail) printSection('Test 4: Check quiz limit with invalid token (should fail with 401)'); try { const response = await axios.get(`${BASE_URL}/guest/quiz-limit`, { headers: { 'X-Guest-Token': 'invalid.token.here' } }); printTestResult(4, 'Invalid token provided', false, 'Should have returned 401 but got: ' + response.status); } catch (error) { if (error.response?.status === 401) { printTestResult(4, 'Invalid token provided', true, `Correctly returned 401: ${error.response.data.message}`); } else { printTestResult(4, 'Invalid token provided', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } // Test 5: Simulate reaching quiz limit printSection('Test 5: Simulate quiz limit reached (update database manually)'); console.log('\nℹ️ To test limit reached scenario:'); console.log(' Run this SQL query:'); console.log(` UPDATE guest_sessions SET quizzes_attempted = 3 WHERE guest_id = '${testSession.guestId}';`); console.log('\nℹ️ Then check quiz limit again with this curl command:'); console.log(` curl -H "X-Guest-Token: ${testSession.sessionToken}" ${BASE_URL}/guest/quiz-limit`); console.log('\n Expected: hasReachedLimit: true, upgradePrompt with benefits'); // Test 6: Check with non-existent guest ID token printSection('Test 6: Check with token for non-existent guest (should fail with 404)'); try { // Create a token with fake guest ID const jwt = require('jsonwebtoken'); const config = require('./config/config'); const fakeToken = jwt.sign( { guestId: 'guest_fake_12345' }, config.jwt.secret, { expiresIn: '24h' } ); const response = await axios.get(`${BASE_URL}/guest/quiz-limit`, { headers: { 'X-Guest-Token': fakeToken } }); printTestResult(6, 'Non-existent guest ID', false, 'Should have returned 404 but got: ' + response.status); } catch (error) { if (error.response?.status === 404) { printTestResult(6, 'Non-existent guest ID', true, `Correctly returned 404: ${error.response.data.message}`); } else { printTestResult(6, 'Non-existent guest ID', false, `Wrong status code: ${error.response?.status || 'unknown'}`); } } // Test 7: Verify response structure printSection('Test 7: Verify response structure and data types'); try { const response = await axios.get(`${BASE_URL}/guest/quiz-limit`, { headers: { 'X-Guest-Token': testSession.sessionToken } }); const { data } = response.data; const hasCorrectStructure = data.guestId && data.quizLimit && typeof data.quizLimit.maxQuizzes === 'number' && typeof data.quizLimit.quizzesAttempted === 'number' && typeof data.quizLimit.quizzesRemaining === 'number' && typeof data.quizLimit.hasReachedLimit === 'boolean' && data.session && data.session.expiresAt && data.session.timeRemaining; if (hasCorrectStructure) { printTestResult(7, 'Response structure verification', true, 'All required fields present with correct types'); } else { printTestResult(7, 'Response structure verification', false, 'Missing or incorrect fields in response'); } } catch (error) { printTestResult(7, 'Response structure verification', false, `Error: ${error.message}`); } // Test 8: Verify calculations printSection('Test 8: Verify quiz remaining calculation'); try { const response = await axios.get(`${BASE_URL}/guest/quiz-limit`, { headers: { 'X-Guest-Token': testSession.sessionToken } }); const { quizLimit } = response.data.data; const expectedRemaining = quizLimit.maxQuizzes - quizLimit.quizzesAttempted; if (quizLimit.quizzesRemaining === expectedRemaining) { printTestResult(8, 'Quiz remaining calculation', true, `Calculation correct: ${quizLimit.maxQuizzes} - ${quizLimit.quizzesAttempted} = ${quizLimit.quizzesRemaining}`); } else { printTestResult(8, 'Quiz remaining calculation', false, `Expected ${expectedRemaining} but got ${quizLimit.quizzesRemaining}`); } } catch (error) { printTestResult(8, 'Quiz remaining calculation', false, `Error: ${error.message}`); } } catch (error) { console.error('\n❌ Fatal error during testing:', error.message); } console.log('\n╔════════════════════════════════════════════════════════════╗'); console.log('║ Tests Completed ║'); console.log('╚════════════════════════════════════════════════════════════╝\n'); } // Run tests runTests();