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);