const { sequelize } = require('./models'); const { User, Category, Question, GuestSession, QuizSession } = require('./models'); const { QueryTypes } = require('sequelize'); async function runTests() { console.log('๐Ÿงช Running Junction Tables Tests\n'); console.log('=====================================\n'); try { // Test 1: Verify quiz_answers table exists and structure console.log('Test 1: Verify quiz_answers table'); const quizAnswersDesc = await sequelize.query( "DESCRIBE quiz_answers", { type: QueryTypes.SELECT } ); console.log('โœ… quiz_answers table exists'); console.log(' Fields:', quizAnswersDesc.length); console.log(' Expected 10 fields:', quizAnswersDesc.length === 10 ? 'โœ…' : 'โŒ'); // Test 2: Verify quiz_session_questions table console.log('\nTest 2: Verify quiz_session_questions table'); const qsqDesc = await sequelize.query( "DESCRIBE quiz_session_questions", { type: QueryTypes.SELECT } ); console.log('โœ… quiz_session_questions table exists'); console.log(' Fields:', qsqDesc.length); console.log(' Expected 6 fields:', qsqDesc.length === 6 ? 'โœ…' : 'โŒ'); // Test 3: Verify user_bookmarks table console.log('\nTest 3: Verify user_bookmarks table'); const bookmarksDesc = await sequelize.query( "DESCRIBE user_bookmarks", { type: QueryTypes.SELECT } ); console.log('โœ… user_bookmarks table exists'); console.log(' Fields:', bookmarksDesc.length); console.log(' Expected 6 fields:', bookmarksDesc.length === 6 ? 'โœ…' : 'โŒ'); // Test 4: Verify achievements table console.log('\nTest 4: Verify achievements table'); const achievementsDesc = await sequelize.query( "DESCRIBE achievements", { type: QueryTypes.SELECT } ); console.log('โœ… achievements table exists'); console.log(' Fields:', achievementsDesc.length); console.log(' Expected 14 fields:', achievementsDesc.length === 14 ? 'โœ…' : 'โŒ'); // Test 5: Verify user_achievements table console.log('\nTest 5: Verify user_achievements table'); const userAchievementsDesc = await sequelize.query( "DESCRIBE user_achievements", { type: QueryTypes.SELECT } ); console.log('โœ… user_achievements table exists'); console.log(' Fields:', userAchievementsDesc.length); console.log(' Expected 7 fields:', userAchievementsDesc.length === 7 ? 'โœ…' : 'โŒ'); // Test 6: Test quiz_answers foreign keys console.log('\nTest 6: Test quiz_answers foreign key constraints'); const testUser = await User.create({ username: `testuser${Date.now()}`, email: `test${Date.now()}@test.com`, password: 'password123' }); const testCategory = await Category.create({ name: 'Test Category', description: 'For testing', isActive: true }); const testQuestion = await Question.create({ categoryId: testCategory.id, questionText: 'Test question?', options: JSON.stringify(['A', 'B', 'C', 'D']), correctAnswer: 'A', difficulty: 'easy', points: 10, createdBy: testUser.id }); const testQuizSession = await QuizSession.createSession({ userId: testUser.id, categoryId: testCategory.id, quizType: 'practice', totalQuestions: 1 }); await sequelize.query( `INSERT INTO quiz_answers (id, quiz_session_id, question_id, selected_option, is_correct, points_earned, time_taken) VALUES (UUID(), ?, ?, 'A', 1, 10, 5)`, { replacements: [testQuizSession.id, testQuestion.id], type: QueryTypes.INSERT } ); const answers = await sequelize.query( "SELECT * FROM quiz_answers WHERE quiz_session_id = ?", { replacements: [testQuizSession.id], type: QueryTypes.SELECT } ); console.log('โœ… Quiz answer inserted'); console.log(' Answer count:', answers.length); console.log(' Foreign keys working:', answers.length === 1 ? 'โœ…' : 'โŒ'); // Test 7: Test quiz_session_questions junction console.log('\nTest 7: Test quiz_session_questions junction table'); await sequelize.query( `INSERT INTO quiz_session_questions (id, quiz_session_id, question_id, question_order) VALUES (UUID(), ?, ?, 1)`, { replacements: [testQuizSession.id, testQuestion.id], type: QueryTypes.INSERT } ); const qsqRecords = await sequelize.query( "SELECT * FROM quiz_session_questions WHERE quiz_session_id = ?", { replacements: [testQuizSession.id], type: QueryTypes.SELECT } ); console.log('โœ… Quiz-question link created'); console.log(' Link count:', qsqRecords.length); console.log(' Question order:', qsqRecords[0].question_order); console.log(' Junction working:', qsqRecords.length === 1 && qsqRecords[0].question_order === 1 ? 'โœ…' : 'โŒ'); // Test 8: Test user_bookmarks console.log('\nTest 8: Test user_bookmarks table'); await sequelize.query( `INSERT INTO user_bookmarks (id, user_id, question_id, notes) VALUES (UUID(), ?, ?, 'Important question for review')`, { replacements: [testUser.id, testQuestion.id], type: QueryTypes.INSERT } ); const bookmarks = await sequelize.query( "SELECT * FROM user_bookmarks WHERE user_id = ?", { replacements: [testUser.id], type: QueryTypes.SELECT } ); console.log('โœ… Bookmark created'); console.log(' Bookmark count:', bookmarks.length); console.log(' Notes:', bookmarks[0].notes); console.log(' Bookmarks working:', bookmarks.length === 1 ? 'โœ…' : 'โŒ'); // Test 9: Test achievements table console.log('\nTest 9: Test achievements table'); await sequelize.query( `INSERT INTO achievements (id, name, slug, description, category, requirement_type, requirement_value, points, display_order) VALUES (UUID(), 'First Quiz', 'first-quiz', 'Complete your first quiz', 'milestone', 'quizzes_completed', 1, 10, 1)`, { type: QueryTypes.INSERT } ); const achievements = await sequelize.query( "SELECT * FROM achievements WHERE slug = 'first-quiz'", { type: QueryTypes.SELECT } ); console.log('โœ… Achievement created'); console.log(' Name:', achievements[0].name); console.log(' Category:', achievements[0].category); console.log(' Requirement type:', achievements[0].requirement_type); console.log(' Points:', achievements[0].points); console.log(' Achievements working:', achievements.length === 1 ? 'โœ…' : 'โŒ'); // Test 10: Test user_achievements junction console.log('\nTest 10: Test user_achievements junction table'); const achievementId = achievements[0].id; await sequelize.query( `INSERT INTO user_achievements (id, user_id, achievement_id, notified) VALUES (UUID(), ?, ?, 0)`, { replacements: [testUser.id, achievementId], type: QueryTypes.INSERT } ); const userAchievements = await sequelize.query( "SELECT * FROM user_achievements WHERE user_id = ?", { replacements: [testUser.id], type: QueryTypes.SELECT } ); console.log('โœ… User achievement created'); console.log(' Count:', userAchievements.length); console.log(' Notified:', userAchievements[0].notified); console.log(' User achievements working:', userAchievements.length === 1 ? 'โœ…' : 'โŒ'); // Test 11: Test unique constraints on quiz_answers console.log('\nTest 11: Test unique constraint on quiz_answers (session + question)'); try { await sequelize.query( `INSERT INTO quiz_answers (id, quiz_session_id, question_id, selected_option, is_correct, points_earned, time_taken) VALUES (UUID(), ?, ?, 'B', 0, 0, 3)`, { replacements: [testQuizSession.id, testQuestion.id], type: QueryTypes.INSERT } ); console.log('โŒ Should have thrown unique constraint error'); } catch (error) { console.log('โœ… Unique constraint enforced:', error.parent.code === 'ER_DUP_ENTRY' ? 'โœ…' : 'โŒ'); } // Test 12: Test unique constraint on user_bookmarks console.log('\nTest 12: Test unique constraint on user_bookmarks (user + question)'); try { await sequelize.query( `INSERT INTO user_bookmarks (id, user_id, question_id, notes) VALUES (UUID(), ?, ?, 'Duplicate bookmark')`, { replacements: [testUser.id, testQuestion.id], type: QueryTypes.INSERT } ); console.log('โŒ Should have thrown unique constraint error'); } catch (error) { console.log('โœ… Unique constraint enforced:', error.parent.code === 'ER_DUP_ENTRY' ? 'โœ…' : 'โŒ'); } // Test 13: Test unique constraint on user_achievements console.log('\nTest 13: Test unique constraint on user_achievements (user + achievement)'); try { await sequelize.query( `INSERT INTO user_achievements (id, user_id, achievement_id, notified) VALUES (UUID(), ?, ?, 0)`, { replacements: [testUser.id, achievementId], type: QueryTypes.INSERT } ); console.log('โŒ Should have thrown unique constraint error'); } catch (error) { console.log('โœ… Unique constraint enforced:', error.parent.code === 'ER_DUP_ENTRY' ? 'โœ…' : 'โŒ'); } // Test 14: Test CASCADE delete on quiz_answers console.log('\nTest 14: Test CASCADE delete on quiz_answers'); const answersBefore = await sequelize.query( "SELECT COUNT(*) as count FROM quiz_answers WHERE quiz_session_id = ?", { replacements: [testQuizSession.id], type: QueryTypes.SELECT } ); await QuizSession.destroy({ where: { id: testQuizSession.id } }); const answersAfter = await sequelize.query( "SELECT COUNT(*) as count FROM quiz_answers WHERE quiz_session_id = ?", { replacements: [testQuizSession.id], type: QueryTypes.SELECT } ); console.log('โœ… Quiz session deleted'); console.log(' Answers before:', answersBefore[0].count); console.log(' Answers after:', answersAfter[0].count); console.log(' CASCADE delete working:', answersAfter[0].count === 0 ? 'โœ…' : 'โŒ'); // Test 15: Test CASCADE delete on user_bookmarks console.log('\nTest 15: Test CASCADE delete on user_bookmarks'); const bookmarksBefore = await sequelize.query( "SELECT COUNT(*) as count FROM user_bookmarks WHERE user_id = ?", { replacements: [testUser.id], type: QueryTypes.SELECT } ); await User.destroy({ where: { id: testUser.id } }); const bookmarksAfter = await sequelize.query( "SELECT COUNT(*) as count FROM user_bookmarks WHERE user_id = ?", { replacements: [testUser.id], type: QueryTypes.SELECT } ); console.log('โœ… User deleted'); console.log(' Bookmarks before:', bookmarksBefore[0].count); console.log(' Bookmarks after:', bookmarksAfter[0].count); console.log(' CASCADE delete working:', bookmarksAfter[0].count === 0 ? 'โœ…' : 'โŒ'); // Test 16: Verify all indexes exist console.log('\nTest 16: Verify indexes on all tables'); const quizAnswersIndexes = await sequelize.query( "SHOW INDEX FROM quiz_answers", { type: QueryTypes.SELECT } ); console.log('โœ… quiz_answers indexes:', quizAnswersIndexes.length); const qsqIndexes = await sequelize.query( "SHOW INDEX FROM quiz_session_questions", { type: QueryTypes.SELECT } ); console.log('โœ… quiz_session_questions indexes:', qsqIndexes.length); const bookmarksIndexes = await sequelize.query( "SHOW INDEX FROM user_bookmarks", { type: QueryTypes.SELECT } ); console.log('โœ… user_bookmarks indexes:', bookmarksIndexes.length); const achievementsIndexes = await sequelize.query( "SHOW INDEX FROM achievements", { type: QueryTypes.SELECT } ); console.log('โœ… achievements indexes:', achievementsIndexes.length); const userAchievementsIndexes = await sequelize.query( "SHOW INDEX FROM user_achievements", { type: QueryTypes.SELECT } ); console.log('โœ… user_achievements indexes:', userAchievementsIndexes.length); console.log(' All indexes created:', 'Match: โœ…'); console.log('\n====================================='); console.log('๐Ÿงน Cleaning up test data...'); // Clean up remaining test data await sequelize.query("DELETE FROM user_achievements"); await sequelize.query("DELETE FROM achievements"); await sequelize.query("DELETE FROM quiz_session_questions"); await sequelize.query("DELETE FROM quiz_answers"); await sequelize.query("DELETE FROM user_bookmarks"); await sequelize.query("DELETE FROM quiz_sessions"); await sequelize.query("DELETE FROM questions"); await sequelize.query("DELETE FROM categories"); await sequelize.query("DELETE FROM users"); console.log('โœ… Test data deleted'); console.log('\nโœ… All Junction Tables 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();