Spaces:
Running
Running
File size: 3,824 Bytes
149698e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | #!/usr/bin/env node
// 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);
|