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
listenandsignalpatterns 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
listento 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