require('dotenv').config(); const db = require('../models'); const { User } = db; async function testUserModel() { console.log('\n๐Ÿงช Testing User Model...\n'); try { // Test 1: Create a test user console.log('Test 1: Creating a test user...'); const testUser = await User.create({ username: 'testuser', email: 'test@example.com', password: 'password123', role: 'user' }); console.log('โœ… User created successfully'); console.log(' - ID:', testUser.id); console.log(' - Username:', testUser.username); console.log(' - Email:', testUser.email); console.log(' - Role:', testUser.role); console.log(' - Password hashed:', testUser.password.substring(0, 20) + '...'); console.log(' - Password length:', testUser.password.length); // Test 2: Verify password hashing console.log('\nTest 2: Testing password hashing...'); const isPasswordHashed = testUser.password !== 'password123'; console.log('โœ… Password is hashed:', isPasswordHashed); console.log(' - Original: password123'); console.log(' - Hashed:', testUser.password.substring(0, 30) + '...'); // Test 3: Test password comparison console.log('\nTest 3: Testing password comparison...'); const isCorrectPassword = await testUser.comparePassword('password123'); const isWrongPassword = await testUser.comparePassword('wrongpassword'); console.log('โœ… Correct password:', isCorrectPassword); console.log('โœ… Wrong password rejected:', !isWrongPassword); // Test 4: Test toJSON (password should be excluded) console.log('\nTest 4: Testing toJSON (password exclusion)...'); const userJSON = testUser.toJSON(); const hasPassword = 'password' in userJSON; console.log('โœ… Password excluded from JSON:', !hasPassword); console.log(' JSON keys:', Object.keys(userJSON).join(', ')); // Test 5: Test findByEmail console.log('\nTest 5: Testing findByEmail...'); const foundUser = await User.findByEmail('test@example.com'); console.log('โœ… User found by email:', foundUser ? 'Yes' : 'No'); console.log(' - Username:', foundUser.username); // Test 6: Test findByUsername console.log('\nTest 6: Testing findByUsername...'); const foundByUsername = await User.findByUsername('testuser'); console.log('โœ… User found by username:', foundByUsername ? 'Yes' : 'No'); // Test 7: Test streak calculation console.log('\nTest 7: Testing streak calculation...'); testUser.updateStreak(); console.log('โœ… Streak updated'); console.log(' - Current streak:', testUser.currentStreak); console.log(' - Longest streak:', testUser.longestStreak); console.log(' - Last quiz date:', testUser.lastQuizDate); // Test 8: Test accuracy calculation console.log('\nTest 8: Testing accuracy calculation...'); testUser.totalQuestionsAnswered = 10; testUser.correctAnswers = 8; const accuracy = testUser.calculateAccuracy(); console.log('โœ… Accuracy calculated:', accuracy + '%'); // Test 9: Test pass rate calculation console.log('\nTest 9: Testing pass rate calculation...'); testUser.totalQuizzes = 5; testUser.quizzesPassed = 4; const passRate = testUser.getPassRate(); console.log('โœ… Pass rate calculated:', passRate + '%'); // Test 10: Test unique constraints console.log('\nTest 10: Testing unique constraints...'); try { await User.create({ username: 'testuser', // Duplicate username email: 'another@example.com', password: 'password123' }); console.log('โŒ Unique constraint not working'); } catch (error) { if (error.name === 'SequelizeUniqueConstraintError') { console.log('โœ… Unique username constraint working'); } } // Test 11: Test email validation console.log('\nTest 11: Testing email validation...'); try { await User.create({ username: 'invaliduser', email: 'not-an-email', // Invalid email password: 'password123' }); console.log('โŒ Email validation not working'); } catch (error) { if (error.name === 'SequelizeValidationError') { console.log('โœ… Email validation working'); } } // Test 12: Test password update console.log('\nTest 12: Testing password update...'); const oldPassword = testUser.password; testUser.password = 'newpassword456'; await testUser.save(); const passwordChanged = oldPassword !== testUser.password; console.log('โœ… Password re-hashed on update:', passwordChanged); const newPasswordWorks = await testUser.comparePassword('newpassword456'); console.log('โœ… New password works:', newPasswordWorks); // Cleanup console.log('\n๐Ÿงน Cleaning up test data...'); await testUser.destroy(); console.log('โœ… Test user deleted'); console.log('\n' + '='.repeat(60)); console.log('โœ… ALL TESTS PASSED!'); console.log('='.repeat(60)); console.log('\nUser Model Summary:'); console.log('- โœ… User creation with UUID'); console.log('- โœ… Password hashing (bcrypt)'); console.log('- โœ… Password comparison'); console.log('- โœ… toJSON excludes password'); console.log('- โœ… Find by email/username'); console.log('- โœ… Streak calculation'); console.log('- โœ… Accuracy/pass rate calculation'); console.log('- โœ… Unique constraints'); console.log('- โœ… Email validation'); console.log('- โœ… Password update & re-hash'); console.log('\n'); process.exit(0); } catch (error) { console.error('\nโŒ Test failed:', error.message); if (error.errors) { error.errors.forEach(err => { console.error(' -', err.message); }); } console.error('\nStack:', error.stack); process.exit(1); } } testUserModel();