// GuestSession Model Tests const { sequelize, GuestSession, User } = require('./models'); async function runTests() { try { console.log('๐Ÿงช Running GuestSession Model Tests\n'); console.log('=====================================\n'); // Test 1: Create a guest session console.log('Test 1: Create a new guest session'); const session1 = await GuestSession.createSession({ deviceId: 'device-123', ipAddress: '192.168.1.1', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', maxQuizzes: 5 }); console.log('โœ… Guest session created with ID:', session1.id); console.log(' Guest ID:', session1.guestId); console.log(' Session token:', session1.sessionToken.substring(0, 50) + '...'); console.log(' Max quizzes:', session1.maxQuizzes); console.log(' Expires at:', session1.expiresAt); console.log(' Match:', session1.guestId.startsWith('guest_') ? 'โœ…' : 'โŒ'); // Test 2: Generate guest ID console.log('\nTest 2: Generate guest ID with correct format'); const guestId = GuestSession.generateGuestId(); console.log('โœ… Generated guest ID:', guestId); console.log(' Starts with "guest_":', guestId.startsWith('guest_') ? 'โœ…' : 'โŒ'); console.log(' Has timestamp and random:', guestId.split('_').length === 3 ? 'โœ…' : 'โŒ'); // Test 3: Token verification console.log('\nTest 3: Verify and decode session token'); try { const decoded = GuestSession.verifyToken(session1.sessionToken); console.log('โœ… Token verified successfully'); console.log(' Guest ID matches:', decoded.guestId === session1.guestId ? 'โœ…' : 'โŒ'); console.log(' Session ID matches:', decoded.sessionId === session1.id ? 'โœ…' : 'โŒ'); console.log(' Token type:', decoded.type); } catch (error) { console.log('โŒ Token verification failed:', error.message); } // Test 4: Find by guest ID console.log('\nTest 4: Find session by guest ID'); const foundSession = await GuestSession.findByGuestId(session1.guestId); console.log('โœ… Session found by guest ID'); console.log(' ID matches:', foundSession.id === session1.id ? 'โœ…' : 'โŒ'); // Test 5: Find by token console.log('\nTest 5: Find session by token'); const foundByToken = await GuestSession.findByToken(session1.sessionToken); console.log('โœ… Session found by token'); console.log(' ID matches:', foundByToken.id === session1.id ? 'โœ…' : 'โŒ'); // Test 6: Check if expired console.log('\nTest 6: Check if session is expired'); const isExpired = session1.isExpired(); console.log('โœ… Session expiry checked'); console.log(' Is expired:', isExpired); console.log(' Should not be expired:', !isExpired ? 'โœ…' : 'โŒ'); // Test 7: Quiz limit check console.log('\nTest 7: Check quiz limit'); const hasReachedLimit = session1.hasReachedQuizLimit(); const remaining = session1.getRemainingQuizzes(); console.log('โœ… Quiz limit checked'); console.log(' Has reached limit:', hasReachedLimit); console.log(' Remaining quizzes:', remaining); console.log(' Match expected (5):', remaining === 5 ? 'โœ…' : 'โŒ'); // Test 8: Increment quiz attempt console.log('\nTest 8: Increment quiz attempt count'); const beforeAttempts = session1.quizzesAttempted; await session1.incrementQuizAttempt(); await session1.reload(); console.log('โœ… Quiz attempt incremented'); console.log(' Before:', beforeAttempts); console.log(' After:', session1.quizzesAttempted); console.log(' Match:', session1.quizzesAttempted === beforeAttempts + 1 ? 'โœ…' : 'โŒ'); // Test 9: Multiple quiz attempts until limit console.log('\nTest 9: Increment attempts until limit reached'); for (let i = 0; i < 4; i++) { await session1.incrementQuizAttempt(); } await session1.reload(); console.log('โœ… Incremented to limit'); console.log(' Quizzes attempted:', session1.quizzesAttempted); console.log(' Max quizzes:', session1.maxQuizzes); console.log(' Has reached limit:', session1.hasReachedQuizLimit() ? 'โœ…' : 'โŒ'); console.log(' Remaining quizzes:', session1.getRemainingQuizzes()); // Test 10: Get session info console.log('\nTest 10: Get session info object'); const sessionInfo = session1.getSessionInfo(); console.log('โœ… Session info retrieved'); console.log(' Guest ID:', sessionInfo.guestId); console.log(' Quizzes attempted:', sessionInfo.quizzesAttempted); console.log(' Remaining:', sessionInfo.remainingQuizzes); console.log(' Has reached limit:', sessionInfo.hasReachedLimit); console.log(' Match:', typeof sessionInfo === 'object' ? 'โœ…' : 'โŒ'); // Test 11: Extend session console.log('\nTest 11: Extend session expiry'); const oldExpiry = new Date(session1.expiresAt); await session1.extend(48); // Extend by 48 hours await session1.reload(); const newExpiry = new Date(session1.expiresAt); console.log('โœ… Session extended'); console.log(' Old expiry:', oldExpiry); console.log(' New expiry:', newExpiry); console.log(' Extended:', newExpiry > oldExpiry ? 'โœ…' : 'โŒ'); // Test 12: Create user and convert session console.log('\nTest 12: Convert guest session to registered user'); const testUser = await User.create({ username: `converteduser${Date.now()}`, email: `converted${Date.now()}@test.com`, password: 'password123', role: 'user' }); await session1.convertToUser(testUser.id); await session1.reload(); console.log('โœ… Session converted to user'); console.log(' Is converted:', session1.isConverted); console.log(' Converted user ID:', session1.convertedUserId); console.log(' Match:', session1.convertedUserId === testUser.id ? 'โœ…' : 'โŒ'); // Test 13: Find active session (should not find converted one) console.log('\nTest 13: Find active session (excluding converted)'); const activeSession = await GuestSession.findActiveSession(session1.guestId); console.log('โœ… Active session search completed'); console.log(' Should be null:', activeSession === null ? 'โœ…' : 'โŒ'); // Test 14: Create another session and find active console.log('\nTest 14: Create new session and find active'); const session2 = await GuestSession.createSession({ deviceId: 'device-456', maxQuizzes: 3 }); const activeSession2 = await GuestSession.findActiveSession(session2.guestId); console.log('โœ… Found active session'); console.log(' ID matches:', activeSession2.id === session2.id ? 'โœ…' : 'โŒ'); // Test 15: Get active guest count console.log('\nTest 15: Get active guest count'); const activeCount = await GuestSession.getActiveGuestCount(); console.log('โœ… Active guest count:', activeCount); console.log(' Expected at least 1:', activeCount >= 1 ? 'โœ…' : 'โŒ'); // Test 16: Get conversion rate console.log('\nTest 16: Calculate conversion rate'); const conversionRate = await GuestSession.getConversionRate(); console.log('โœ… Conversion rate:', conversionRate + '%'); console.log(' Expected 50% (1 of 2):', conversionRate === 50 ? 'โœ…' : 'โŒ'); // Test 17: Invalid token verification console.log('\nTest 17: Verify invalid token'); try { GuestSession.verifyToken('invalid-token-12345'); console.log('โŒ Should have thrown error'); } catch (error) { console.log('โœ… Invalid token rejected:', error.message.includes('Invalid') ? 'โœ…' : 'โŒ'); } // Test 18: Unique constraints console.log('\nTest 18: Test unique constraint on guest_id'); try { await GuestSession.create({ guestId: session1.guestId, // Duplicate guest_id sessionToken: 'some-unique-token', expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), maxQuizzes: 3 }); console.log('โŒ Should have thrown unique constraint error'); } catch (error) { console.log('โœ… Unique constraint enforced:', error.name === 'SequelizeUniqueConstraintError' ? 'โœ…' : 'โŒ'); } // Test 19: Association with User console.log('\nTest 19: Load session with converted user association'); const sessionWithUser = await GuestSession.findByPk(session1.id, { include: [{ model: User, as: 'convertedUser' }] }); console.log('โœ… Session loaded with user association'); console.log(' User username:', sessionWithUser.convertedUser?.username); console.log(' Match:', sessionWithUser.convertedUser?.id === testUser.id ? 'โœ…' : 'โŒ'); // Test 20: Cleanup expired sessions (simulate) console.log('\nTest 20: Cleanup expired sessions'); // Create an expired session by creating a valid one then updating it const tempSession = await GuestSession.createSession({ maxQuizzes: 3 }); await tempSession.update({ expiresAt: new Date(Date.now() - 1000) // Set to expired }, { validate: false // Skip validation }); const cleanedCount = await GuestSession.cleanupExpiredSessions(); console.log('โœ… Expired sessions cleaned'); console.log(' Sessions deleted:', cleanedCount); console.log(' Expected at least 1:', cleanedCount >= 1 ? 'โœ…' : 'โŒ'); // Cleanup console.log('\n====================================='); console.log('๐Ÿงน Cleaning up test data...'); await GuestSession.destroy({ where: {}, force: true }); await User.destroy({ where: {}, force: true }); console.log('โœ… Test data deleted\n'); await sequelize.close(); console.log('โœ… All GuestSession Model Tests Completed!\n'); process.exit(0); } catch (error) { console.error('\nโŒ Test failed with error:', error.message); console.error('Error details:', error); await sequelize.close(); process.exit(1); } } // Need uuid for test 20 const { v4: uuidv4 } = require('uuid'); runTests();