Spaces:
Running
Running
| // scripts/test-websocket.ts | |
| // | |
| // Tests Socket.io WebSocket connection and event handling | |
| // Run: npx tsx scripts/test-websocket.ts | |
| // Requires server running. | |
| import 'dotenv/config'; | |
| import { io, type Socket } from 'socket.io-client'; | |
| const PORT = process.env.PORT || '3001'; | |
| const BASE_URL = `http://localhost:${PORT}`; | |
| const PASS = '\x1b[32m✅\x1b[0m'; | |
| const FAIL = '\x1b[31m❌\x1b[0m'; | |
| let passed = 0; | |
| let failed = 0; | |
| function pass(msg: string) { console.log(` ${PASS} ${msg}`); passed++; } | |
| function fail(msg: string) { console.log(` ${FAIL} ${msg}`); failed++; } | |
| function connectSocket(timeout = 5000): Promise<Socket> { | |
| return new Promise((resolve, reject) => { | |
| const socket = io(BASE_URL, { | |
| path: '/ws/socket.io', | |
| transports: ['websocket', 'polling'], | |
| timeout, | |
| reconnection: false, | |
| }); | |
| const timer = setTimeout(() => { | |
| socket.disconnect(); | |
| reject(new Error('Connection timeout')); | |
| }, timeout); | |
| socket.on('connect', () => { | |
| clearTimeout(timer); | |
| resolve(socket); | |
| }); | |
| socket.on('connect_error', (err) => { | |
| clearTimeout(timer); | |
| reject(new Error(`Connection failed: ${err.message}`)); | |
| }); | |
| }); | |
| } | |
| async function main() { | |
| console.log('\n\x1b[1m🔌 ICC WebSocket (Socket.io) Tests\x1b[0m'); | |
| console.log(` Server: ${BASE_URL}`); | |
| console.log('═'.repeat(50)); | |
| // Check server is running first | |
| try { | |
| await fetch(`${BASE_URL}/api/health`, { signal: AbortSignal.timeout(2000) }); | |
| } catch { | |
| fail('Server not running'); | |
| console.log(' → Start with: cd packages/server && npx tsx src/index.ts'); | |
| process.exit(1); | |
| } | |
| // Test 1: Basic connection | |
| console.log('\n\x1b[1mConnection\x1b[0m'); | |
| let mainSocket: Socket | null = null; | |
| try { | |
| mainSocket = await connectSocket(5000); | |
| pass(`Socket.io connects successfully (id: ${mainSocket.id})`); | |
| } catch (error: any) { | |
| fail(`Socket.io connection failed: ${error.message}`); | |
| // Try polling-only as fallback info | |
| console.log(' Trying HTTP polling endpoint...'); | |
| try { | |
| const res = await fetch(`${BASE_URL}/ws/socket.io/?EIO=4&transport=polling`, { signal: AbortSignal.timeout(3000) }); | |
| if (res.ok) { | |
| pass('Socket.io HTTP polling endpoint responds'); | |
| } else { | |
| fail(`Socket.io polling returned ${res.status}`); | |
| } | |
| } catch (e: any) { | |
| fail(`Socket.io polling failed: ${e.message}`); | |
| } | |
| printSummary(); | |
| return; | |
| } | |
| // Test 2: Multiple concurrent connections (stress test) | |
| console.log('\n\x1b[1mStress Test\x1b[0m'); | |
| const clients: Socket[] = []; | |
| let connectFails = 0; | |
| for (let i = 0; i < 5; i++) { | |
| try { | |
| const client = await connectSocket(3000); | |
| clients.push(client); | |
| } catch { | |
| connectFails++; | |
| } | |
| } | |
| if (connectFails === 0) { | |
| pass('5 concurrent connections handled'); | |
| } else { | |
| fail(`${connectFails}/5 connections failed`); | |
| } | |
| // Clean up | |
| clients.forEach((c) => c.disconnect()); | |
| // Test 3: Graceful disconnect | |
| console.log('\n\x1b[1mDisconnect\x1b[0m'); | |
| mainSocket.disconnect(); | |
| await new Promise((r) => setTimeout(r, 500)); | |
| if (!mainSocket.connected) { | |
| pass('Clean disconnect'); | |
| } else { | |
| fail('Socket still connected after disconnect'); | |
| } | |
| // Test 4: Reconnect after disconnect | |
| try { | |
| const ws2 = await connectSocket(5000); | |
| pass('Reconnection after disconnect works'); | |
| ws2.disconnect(); | |
| } catch (e: any) { | |
| fail(`Reconnection failed: ${e.message}`); | |
| } | |
| printSummary(); | |
| } | |
| function printSummary() { | |
| console.log('\n' + '═'.repeat(50)); | |
| console.log(`\x1b[1m📋 Results: ${passed} passed, ${failed} failed\x1b[0m`); | |
| console.log('═'.repeat(50) + '\n'); | |
| process.exit(failed > 0 ? 1 : 0); | |
| } | |
| main().catch(console.error); | |