const axios = require('axios'); const ioClient = require('socket.io-client'); const prisma = require('../src/helpers/db/db_connection'); const BASE_URL = 'http://localhost:9000'; async function runTests() { console.log('=== STARTING INTEGRATION TESTS FOR NOTIFICATION SYSTEM ===\n'); // 0. Clean up existing memberships and notifications for rafi@student.com (user ID 1) console.log('0. Cleaning up existing project memberships and notifications for rafi@student.com...'); await prisma.projectMember.deleteMany({ where: { id_user: 1 } }); await prisma.notification.deleteMany({ where: { id_user: 1 } }); console.log(' Cleanup successful!\n'); let adminToken = ''; let mentorToken = ''; let internToken = ''; let mentorId = null; let internId = null; let createdProjectId = null; let taskId = null; const mentorEmail = `mentor_notif_${Date.now()}@internify.com`; const mentorPassword = 'Password123'; const internEmail = 'rafi@student.com'; const internPassword = 'password123'; // Helper config generator const getHeader = (token) => ({ headers: { Authorization: `Bearer ${token}` } }); let internSocket = null; let mentorSocket = null; const internReceivedNotifs = []; const mentorReceivedNotifs = []; try { // 1. Login as Admin console.log('1. Logging in as Admin (admin1@internify.com)...'); const loginRes = await axios.post(`${BASE_URL}/auth-api/login`, { email: 'admin1@internify.com', password: 'password123' }); adminToken = loginRes.data.data.token; console.log(' Admin logged in successfully!\n'); // 2. Create Mentor Account via Admin API console.log(`2. Creating a new Mentor account (${mentorEmail})...`); const createMentorRes = await axios.post(`${BASE_URL}/admin-api/add`, { nama_depan: 'Jane', nama_belakang: 'MentorNotif', email: mentorEmail, password: mentorPassword, role: 'mentor' }, getHeader(adminToken)); console.log(' Mentor account created successfully!\n'); // 3. Login as the new Mentor console.log('3. Logging in as the new Mentor...'); const mentorLoginRes = await axios.post(`${BASE_URL}/auth-api/login`, { email: mentorEmail, password: mentorPassword }); mentorToken = mentorLoginRes.data.data.token; mentorId = mentorLoginRes.data.data.user.id; console.log(` Mentor logged in successfully! ID: ${mentorId}\n`); // 4. Login as Intern console.log(`4. Logging in as Intern (${internEmail})...`); const internLoginRes = await axios.post(`${BASE_URL}/auth-api/login`, { email: internEmail, password: internPassword }); internToken = internLoginRes.data.data.token; internId = internLoginRes.data.data.user.id; console.log(` Intern logged in successfully! ID: ${internId}\n`); // 5. Establish WebSocket Connections for Intern and Mentor console.log('5. Connecting to WebSocket (Socket.io) server...'); internSocket = ioClient(BASE_URL, { auth: { token: internToken }, transports: ['websocket'] }); mentorSocket = ioClient(BASE_URL, { auth: { token: mentorToken }, transports: ['websocket'] }); // Setup socket listeners internSocket.on('notification', (notif) => { console.log(` [WS Event] Intern received real-time notification: "${notif.title}" - ${notif.message}`); internReceivedNotifs.push(notif); }); mentorSocket.on('notification', (notif) => { console.log(` [WS Event] Mentor received real-time notification: "${notif.title}" - ${notif.message}`); mentorReceivedNotifs.push(notif); }); // Wait a brief moment to ensure sockets are connected await new Promise(resolve => setTimeout(resolve, 1000)); console.log(' Sockets connected!\n'); // 6. Mentor creates project and assigns Intern console.log(`6. Mentor creating project and assigning intern (ID: ${internId})...`); const createProjectRes = await axios.post(`${BASE_URL}/project-api/add`, { project_icon: 'code', project_name: `Notification Test Project - ${Date.now()}`, description: 'Project to test WebSocket notifications.', start_date: '2026-07-01', end_date: '2026-10-01', member_emails: [internEmail] }, getHeader(mentorToken)); createdProjectId = createProjectRes.data.data.id; console.log(` Project created successfully! ID: ${createdProjectId}`); // Wait for the WS notification to arrive await new Promise(resolve => setTimeout(resolve, 1000)); // Check if intern received "Diterima ke Proyek" notification const assignmentNotif = internReceivedNotifs.find(n => n.title === 'Diterima ke Proyek'); if (!assignmentNotif) { throw new Error('TEST FAILED: Intern did not receive real-time project assignment notification!'); } console.log(' PASSED: Intern received project assignment notification over WebSocket.\n'); // 7. Mentor creates a task in the project console.log(`7. Mentor creating a task in project ID ${createdProjectId}...`); const createTaskRes = await axios.post(`${BASE_URL}/task-api/projects/${createdProjectId}/tasks`, { title: 'Real-time Task', description: 'Submit this task to test mentor notifications.', deadline_date: '2026-08-01', specific_time: '23:59', submission_type: 'url_link' }, getHeader(mentorToken)); taskId = createTaskRes.data.data.id; console.log(` Task created successfully! ID: ${taskId}`); // Wait for the WS notification to arrive await new Promise(resolve => setTimeout(resolve, 1000)); // Check if intern received "Tugas Baru Ditambahkan" notification const taskNotif = internReceivedNotifs.find(n => n.title === 'Tugas Baru Ditambahkan'); if (!taskNotif) { throw new Error('TEST FAILED: Intern did not receive real-time task creation notification!'); } console.log(' PASSED: Intern received task creation notification over WebSocket.\n'); // 8. Intern submits the task console.log(`8. Intern submitting task ID ${taskId}...`); await axios.post(`${BASE_URL}/task-api/tasks/${taskId}/submissions`, { url_link: 'https://github.com/rafiathallah/notification-system' }, getHeader(internToken)); console.log(' Task submitted successfully!'); // Wait for the WS notification to arrive await new Promise(resolve => setTimeout(resolve, 1000)); // Check if mentor received "Pengiriman Tugas Baru" notification const submissionNotif = mentorReceivedNotifs.find(n => n.title === 'Pengiriman Tugas Baru'); if (!submissionNotif) { throw new Error('TEST FAILED: Mentor did not receive real-time task submission notification!'); } console.log(' PASSED: Mentor received task submission notification over WebSocket.\n'); // 9. Intern retrieves their notifications via HTTP console.log('9. Intern fetching notifications via GET /notification-api...'); const getNotifsRes = await axios.get(`${BASE_URL}/notification-api`, getHeader(internToken)); const dbNotifications = getNotifsRes.data.data; console.log(` Notifications found: ${dbNotifications.length}`); dbNotifications.forEach(n => console.log(` - [ID: ${n.id}] [Read: ${n.is_read}] ${n.title}: ${n.message}`)); if (dbNotifications.length < 2) { throw new Error('TEST FAILED: Intern notifications list in database is incomplete!'); } const hasUnread = dbNotifications.every(n => n.is_read === false); if (!hasUnread) { throw new Error('TEST FAILED: Notifications should be unread by default!'); } console.log(' PASSED: HTTP notification retrieval correct.\n'); // 10. Intern marks a single notification as read const targetNotifId = dbNotifications[0].id; console.log(`10. Intern marking notification ID ${targetNotifId} as read...`); const markReadRes = await axios.patch(`${BASE_URL}/notification-api/${targetNotifId}/read`, {}, getHeader(internToken)); if (!markReadRes.data.data.is_read) { throw new Error('TEST FAILED: Notification status did not update to read!'); } console.log(' PASSED: Single notification marked as read.\n'); // 11. Intern marks all notifications as read console.log('11. Intern marking all remaining notifications as read...'); await axios.patch(`${BASE_URL}/notification-api/read-all`, {}, getHeader(internToken)); const recheckNotifsRes = await axios.get(`${BASE_URL}/notification-api`, getHeader(internToken)); const updatedNotifications = recheckNotifsRes.data.data; const allRead = updatedNotifications.every(n => n.is_read === true); if (!allRead) { throw new Error('TEST FAILED: Not all notifications were marked as read!'); } console.log(' PASSED: All notifications marked as read successfully.\n'); console.log('=== ALL INTEGRATION TESTS PASSED SUCCESSFULLY! ==='); } catch (err) { console.error('=== TEST EXECUTION ENCOUNTERED AN ERROR ==='); if (err.response) { console.error(`Status: ${err.response.status}`); console.error('Response Data:', JSON.stringify(err.response.data, null, 2)); } else { console.error(err); } process.exit(1); } finally { // Cleanup WebSocket connections if (internSocket) internSocket.close(); if (mentorSocket) mentorSocket.close(); } } runTests();