import readline from 'readline'; import { io } from 'socket.io-client'; const API_URL = process.env.API_URL || 'http://localhost:4010/api'; // slug المستأجر — «siro» هو المزروع على السيرفر (راجع لوق [Seed] عند الإقلاع). const TENANT_ID = process.env.TENANT_ID || 'siro'; async function api(method, path, body = null, token = null) { const options = { method, headers: { 'Content-Type': 'application/json', 'x-tenant-id': TENANT_ID, 'x-device-id': 'simulated-device-123' } }; if (token) { options.headers['Authorization'] = `Bearer ${token}`; } if (body) { options.body = JSON.stringify(body); } const res = await fetch(`${API_URL}${path}`, options); const data = await res.json().catch(() => null); if (!res.ok) { console.error(`\x1b[31m[API Error] ${method} ${path} -> ${res.status}\x1b[0m`, data); throw new Error(`API Error: ${res.status}`); } return data; } async function run() { console.log('\n=========================================='); console.log('🚀 Tripz Backend Automated E2E Simulation'); console.log('==========================================\n'); // 1. Authenticate Demo Driver const driverPhone = '+962790000001'; console.log(`[Driver] Authenticating Demo Driver (${driverPhone})...`); await api('POST', '/auth/send-otp', { phone: driverPhone }); const driverAuth = await api('POST', '/auth/verify-otp', { phone: driverPhone, code: '1234' }); const driverToken = driverAuth.access_token; console.log('\x1b[32m[Driver] Authenticated successfully!\x1b[0m\n'); // 2. Authenticate Demo Rider const riderPhone = '+962790000002'; console.log(`[Rider] Authenticating Demo Rider (${riderPhone})...`); await api('POST', '/auth/send-otp', { phone: riderPhone }); const riderAuth = await api('POST', '/auth/verify-otp', { phone: riderPhone, code: '1234' }); const riderToken = riderAuth.access_token; console.log('\x1b[32m[Rider] Authenticated successfully!\x1b[0m\n'); // 3. Setup Driver Profile & Go Online console.log(`[Driver] Creating Driver profile...`); await api('POST', '/drivers/apply', { service_class: 'economy', vehicle_make: 'Toyota', vehicle_model: 'Prius', vehicle_plate: '12-3456' }, driverToken); console.log(`[Driver] Going Online...`); await api('PATCH', '/drivers/status', { online: true }, driverToken); console.log('\x1b[32m[Driver] Profile created and is now ONLINE.\x1b[0m\n'); // 4. Connect WebSockets console.log(`[Sockets] Connecting Rider and Driver via WebSockets...`); const WS_URL = API_URL.replace('/api', ''); const driverSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${driverToken}` } }); const riderSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${riderToken}` } }); let tripId = null; driverSocket.on('connect', () => console.log('\x1b[36m[Driver WS] Connected to Gateway\x1b[0m')); riderSocket.on('connect', () => console.log('\x1b[36m[Rider WS] Connected to Gateway\x1b[0m')); driverSocket.on('trip:dispatch', async (data) => { console.log(`\n\x1b[35m[Driver WS] 🔔 RECEIVED DISPATCH for Trip ${data.id}!\x1b[0m`); tripId = data.id; console.log(`[Driver] Accepting Trip...`); await api('POST', `/trips/${tripId}/accept`, null, driverToken); console.log(`\x1b[32m[Driver] Trip Accepted successfully!\x1b[0m`); }); riderSocket.on('trip:updated', (data) => { console.log(`\x1b[33m[Rider WS] Trip status updated: ${data.status}\x1b[0m`); }); await new Promise(r => setTimeout(r, 2000)); // 5. Driver Location Pings let driverLat = 32.0645; // Zarqa Coordinates let driverLng = 36.0827; const locationInterval = setInterval(() => { // Driver moves slightly driverLat += 0.0001; driverSocket.emit('driver:location', { lat: driverLat, lng: driverLng, speed: 40, heading: 90 }); console.log(`[Driver WS] 📍 Location ping: ${driverLat.toFixed(5)}, ${driverLng.toFixed(5)}`); }, 3000); // 6. Rider Requests Trip console.log(`\n[Rider] Requesting Trip from Zarqa...`); const tripRequest = await api('POST', '/trips', { city: 'amman', service_class: 'economy', origin: { lat: 32.0650, lng: 36.0830 }, // Zarqa origin destination: { lat: 32.0700, lng: 36.0900 } }, riderToken); console.log(`\x1b[32m[Rider] Trip created: ${tripRequest.trip.id}\x1b[0m`); // 7. Simulate Trip Flow (Wait 10 seconds per state) await new Promise(r => setTimeout(r, 10000)); if (tripId) { console.log(`\n[Driver] Arriving at pickup...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'driver_arrived' }, driverToken); await new Promise(r => setTimeout(r, 5000)); console.log(`\n[Driver] Starting Trip...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'in_progress' }, driverToken); await new Promise(r => setTimeout(r, 5000)); console.log(`\n[Driver] Completing Trip...`); await api('PATCH', `/trips/${tripId}/status`, { status: 'completed' }, driverToken); console.log(`\n\x1b[32m🎉 E2E Simulation Completed Successfully!\x1b[0m\n`); } else { console.log(`\n\x1b[31mFailed to receive dispatch!\x1b[0m\n`); } clearInterval(locationInterval); driverSocket.disconnect(); riderSocket.disconnect(); process.exit(0); } run().catch(console.error);