websocket-tester

Test WebSocket connections, message flows, and real-time features. Connect to endpoints, send/receive messages, test reconnection logic, measure latency, validate message schemas, and load test concurrent connections.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "websocket-tester" with this command: npx skills add charlie-morrison/websocket-tester

WebSocket Tester

Test WebSocket endpoints without a browser. Connect, send messages, validate responses, test reconnection, measure latency, and load test concurrent connections — for chat, real-time updates, game servers, IoT, and streaming APIs.

Use when: "test websocket", "websocket not connecting", "debug real-time", "ws connection issues", "websocket load test", "test socket.io", "chat server testing", or when building/debugging real-time features.

Commands

1. connect — Test WebSocket Connection

# Basic connection test with wscat (Node.js)
npx wscat -c "wss://$HOST/ws" 2>&1 &
WSCAT_PID=$!
sleep 3
kill $WSCAT_PID 2>/dev/null

# Or with websocat (Rust)
echo "test" | websocat "wss://$HOST/ws" 2>&1

# Or with Python
python3 -c "
import asyncio, websockets, time, json

async def test_connection():
    url = 'wss://$HOST/ws'
    start = time.time()
    try:
        async with websockets.connect(url, close_timeout=5) as ws:
            latency = (time.time() - start) * 1000
            print(f'✅ Connected in {latency:.0f}ms')
            print(f'Protocol: {ws.subprotocol or \"none\"}')
            print(f'Headers: {dict(ws.response_headers)}')

            # Test ping/pong
            pong = await ws.ping()
            await pong
            print('✅ Ping/Pong working')

            # Listen for initial messages (server hello, auth challenge)
            try:
                msg = await asyncio.wait_for(ws.recv(), timeout=3)
                print(f'Server sent: {msg[:200]}')
            except asyncio.TimeoutError:
                print('No initial message from server (normal for some protocols)')

    except websockets.exceptions.InvalidStatusCode as e:
        print(f'❌ Connection rejected: HTTP {e.status_code}')
    except ConnectionRefusedError:
        print(f'❌ Connection refused — server not listening on WebSocket endpoint')
    except Exception as e:
        print(f'❌ Error: {e}')

asyncio.run(test_connection())
" 2>&1

2. test-messages — Send and Validate Messages

import asyncio, websockets, json, time

async def test_messages():
    async with websockets.connect('wss://$HOST/ws') as ws:
        # Test 1: Send and receive
        test_msg = json.dumps({'type': 'ping', 'data': 'hello'})
        await ws.send(test_msg)
        print(f'→ Sent: {test_msg}')

        response = await asyncio.wait_for(ws.recv(), timeout=5)
        print(f'← Received: {response[:200]}')

        # Validate response schema
        try:
            data = json.loads(response)
            assert 'type' in data, 'Missing type field'
            print('✅ Response is valid JSON with type field')
        except json.JSONDecodeError:
            print('⚠️ Response is not JSON — might be binary or plain text')
        except AssertionError as e:
            print(f'❌ Schema validation: {e}')

        # Test 2: Measure round-trip latency
        latencies = []
        for i in range(10):
            start = time.time()
            await ws.send(json.dumps({'type': 'ping', 'seq': i}))
            await asyncio.wait_for(ws.recv(), timeout=5)
            latencies.append((time.time() - start) * 1000)

        avg = sum(latencies) / len(latencies)
        p95 = sorted(latencies)[int(len(latencies) * 0.95)]
        print(f'\\nLatency (10 round-trips): avg={avg:.1f}ms, p95={p95:.1f}ms')

asyncio.run(test_messages())

3. reconnect — Test Reconnection Logic

async def test_reconnection():
    """Simulate connection drops and verify client reconnects"""

    # Test 1: Server closes connection
    async with websockets.connect('wss://$HOST/ws') as ws:
        print('Connected. Sending close frame...')
        await ws.close(1001, 'Testing reconnection')
        print(f'Close code: {ws.close_code}, reason: {ws.close_reason}')

    # Test 2: Reconnect and verify state
    async with websockets.connect('wss://$HOST/ws') as ws:
        print('✅ Reconnected successfully')
        # Check if server restored session state
        await ws.send(json.dumps({'type': 'get_state'}))
        state = await asyncio.wait_for(ws.recv(), timeout=5)
        print(f'State after reconnect: {state[:200]}')

    # Test 3: Connection with auth token
    async with websockets.connect(
        'wss://$HOST/ws',
        extra_headers={'Authorization': f'Bearer {TOKEN}'}
    ) as ws:
        print('✅ Authenticated connection')

4. load-test — Concurrent Connection Load Test

import asyncio, websockets, time, statistics

async def load_test(url, num_connections, duration_sec, messages_per_sec):
    """Load test WebSocket endpoint"""
    results = {
        'connected': 0,
        'failed': 0,
        'messages_sent': 0,
        'messages_received': 0,
        'latencies': [],
        'errors': [],
    }

    async def client(client_id):
        try:
            async with websockets.connect(url, close_timeout=5) as ws:
                results['connected'] += 1
                end_time = time.time() + duration_sec

                while time.time() < end_time:
                    start = time.time()
                    await ws.send(json.dumps({
                        'type': 'message',
                        'client': client_id,
                        'ts': start
                    }))
                    results['messages_sent'] += 1

                    try:
                        await asyncio.wait_for(ws.recv(), timeout=5)
                        results['messages_received'] += 1
                        results['latencies'].append((time.time() - start) * 1000)
                    except asyncio.TimeoutError:
                        results['errors'].append(f'Client {client_id}: timeout')

                    await asyncio.sleep(1.0 / messages_per_sec)

        except Exception as e:
            results['failed'] += 1
            results['errors'].append(f'Client {client_id}: {e}')

    tasks = [client(i) for i in range(num_connections)]
    await asyncio.gather(*tasks)

    # Report
    lats = results['latencies']
    print(f'\\n=== WebSocket Load Test Results ===')
    print(f'Connections: {results["connected"]}/{num_connections} ({results["failed"]} failed)')
    print(f'Messages: {results["messages_sent"]} sent, {results["messages_received"]} received')
    if lats:
        print(f'Latency: avg={statistics.mean(lats):.1f}ms, '
              f'p50={statistics.median(lats):.1f}ms, '
              f'p95={sorted(lats)[int(len(lats)*0.95)]:.1f}ms, '
              f'p99={sorted(lats)[int(len(lats)*0.99)]:.1f}ms')
    if results['errors']:
        print(f'Errors ({len(results["errors"])}):')
        for e in results['errors'][:5]:
            print(f'  - {e}')

# Run: 100 concurrent connections, 60s, 1 msg/sec each
asyncio.run(load_test('wss://$HOST/ws', 100, 60, 1))

5. diagnose — Common WebSocket Issues

Connection failures:

  • HTTP 101 upgrade rejected → check server supports WebSocket
  • 403 on connect → CORS or auth issue
  • Connection timeout → firewall blocking WS, or wrong port
  • SSL/TLS error → certificate issue on wss://

Message issues:

  • Messages not received → check subscription/room join logic
  • Duplicate messages → missing deduplication, reconnect replay
  • Out-of-order → add sequence numbers, reorder buffer
  • Large messages rejected → check server max frame size

Performance:

  • High latency → check server-side processing time
  • Connection drops → heartbeat/ping interval too long
  • Memory growth → connection leak (not closing on client disconnect)

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Peon Ping for Openclaw

Install and configure PeonPing with an opinionated default (Orc Peon voice) so alerts work immediately with minimal user friction. Use when the user asks for...

Registry SourceRecently Updated
General

Openclaw Skill Publish

Polymarket prediction markets: analytics, trading, hot markets, price movements, top traders, and market search. Powered by prob.trade.

Registry SourceRecently Updated
General

post-to-xhs

小红书内容发布与管理助手。当用户要求登录、发小红书、搜索小红书、评论点赞收藏等任何小红书相关操作时使用。

Registry SourceRecently Updated
General

Chat History Analyzer

Extracts and analyzes Cursor IDE chat history to identify key discoveries, obstacles, and solutions, saving findings to the journal.

Registry SourceRecently Updated