ADVANCED
WebSocket Testing
Test real-time WebSocket connections with built-in support for text and binary messages, custom handlers, and seamless async event integration.
On this page:
- karate.webSocket() - Connect to WebSocket endpoints
- Message handlers - Filter incoming messages with custom functions
- Options - Configure authentication, sub-protocols, and payload limits
- Binary messages - Handle binary payloads with
karate.webSocketBinary() - listen pattern - Async event-driven testing
Basic WebSocket Connection
Connect to a WebSocket endpoint and exchange messages using karate.webSocket():
Feature: Simple WebSocket
Scenario: Send and receive text message
* def socket = karate.webSocket('wss://echo.websocket.events')
* 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.
Method Signatures
Three forms are available:
| Signature | Description |
|---|---|
karate.webSocket(url) | Connect with defaults, returns first message |
karate.webSocket(url, handler) | Connect with custom message handler |
karate.webSocket(url, handler, options) | Connect with handler and configuration |
Message Handlers
Filter incoming messages with custom handler functions. The handler receives each message and returns true to capture it (completing the listen wait) or false to ignore and keep waiting:
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(wsUrl, handler)
* socket.send('Billie')
* listen 5000
* match listenResult == 'hello Billie !'
Use handlers to filter out heartbeats, system messages, or irrelevant events. The handler is called for each incoming message until it returns true.
WebSocket Options
Configure authentication, sub-protocols, and payload limits with the options parameter:
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
* match listenResult contains 'channel'
Available Options
| Option | Description | Default |
|---|---|---|
subProtocol | Protocol negotiation string expected by server | none |
headers | Authentication tokens, API keys, or custom headers | none |
maxPayloadSize | Maximum message size in bytes | 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')
* bytes payload = read('classpath:test-data.bin')
* binarySocket.send(payload)
* listen 5000
* bytes received = listenResult
* match received.length > 0
The karate.webSocketBinary() method has the same signatures as karate.webSocket() but handles byte arrays instead of strings. Use it for image uploads, file transfers, or any non-text protocol.
Listen and Signal Pattern
WebSocket integrates with Karate's async listen keyword for event-driven testing. The listen keyword pauses execution until the handler returns true or timeout expires:
Feature: Async WebSocket workflow
Background:
* def wsUrl = 'ws://localhost:8080/events'
Scenario: Trigger action and wait for event
* 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' }
If timeout occurs without the handler returning true, listenResult is null.
WebSocket connections auto-close at scenario end. For long-running scenarios, close explicitly with socket.close() to free resources.
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 'joined'
# Send message
* socket.send('{ "action": "message", "text": "Hello everyone" }')
* listen 3000
* match listenResult contains 'Hello everyone'
# Leave room
* socket.send('{ "action": "leave" }')
* listen 3000
* match listenResult contains 'left'
Event Correlation
Correlate WebSocket events with HTTP operations by collecting events in a handler:
Feature: Order processing pipeline
Scenario: Track order through WebSocket events
* def orderId = java.util.UUID.randomUUID() + ''
* def events = []
* def handler =
"""
function(msg) {
var event = JSON.parse(msg);
if (event.orderId === orderId) {
events.push(event);
return event.status === 'shipped';
}
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]'
* match events[2].status == 'shipped'
Next Steps
- Polling and Async Operations - Master async patterns
- Karate Object - Explore karate methods
- Debugging - Troubleshoot WebSocket issues