ADVANCED
WebSocket Testing
Test real-time WebSocket connections with built-in support for text and binary messages, custom handlers, and seamless async event integration.
Why WebSocket Testing?
- Real-time validation: Test live bidirectional communication between client and server
- Built-in async handling: Integrated
listen
andsignal
patterns eliminate custom polling logic - Flexible filtering: Handler functions let you ignore noise and capture specific message patterns
- Zero configuration: Works out of the box with automatic connection cleanup
Basic WebSocket Connection
Connect to a WebSocket endpoint and exchange messages:
Feature: Simple WebSocket
Scenario: Send and receive text message
* def socket = karate.webSocket('ws://echo.websocket.org')
* socket.send('Hello WebSocket')
* listen 5000
* match listenResult == 'Hello WebSocket'
Without a handler function, listen
returns the first message received. The connection auto-closes when the scenario ends.
Message Handlers
Filter incoming messages with custom handler functions that return true
to capture or false
to ignore:
Feature: Filtered WebSocket messages
Scenario: Wait for specific message type
# Handler captures only messages starting with 'hello'
* def handler = function(msg) { return msg.startsWith('hello') }
* def socket = karate.webSocket('ws://localhost:8080/chat', handler)
# Send message
* socket.send('Billie')
# Wait for matching message (ignores others)
* listen 5000
* match listenResult == 'hello Billie !'
The handler function receives each incoming message. Return true
to signal and populate listenResult
, or false
to keep waiting. Use handlers to filter out heartbeats, system messages, or irrelevant events.
WebSocket Options
Configure authentication, sub-protocols, and payload limits:
Feature: Authenticated WebSocket
Scenario: Connect with JWT authentication
* def token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
* def options =
{
subProtocol: 'chat',
headers: { Authorization: 'Bearer ' + token },
maxPayloadSize: 8388608
}
* def socket = karate.webSocket('wss://api.example.com/socket', null, options)
* socket.send({ action: 'subscribe', channel: 'updates' })
* listen 5000
* def message = listenResult
* match message.channel == 'updates'
Available options:
subProtocol
: Protocol negotiation string expected by serverheaders
: Authentication tokens, API keys, or custom headersmaxPayloadSize
: Maximum message size in bytes (default: 4194304 / 4 MB)
Binary Messages
Handle binary WebSocket payloads with karate.webSocketBinary()
:
Feature: Binary WebSocket
Scenario: Send and receive binary data
* def binarySocket = karate.webSocketBinary('ws://localhost:8080/binary')
# Send byte array
* bytes payload = read('test-data.bin')
* binarySocket.send(payload)
# Receive binary response
* listen 5000
* bytes response = listenResult
* match response.length > 0
Use karate.webSocketBinary()
for image uploads, file transfers, or any non-text protocol. The API signature matches karate.webSocket()
but handles byte arrays instead of strings.
Listen and Signal Pattern
WebSocket integrates with Karate's async listen
keyword for event-driven testing:
Feature: Async WebSocket workflow
Background:
* def wsUrl = 'ws://localhost:8080/events'
Scenario: Trigger action and wait for event
# Set up handler to capture completion events
* def handler =
"""
function(msg) {
var data = JSON.parse(msg);
return data.type === 'completed';
}
"""
* def socket = karate.webSocket(wsUrl, handler)
# Trigger async operation via HTTP
Given url baseUrl + '/process'
And request { orderId: 'ORD-123', priority: 'high' }
When method post
Then status 202
# Wait for WebSocket notification (max 10 seconds)
* listen 10000
* def event = JSON.parse(listenResult)
* match event == { type: 'completed', orderId: 'ORD-123', status: 'success' }
The listen
keyword pauses execution until the handler returns true
or timeout expires. If timeout occurs, listenResult
is null
.
WebSocket connections auto-close at scenario end. No manual cleanup required. For long-running scenarios, close explicitly with socket.close()
to free resources.
Real-Time Testing Patterns
Multi-Message Workflows
Test sequences of WebSocket interactions:
Feature: Chat workflow
Scenario: Join room and exchange messages
* def socket = karate.webSocket('ws://localhost:8080/chat')
# Join room
* socket.send({ action: 'join', room: 'lobby' })
* listen 3000
* match listenResult contains { type: 'joined', room: 'lobby' }
# Send message
* socket.send({ action: 'message', text: 'Hello everyone' })
* listen 3000
* match listenResult contains { type: 'message', text: 'Hello everyone' }
# Leave room
* socket.send({ action: 'leave' })
* listen 3000
* match listenResult.type == 'left'
Event Correlation
Correlate WebSocket events with HTTP operations:
Feature: Order processing pipeline
Scenario: Track order through WebSocket events
* def orderId = java.util.UUID.randomUUID() + ''
* def events = []
# Handler collects all events for this order
* def handler =
"""
function(msg) {
var event = JSON.parse(msg);
if (event.orderId === orderId) {
events.push(event);
return event.status === 'shipped'; # Stop at final status
}
return false;
}
"""
* def socket = karate.webSocket('ws://localhost:8080/orders', handler)
# Place order via HTTP
Given url baseUrl + '/orders'
And request { id: '#(orderId)', items: ['item1', 'item2'] }
When method post
Then status 201
# Wait for final event
* listen 15000
* match events == '#[3]' # Expect: created, processing, shipped
* match events[*].orderId == [orderId, orderId, orderId]
* match events[2].status == 'shipped'
When to Use WebSockets
Use WebSocket testing when:
- Testing real-time features: notifications, live dashboards, chat applications
- Validating bidirectional communication patterns
- Testing event-driven architectures with WebSocket transports
- Verifying server-sent events arrive correctly and in order
Prefer HTTP when:
- Testing request-response APIs without real-time requirements
- Communication is one-directional (client → server only)
- Stateless operations that do not require persistent connections
Performance considerations:
- WebSocket connections are lightweight but maintain server resources
- Use realistic timeouts in
listen
to avoid hanging tests - Close connections explicitly in long-running scenarios
- Test connection recovery and reconnection logic separately
Next Steps
- Master async patterns: Polling and Async Operations
- Integrate with Java: Java API
- Explore karate methods: Karate Object
- Handle conditional flows: Conditional Logic
- Debug WebSocket issues: Debugging