Skip to main content

WebSocket Extension

The commercial websocket extension gives WebSocket tests the same session model as the gRPC and Kafka extensions: a karate.channel('websocket') session with send() / pop() / collect(), plus codecs — pluggable encoders/decoders that turn a text-frame protocol such as STOMP into plain JSON your assertions can match on.

Two WebSocket surfaces

Open-source Karate has karate.webSocket() — fine for simple echo-style checks. This page is the commercial extension, which adds the session/codec model, suite-wide defaults, and message collection. They are different APIs; snippets are not interchangeable.

What you need
  • Either engine JAR — karate-agent-<version>.jar or karate-async-<version>.jar (WebSocket is in both). Download from the karate-addons releases.
  • A license with the openapi entitlement — WebSocket rides that bundle; it is not a separate product.
  • JDK 21+.

Activate the extension

karate-boot.js
// Activates WebSocket support. There is no endpoint to set globally — a WebSocket URL
// belongs to the session, so each check sets its own `url`.
boot.ext('websocket');

Optional suite-wide defaults on the same object:

var ws = boot.ext('websocket');
ws.headers = { Authorization: 'Bearer ' + token }; // applied to every session
ws.codec = new (Java.type('io.karatelabs.ext.websocket.JsonTextCodec'))(); // default codec

Write a check

checks/echo.feature
Feature: WebSocket checks

Scenario: raw text echo
* def session = karate.channel('websocket')
* session.url = 'ws://localhost:8090/echo'
* session.start()
* session.send('hello')
* match session.pop() == 'hello'

Scenario: JSON messages via the built-in codec
* def JsonTextCodec = Java.type('io.karatelabs.ext.websocket.JsonTextCodec')
* def session = karate.channel('websocket')
* session.url = 'ws://localhost:8090/echo'
* session.codec = new JsonTextCodec()
* session.start()
* session.send({ type: 'ping', seq: 1 })
* match session.pop() == { type: 'ping', seq: 1 }

Scenario: collect a stream of messages
# count says how many to wait for; collect() blocks until they arrive or the timeout passes
* def session = karate.channel('websocket')
* session.url = 'ws://localhost:8090/echo'
* session.count = 3
* session.start()
* session.send('a')
* session.send('b')
* session.send('c')
* match session.collect() == ['a', 'b', 'c']

Run it: java -jar karate-agent-<version>.jar checks — the HTML report lands in target/karate-reports/.

Configuration reference

Session keys (on karate.channel('websocket')):

KeyMeans
urlthe ws:// or wss:// endpoint — per session, always
start()open the connection
send(msg)send a message — a string, or an object when a codec encodes it
counthow many messages collect() waits for (default 1)
timeoutwait limit in milliseconds
pop()take the next message
collect()take all messages received (waits for count)
filtera JS function — keep only the messages it returns true for
codecthe wire codec — see below
headers, header(k, v)connection headers (e.g. auth)
subProtocolthe Sec-WebSocket-Protocol value to negotiate
sslboolean or { trustAll: bool }. The default is trust-all (test-friendly); set ssl = false for strict certificate validation
stop()close the connection

Codecs — speak the wire protocol, assert in JSON

A codec implements the WireCodec interface (encode/decode). Two are built in:

  • io.karatelabs.ext.websocket.RawCodec — the default; text frames pass through as strings, binary frames as byte[].
  • io.karatelabs.ext.websocket.JsonTextCodec — objects encode to JSON text and decode back.

A custom codec is how you test a protocol layered on WebSocket. The runnable kit includes a complete STOMP example — a small Java class compiled with nothing but the engine jar:

checks/stomp.feature
    * def StompCodec = Java.type('StompCodec')
* def session = karate.channel('websocket')
* session.url = 'ws://localhost:8091/stomp'
* session.codec = new StompCodec()
* session.start()
* session.send({ command: 'CONNECT', headers: { 'accept-version': '1.2', 'heart-beat': '0,0' } })
* match session.pop().command == 'CONNECTED'
* session.send({ command: 'SUBSCRIBE', headers: { id: 'sub-0', destination: '/topic/greetings' } })
* session.send({ command: 'SEND', headers: { destination: '/app/hello' }, body: { name: 'foo' } })
* def message = session.pop()
* match message.command == 'MESSAGE'
* match message.body.content == 'Hello, foo!'

STOMP frames in, plain JSON out — every assertion is an ordinary match. When a check loads a Java class by name like this, compile it against the engine jar and run with a classpath instead of -jar (in the kit, the codec lives under server/):

javac -cp karate-agent-<version>.jar -d server-classes server/StompCodec.java
java -cp "karate-agent-<version>.jar:server-classes" io.karatelabs.Main run checks
Migrating from 0.x

The 0.x session.adapter / WebsocketAdapter / io.karatelabs.websocket.JsonAdapter API is gone. The replacement is session.codec with the WireCodec interface, and the built-ins under io.karatelabs.ext.websocket.* as above. Lifecycle hooks (onStart / onStop / onMessage) moved to the separate WebsocketLifecycle mix-in.

Runnable example

A complete, CI-verified project — echo server, STOMP broker, the StompCodec source, checks and boot file — is at karate-agent-examples/websocket, with its live report. If a snippet on this page ever disagrees with that kit, the kit is the one gated by CI.

Part of Karate Agent

The openapi entitlement that unlocks WebSocket is part of Karate Agent — the AI-native engine that adds a served console, API governance and requirements traceability over the same feature files. See the enterprise overview.

See Also