const { sequelize } = require('../models'); const { User, Category, GuestSession, QuizSession } = require('../models'); async function runTests() { console.log('๐Ÿงช Running QuizSession Model Tests\n'); console.log('=====================================\n'); try { let testUser, testCategory, testGuestSession, userQuiz, guestQuiz; // Test 1: Create a quiz session for a registered user console.log('Test 1: Create quiz session for user'); testUser = await User.create({ username: `quizuser${Date.now()}`, email: `quizuser${Date.now()}@test.com`, password: 'password123', role: 'user' }); testCategory = await Category.create({ name: 'Test Category for Quiz', description: 'Category for quiz testing', isActive: true }); userQuiz = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', difficulty: 'medium', totalQuestions: 10, passPercentage: 70.00 }); console.log('โœ… User quiz session created with ID:', userQuiz.id); console.log(' User ID:', userQuiz.userId); console.log(' Category ID:', userQuiz.categoryId); console.log(' Status:', userQuiz.status); console.log(' Total questions:', userQuiz.totalQuestions); console.log(' Match:', userQuiz.status === 'not_started' ? 'โœ…' : 'โŒ'); // Test 2: Create a quiz session for a guest console.log('\nTest 2: Create quiz session for guest'); testGuestSession = await GuestSession.createSession({ maxQuizzes: 5, expiryHours: 24 }); guestQuiz = await QuizSession.createSession({ guestSessionId: testGuestSession.id, categoryId: testCategory.id, quizType: 'practice', difficulty: 'easy', totalQuestions: 5, passPercentage: 60.00 }); console.log('โœ… Guest quiz session created with ID:', guestQuiz.id); console.log(' Guest session ID:', guestQuiz.guestSessionId); console.log(' Category ID:', guestQuiz.categoryId); console.log(' Total questions:', guestQuiz.totalQuestions); console.log(' Match:', guestQuiz.guestSessionId === testGuestSession.id ? 'โœ…' : 'โŒ'); // Test 3: Start a quiz session console.log('\nTest 3: Start quiz session'); await userQuiz.start(); await userQuiz.reload(); console.log('โœ… Quiz started'); console.log(' Status:', userQuiz.status); console.log(' Started at:', userQuiz.startedAt); console.log(' Match:', userQuiz.status === 'in_progress' && userQuiz.startedAt ? 'โœ…' : 'โŒ'); // Test 4: Record correct answer console.log('\nTest 4: Record correct answer'); const beforeAnswers = userQuiz.questionsAnswered; const beforeCorrect = userQuiz.correctAnswers; await userQuiz.recordAnswer(true, 10); await userQuiz.reload(); console.log('โœ… Answer recorded'); console.log(' Questions answered:', userQuiz.questionsAnswered); console.log(' Correct answers:', userQuiz.correctAnswers); console.log(' Total points:', userQuiz.totalPoints); console.log(' Match:', userQuiz.questionsAnswered === beforeAnswers + 1 && userQuiz.correctAnswers === beforeCorrect + 1 ? 'โœ…' : 'โŒ'); // Test 5: Record incorrect answer console.log('\nTest 5: Record incorrect answer'); const beforeAnswers2 = userQuiz.questionsAnswered; const beforeCorrect2 = userQuiz.correctAnswers; await userQuiz.recordAnswer(false, 0); await userQuiz.reload(); console.log('โœ… Incorrect answer recorded'); console.log(' Questions answered:', userQuiz.questionsAnswered); console.log(' Correct answers:', userQuiz.correctAnswers); console.log(' Match:', userQuiz.questionsAnswered === beforeAnswers2 + 1 && userQuiz.correctAnswers === beforeCorrect2 ? 'โœ…' : 'โŒ'); // Test 6: Get quiz progress console.log('\nTest 6: Get quiz progress'); const progress = userQuiz.getProgress(); console.log('โœ… Progress retrieved'); console.log(' Status:', progress.status); console.log(' Questions answered:', progress.questionsAnswered); console.log(' Questions remaining:', progress.questionsRemaining); console.log(' Progress percentage:', progress.progressPercentage + '%'); console.log(' Current accuracy:', progress.currentAccuracy + '%'); console.log(' Match:', progress.questionsAnswered === 2 ? 'โœ…' : 'โŒ'); // Test 7: Update time spent console.log('\nTest 7: Update time spent'); await userQuiz.updateTimeSpent(120); // 2 minutes await userQuiz.reload(); console.log('โœ… Time updated'); console.log(' Time spent:', userQuiz.timeSpent, 'seconds'); console.log(' Match:', userQuiz.timeSpent === 120 ? 'โœ…' : 'โŒ'); // Test 8: Complete quiz by answering remaining questions console.log('\nTest 8: Auto-complete quiz when all questions answered'); // Answer remaining 8 questions (6 correct, 2 incorrect) for (let i = 0; i < 8; i++) { const isCorrect = i < 6; // First 6 are correct await userQuiz.recordAnswer(isCorrect, isCorrect ? 10 : 0); } await userQuiz.reload(); console.log('โœ… Quiz auto-completed'); console.log(' Status:', userQuiz.status); console.log(' Questions answered:', userQuiz.questionsAnswered); console.log(' Correct answers:', userQuiz.correctAnswers); console.log(' Score:', userQuiz.score + '%'); console.log(' Is passed:', userQuiz.isPassed); console.log(' Match:', userQuiz.status === 'completed' && userQuiz.isPassed === true ? 'โœ…' : 'โŒ'); // Test 9: Get quiz results console.log('\nTest 9: Get quiz results'); const results = userQuiz.getResults(); console.log('โœ… Results retrieved'); console.log(' Total questions:', results.totalQuestions); console.log(' Correct answers:', results.correctAnswers); console.log(' Score:', results.score + '%'); console.log(' Is passed:', results.isPassed); console.log(' Duration:', results.duration, 'seconds'); console.log(' Match:', results.correctAnswers === 8 && results.isPassed === true ? 'โœ…' : 'โŒ'); // Test 10: Calculate score console.log('\nTest 10: Calculate score'); const calculatedScore = userQuiz.calculateScore(); console.log('โœ… Score calculated'); console.log(' Calculated score:', calculatedScore + '%'); console.log(' Expected: 80%'); console.log(' Match:', calculatedScore === 80.00 ? 'โœ…' : 'โŒ'); // Test 11: Create timed quiz console.log('\nTest 11: Create timed quiz with time limit'); const timedQuiz = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'timed', difficulty: 'hard', totalQuestions: 20, timeLimit: 600, // 10 minutes passPercentage: 75.00 }); await timedQuiz.start(); console.log('โœ… Timed quiz created'); console.log(' Quiz type:', timedQuiz.quizType); console.log(' Time limit:', timedQuiz.timeLimit, 'seconds'); console.log(' Match:', timedQuiz.quizType === 'timed' && timedQuiz.timeLimit === 600 ? 'โœ…' : 'โŒ'); // Test 12: Timeout a quiz console.log('\nTest 12: Timeout a quiz'); await timedQuiz.updateTimeSpent(610); // Exceed time limit await timedQuiz.reload(); console.log('โœ… Quiz timed out'); console.log(' Status:', timedQuiz.status); console.log(' Time spent:', timedQuiz.timeSpent); console.log(' Match:', timedQuiz.status === 'timed_out' ? 'โœ…' : 'โŒ'); // Test 13: Abandon a quiz console.log('\nTest 13: Abandon a quiz'); const abandonQuiz = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', difficulty: 'easy', totalQuestions: 15 }); await abandonQuiz.start(); await abandonQuiz.recordAnswer(true, 10); await abandonQuiz.abandon(); await abandonQuiz.reload(); console.log('โœ… Quiz abandoned'); console.log(' Status:', abandonQuiz.status); console.log(' Questions answered:', abandonQuiz.questionsAnswered); console.log(' Completed at:', abandonQuiz.completedAt); console.log(' Match:', abandonQuiz.status === 'abandoned' ? 'โœ…' : 'โŒ'); // Test 14: Find active session for user console.log('\nTest 14: Find active session for user'); const activeQuiz = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', difficulty: 'medium', totalQuestions: 10 }); await activeQuiz.start(); const foundActive = await QuizSession.findActiveForUser(testUser.id); console.log('โœ… Active session found'); console.log(' Found ID:', foundActive.id); console.log(' Created ID:', activeQuiz.id); console.log(' Match:', foundActive.id === activeQuiz.id ? 'โœ…' : 'โŒ'); // Test 15: Find active session for guest console.log('\nTest 15: Find active session for guest'); await guestQuiz.start(); const foundGuestActive = await QuizSession.findActiveForGuest(testGuestSession.id); console.log('โœ… Active guest session found'); console.log(' Found ID:', foundGuestActive.id); console.log(' Created ID:', guestQuiz.id); console.log(' Match:', foundGuestActive.id === guestQuiz.id ? 'โœ…' : 'โŒ'); // Test 16: Get user quiz history console.log('\nTest 16: Get user quiz history'); await activeQuiz.complete(); const history = await QuizSession.getUserHistory(testUser.id, 5); console.log('โœ… User history retrieved'); console.log(' History count:', history.length); console.log(' Expected at least 3: โœ…'); // Test 17: Get user statistics console.log('\nTest 17: Get user statistics'); const stats = await QuizSession.getUserStats(testUser.id); console.log('โœ… User stats calculated'); console.log(' Total quizzes:', stats.totalQuizzes); console.log(' Average score:', stats.averageScore + '%'); console.log(' Pass rate:', stats.passRate + '%'); console.log(' Total time spent:', stats.totalTimeSpent, 'seconds'); console.log(' Match:', stats.totalQuizzes >= 1 ? 'โœ…' : 'โŒ'); // Test 18: Get category statistics console.log('\nTest 18: Get category statistics'); const categoryStats = await QuizSession.getCategoryStats(testCategory.id); console.log('โœ… Category stats calculated'); console.log(' Total attempts:', categoryStats.totalAttempts); console.log(' Average score:', categoryStats.averageScore + '%'); console.log(' Pass rate:', categoryStats.passRate + '%'); console.log(' Match:', categoryStats.totalAttempts >= 1 ? 'โœ…' : 'โŒ'); // Test 19: Check isActive method console.log('\nTest 19: Check isActive method'); const newQuiz = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', totalQuestions: 5 }); const isActiveBeforeStart = newQuiz.isActive(); await newQuiz.start(); const isActiveAfterStart = newQuiz.isActive(); await newQuiz.complete(); const isActiveAfterComplete = newQuiz.isActive(); console.log('โœ… Active status checked'); console.log(' Before start:', isActiveBeforeStart); console.log(' After start:', isActiveAfterStart); console.log(' After complete:', isActiveAfterComplete); console.log(' Match:', !isActiveBeforeStart && isActiveAfterStart && !isActiveAfterComplete ? 'โœ…' : 'โŒ'); // Test 20: Check isCompleted method console.log('\nTest 20: Check isCompleted method'); const completionQuiz = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', totalQuestions: 3 }); const isCompletedBefore = completionQuiz.isCompleted(); await completionQuiz.start(); await completionQuiz.complete(); const isCompletedAfter = completionQuiz.isCompleted(); console.log('โœ… Completion status checked'); console.log(' Before completion:', isCompletedBefore); console.log(' After completion:', isCompletedAfter); console.log(' Match:', !isCompletedBefore && isCompletedAfter ? 'โœ…' : 'โŒ'); // Test 21: Test validation - require either userId or guestSessionId console.log('\nTest 21: Test validation - require userId or guestSessionId'); try { await QuizSession.createSession({ categoryId: testCategory.id, quizType: 'practice', totalQuestions: 10 }); console.log('โŒ Should have thrown validation error'); } catch (error) { console.log('โœ… Validation error caught:', error.message); console.log(' Match:', error.message.includes('userId or guestSessionId') ? 'โœ…' : 'โŒ'); } // Test 22: Test validation - cannot have both userId and guestSessionId console.log('\nTest 22: Test validation - cannot have both userId and guestSessionId'); try { await QuizSession.create({ userId: testUser.id, guestSessionId: testGuestSession.id, categoryId: testCategory.id, quizType: 'practice', totalQuestions: 10 }); console.log('โŒ Should have thrown validation error'); } catch (error) { console.log('โœ… Validation error caught:', error.message); console.log(' Match:', error.message.includes('Cannot have both') ? 'โœ…' : 'โŒ'); } // Test 23: Test associations - load with user console.log('\nTest 23: Load quiz session with user association'); const quizWithUser = await QuizSession.findOne({ where: { id: userQuiz.id }, include: [{ model: User, as: 'user' }] }); console.log('โœ… Quiz loaded with user'); console.log(' User username:', quizWithUser.user.username); console.log(' Match:', quizWithUser.user.id === testUser.id ? 'โœ…' : 'โŒ'); // Test 24: Test associations - load with category console.log('\nTest 24: Load quiz session with category association'); const quizWithCategory = await QuizSession.findOne({ where: { id: userQuiz.id }, include: [{ model: Category, as: 'category' }] }); console.log('โœ… Quiz loaded with category'); console.log(' Category name:', quizWithCategory.category.name); console.log(' Match:', quizWithCategory.category.id === testCategory.id ? 'โœ…' : 'โŒ'); // Test 25: Test associations - load with guest session console.log('\nTest 25: Load quiz session with guest session association'); const quizWithGuest = await QuizSession.findOne({ where: { id: guestQuiz.id }, include: [{ model: GuestSession, as: 'guestSession' }] }); console.log('โœ… Quiz loaded with guest session'); console.log(' Guest ID:', quizWithGuest.guestSession.guestId); console.log(' Match:', quizWithGuest.guestSession.id === testGuestSession.id ? 'โœ…' : 'โŒ'); // Test 26: Clean up abandoned sessions console.log('\nTest 26: Clean up abandoned sessions'); const oldQuiz = await QuizSession.create({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', totalQuestions: 10, status: 'abandoned', createdAt: new Date('2020-01-01') }); const deletedCount = await QuizSession.cleanupAbandoned(7); console.log('โœ… Cleanup executed'); console.log(' Deleted count:', deletedCount); console.log(' Expected at least 1:', deletedCount >= 1 ? 'โœ…' : 'โŒ'); console.log('\n====================================='); console.log('๐Ÿงน Cleaning up test data...'); // Clean up test data await QuizSession.destroy({ where: {} }); await GuestSession.destroy({ where: {} }); await Category.destroy({ where: {} }); await User.destroy({ where: {} }); console.log('โœ… Test data deleted'); console.log('\nโœ… All QuizSession Model Tests Completed!'); } catch (error) { console.error('\nโŒ Test failed with error:', error.message); console.error('Error details:', error); process.exit(1); } finally { await sequelize.close(); } } runTests();