A browser-based, multi-protocol socket testing platform. Provides a Postman-like interface for WebSocket (RFC 6455), Socket.IO, MQTT 3.1.1, and AMQP 0.9.1 connections, with real-time monitoring, performance testing, network condition simulation, and shareable configurations.
- Architecture Overview
- Prerequisites
- Installation
- Configuration
- Protocols and Features
- REST API Reference
- Real-time Control Channel
- Socket-Server (Companion Echo Server)
- Contributing
- License
┌─────────────────────────────────────────────────────────────────┐
│ Browser │
│ React 18 + Zustand + Vite │
│ (served as static assets from NestJS ServeStaticModule) │
└──────────────────────────┬──────────────────────────────────────┘
│ HTTP + Socket.IO (control channel)
┌──────────────────────────▼──────────────────────────────────────┐
│ NestJS Backend (Node.js) │
│ ┌────────────┐ ┌───────────┐ ┌───────┐ ┌──────────────────┐ │
│ │ WebSocket │ │ Socket.IO │ │ MQTT │ │ AMQP (amqplib) │ │
│ │ Proxy │ │ Proxy │ │ Proxy │ │ Proxy │ │
│ └────────────┘ └───────────┘ └───────┘ └──────────────────┘ │
│ ┌────────────┐ ┌───────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ Session │ │ Stats │ │ Performance │ │ Network │ │
│ │ Manager │ │ Aggregator│ │ Tests │ │ Simulator │ │
│ └────────────┘ └───────────┘ └──────────────┘ └───────────┘ │
│ ┌─────────────────┐ ┌─────────┐ ┌─────────────────────────┐ │
│ │ EventsGateway │ │ Log │ │ ShareModule │ │
│ │ (Socket.IO) │ │ Service │ │ (config distribution) │ │
│ └─────────────────┘ └─────────┘ └─────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────────┘
│ MQTT / AMQP / WS / Socket.IO
┌──────────────────────────▼──────────────────────────────────────┐
│ External Services │
│ (WebSocket servers, Socket.IO servers, MQTT brokers, │
│ RabbitMQ clusters, or socket-server companion) │
└─────────────────────────────────────────────────────────────────┘
The backend acts as a proxy: the browser communicates with NestJS over HTTP and a Socket.IO control channel, and NestJS manages the actual protocol connections to external targets. This sidesteps browser TLS, CORS, and header restrictions that affect direct browser-to-server connections.
- Node.js >= 20 LTS
- npm >= 10
- Docker + Docker Compose (for containerized deployment)
Two processes run in parallel: the NestJS backend (port 3000) and the Vite frontend dev server (port 5173). The Vite dev server proxies API calls and Socket.IO connections to the backend.
git clone https://github.com/abelrgr/socket-tester.git
cd socket-tester
# Install root dependencies (backend)
npm install
# Install frontend dependencies
cd client && npm install && cd ..
# Start backend in watch mode (terminal 1)
npm run dev
# Start frontend dev server (terminal 2)
npm run start:clientAccess the UI at http://localhost:5173.
The Swagger/OpenAPI UI is available at http://localhost:3000/api/docs (disabled in production).
git clone https://github.com/abelrgr/socket-tester.git
cd socket-tester
npm install
cd client && npm install && cd ..
# Build React frontend (output: ./public/) and NestJS backend (output: ./dist/)
npm run build
# Run the production server
npm startAccess the UI at http://localhost:3000. The built React assets are served by NestJS via ServeStaticModule.
To override default options at runtime, set environment variables before starting:
PORT=8080 ALLOWED_ORIGINS=https://myapp.example.com npm startThe repository includes a multi-stage Dockerfile and a docker-compose.yml that also starts optional Mosquitto (MQTT) and RabbitMQ (AMQP) brokers.
Single container
docker build -t socket-tester .
docker run -p 3000:3000 \
-e ALLOWED_ORIGINS=http://localhost:3000 \
socket-testerFull stack with Compose
docker compose up --buildServices started by Compose:
| Service | Image | Ports | Purpose |
|---|---|---|---|
app |
local build | 3000:3000 | socket-tester application |
mosquitto |
eclipse-mosquitto:2 | 1883:1883, 9001:9001 | MQTT broker (optional) |
rabbitmq |
rabbitmq:3-management-alpine | 5672:5672, 15672:15672 | RabbitMQ + management UI |
The app container has a health check that polls GET /health every 30 seconds.
To override environment variables without modifying docker-compose.yml, create a .env file in the project root:
PORT=3000
NODE_ENV=production
ALLOWED_ORIGINS=http://localhost:3000
MAX_CONNECTIONS_PER_IP=10
MAX_MESSAGE_SIZE_BYTES=1048576
RATE_LIMIT_TTL=60
RATE_LIMIT_MAX=100
LOG_LEVEL=info
SHARE_CONFIG_TTL_SECONDS=604800All configuration is supplied via environment variables. No config file is required.
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP listen port |
NODE_ENV |
development |
Set to production to disable Swagger and enforce stricter settings |
ALLOWED_ORIGINS |
http://localhost:3000,http://localhost:5173 |
Comma-separated CORS allowed origins |
MAX_CONNECTIONS_PER_IP |
10 |
Maximum concurrent proxy connections per IP |
MAX_MESSAGE_SIZE_BYTES |
1048576 |
Maximum inbound payload size (1 MB) |
RATE_LIMIT_TTL |
60 |
Rate-limit window in seconds |
RATE_LIMIT_MAX |
100 |
Maximum requests per window per IP |
LOG_LEVEL |
info |
NestJS logger verbosity (error, warn, log, debug, verbose) |
PROXY_URL_ALLOWLIST |
(empty) | Comma-separated list of allowed proxy target URLs; empty means no restriction |
SHARE_CONFIG_TTL_SECONDS |
604800 |
TTL for shareable config tokens (default: 7 days) |
Manages native RFC 6455 WebSocket connections.
- Custom HTTP upgrade headers
- Protocol negotiation (
Sec-WebSocket-Protocol) - Manual ping frame with RTT measurement
- 1 MB payload limit (configurable via
MAX_MESSAGE_SIZE_BYTES) - Text, JSON, and binary message types
Proxies Socket.io v4 client connections to remote Socket.io servers.
- Namespace and path support
- Authentication payload (
authobject injected at handshake) - Custom query parameters
- Transport selection (polling, websocket)
- Auto-reconnect with configurable attempts and delay
- Per-event subscriptions forwarded to the control channel in real time
- Origin header spoofing for CORS bypass in Node.js proxy context
Full MQTT 3.1.1 client management.
- QoS levels 0, 1, and 2
- Topic wildcards (
+,#) - Will (LWT) message configuration (topic, payload, QoS, retain)
- TLS connections with custom CA, client certificate, and key
- Initial topic subscriptions set at connection time
- Buffer-based message replay for late-joining frontend clients
- Subscribe, unsubscribe, and publish operations over the REST API
AMQP 0.9.1 connection management via amqplib.
- Exchange types:
direct,fanout,topic,headers - Queue and exchange declaration with durability and auto-delete flags
- Queue-to-exchange binding with routing key
- Consumer with ack/nack support (per delivery tag)
- Publisher to exchange or queue with content type
- TLS with custom certificates
- Heartbeat configuration and vhost support
A built-in performance module runs controlled tests against any open connection.
Latency test: sends a configurable number of ping-pong round trips and collects RTT measurements.
- Parameters:
count(1–1000),intervalMs(10–5000 ms) - Results: min, max, avg, p95, p99 RTT in milliseconds, histogram
Throughput test: sends messages at a target rate and measures actual delivery rate and latency distribution.
- Parameters:
messagesPerSecond(1–1000),durationSeconds(1–60),payloadSize(1–65536 bytes) - Results: sent count, received count, actual rate, latency distribution
Tests can be aborted mid-run. Results are archived per test ID and retrievable via REST.
Applies per-connection artificial impairments for realistic testing.
| Condition | Description |
|---|---|
latencyMs |
Fixed one-way latency added to all outbound messages |
jitterMs |
Random latency variance (±jitterMs) |
packetLossRate |
Probability of dropping each outbound message (0.0–1.0) |
throughputBytesPerSec |
Maximum outbound byte rate |
flappingIntervalMs |
Forces disconnection every N milliseconds |
Conditions are applied server-side and do not require modifying the target server.
Statistics aggregated per connection and globally:
- Total sent/received message counts and bytes
- Latency: last, avg, min, max, p95, p99 (milliseconds)
- Error count and reconnection count
- Time-series data (60-second rolling window) for charting
The frontend renders live charts via Recharts:
- Messages per second
- Latency trends (p95, p99, avg)
- Error rate (per-minute buckets)
- Message size histogram
Logging stores structured log entries per connection (max 5000 entries):
- Levels:
info,warn,error,debug - Log viewer with level filter
- Export to NDJSON format via
GET /api/logs/:connectionId/export
Generate a short token that encodes a connection configuration for sharing.
- Tokens are 12-character hex strings
- TTL: 7 days by default (configurable)
- Credentials (passwords, tokens, API keys) are stripped before encoding
- Token resolves to a URL that pre-populates the connection form
- QR code generated in the frontend for mobile scanning
All routes are prefixed with /api. Swagger documentation is available at /api/docs in development mode.
| Method | Path | Description |
|---|---|---|
POST |
/api/connections/websocket |
Create connection |
POST |
/api/connections/:id/send |
Send message |
POST |
/api/connections/:id/ping |
Send ping frame |
DELETE |
/api/connections/:id |
Close connection |
GET |
/api/connections |
List all connections |
GET |
/api/connections/:id |
Get connection details |
GET |
/api/connections/:id/stats |
Get per-connection stats |
| Method | Path | Description |
|---|---|---|
POST |
/api/connections/socketio |
Create connection |
POST |
/api/connections/socketio/:id/subscribe |
Subscribe to event |
POST |
/api/connections/socketio/:id/send |
Emit event |
| Method | Path | Description |
|---|---|---|
POST |
/api/connections/mqtt |
Create connection |
POST |
/api/connections/mqtt/:id/subscribe |
Subscribe to topic |
DELETE |
/api/connections/mqtt/:id/subscribe |
Unsubscribe from topic |
POST |
/api/connections/mqtt/:id/publish |
Publish message |
| Method | Path | Description |
|---|---|---|
POST |
/api/connections/amqp |
Create connection |
POST |
/api/connections/amqp/:id/setup |
Declare exchange/queue/binding |
POST |
/api/connections/amqp/:id/consume |
Start consuming from queue |
POST |
/api/connections/amqp/:id/ack |
Ack or nack a delivery |
POST |
/api/connections/amqp/:id/publish |
Publish to exchange or queue |
| Method | Path | Description |
|---|---|---|
GET |
/api/stats |
Global stats across all connections |
GET |
/api/stats/:connectionId |
Per-connection stats with percentiles |
| Method | Path | Description |
|---|---|---|
POST |
/api/connections/:connectionId/perf/latency |
Start latency test |
POST |
/api/connections/:connectionId/perf/throughput |
Start throughput test |
DELETE |
/api/connections/:connectionId/perf |
Abort running test |
GET |
/api/connections/:connectionId/perf/active |
Get active test |
GET |
/api/connections/:connectionId/perf/results/:testId |
Get archived test results |
| Method | Path | Description |
|---|---|---|
GET |
/api/connections/:connectionId/network |
Get current conditions |
PUT |
/api/connections/:connectionId/network |
Set conditions |
DELETE |
/api/connections/:connectionId/network |
Clear conditions |
| Method | Path | Description |
|---|---|---|
GET |
/api/logs/:connectionId |
Get logs (query param: level) |
GET |
/api/logs/:connectionId/export |
Export logs as NDJSON |
DELETE |
/api/logs/:connectionId |
Clear logs |
| Method | Path | Description |
|---|---|---|
POST |
/api/share/config |
Create shareable config token |
GET |
/api/share/:token |
Retrieve shared config |
| Method | Path | Description |
|---|---|---|
GET |
/health |
Service health check (status, uptime, timestamp) |
The frontend connects to the backend via a Socket.IO control connection. This channel carries real-time events for all proxied connections.
Clients join a room per connection: conn:{connectionId}.
Events emitted by the backend to the room:
| Event | Trigger |
|---|---|
connection:open |
Proxy connection established |
connection:close |
Proxy connection closed |
connection:error |
Error on the proxy connection |
connection:message |
Inbound message from the remote server |
mqtt:subscribed |
MQTT subscription confirmed by broker |
stats:update |
Updated stats snapshot |
The backend buffers events for a brief window after connection is created to handle race conditions where the frontend has not yet joined the room.
The repository at socket-server is a multi-protocol echo server intended for local and CI testing.
It runs four endpoints simultaneously:
| Protocol | URL | Notes |
|---|---|---|
| Native WebSocket | ws://localhost:4500 |
Echoes all messages |
| Socket.IO | http://localhost:4502 |
Event: message -> response |
| MQTT/TCP | mqtt://localhost:1883 |
Embedded Aedes broker |
| MQTT/WebSocket | ws://localhost:4500/mqtt |
Same HTTP port via path |
MQTT topic convention: publish to test/request (configurable via MQTT_REQUEST_TOPIC), receive echo on echo/{originalTopic}.
Run socket-server:
cd socket-server
npm install
npm run devContributions are welcome. Follow these steps:
- Fork the repository at https://github.com/abelrgr/socket-tester.
- Create a feature branch from
main:git checkout -b feature/your-feature-name
- Apply code style:
npm run format npm run lint
- Run the test suite before opening a PR:
npm test npm run test:e2e - Write or update unit tests for any changed logic.
- Open a pull request against
mainwith a clear description of what was changed and why.
Code style: ESLint + Prettier configured in eslint.config.mjs. No manual config changes to these files are accepted; open an issue if style rules need discussion.
Adding a new protocol proxy: implement a NestJS module following the pattern in src/websocket/ or src/mqtt/. Reuse SessionService for connection state and EventsGateway for real-time event emission. Add corresponding DTO classes and REST controller.
Adding frontend features: state lives in Zustand stores under client/src/stores/. Components follow the component/hook separation pattern. Avoid direct API calls from components; route through services/api.ts.
MIT License. See LICENSE for the full text.
Developed by Abel Gallo Ruiz — https://abelgalloruiz.me/