To add support for websocket
4M01 opened this issue · 6 comments
Karate supports HTTP protocol, it would be great if it can support Websocket.
closing due to inactivity
@4M01 and others - reopening this, and we've made some progress adding websocket helpers to the code. can you provide some examples of test scenarios / requirements
@ptrthomas I will try to provide some example for this by Sunday. Hope that is fine
commit message was not descriptive enough, so a few notes:
- doc pending
- not sure if websocket should be first-class keyword and if clients should be auto-closed at end of scenario
- two new methods on karate JS API,
listen()
andsignal()
- the combination of JS and karate works very nicely for callbacks !
EDIT: for those looking for the current example (syntax will change slightly): https://github.com/intuit/karate/blob/cukexit/karate-demo/src/test/java/demo/websocket/websocket.feature
I think the new "native" support for an "await" has turned out really well.
the CDC example which includes a JMS message listener has been revamped in prev commit.
Feature: payment service
Background:
* def QueueConsumer = Java.type('mock.contract.QueueConsumer')
* def queue = new QueueConsumer(queueName)
* def handler = function(msg){ karate.signal(msg) }
* eval queue.listen(handler)
* url paymentServiceUrl + '/payments'
Scenario: create, get, update, list and delete payments
Given request { amount: 5.67, description: 'test one' }
When method post
Then status 200
And match response == { id: '#number', amount: 5.67, description: 'test one' }
And def id = response.id
* json shipment = karate.listen(5000)
* print '### received:', shipment
* match shipment == { paymentId: '#(id)', status: 'shipped' }
and something I just found out is that function(o){ }
gets converted to java.util.function.Consumer<Object>
via the magic of Nashorn / JVM JS interop !
which leads us to the code behind the queue.listen(handler)
that you see in the Background
above:
public void listen(java.util.function.Consumer<String> handler) {
setMessageListener(message -> {
TextMessage tm = (TextMessage) message;
try {
handler.accept(tm.getText());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
and yes, instead of String
you should be able to use more complex types as the function argument, and the usual rules of JS conversion (e.g. Map
--> JSON) apply
the improved API is designed so the karate.listen(timeout)
call will return the value passed to karate.signal(value)
which makes things pretty elegant if I may say so
which gives us this beauty that can send as well as receive from a websocket connection while ignoring messages we are not interested in:
* def handler = function(msg){ if (msg.startsWith('hello')) karate.signal(msg) }
* def socket = karate.webSocket(demoBaseUrl + '/websocket', handler)
* eval socket.send('Billie')
* def result = karate.listen(5000)
* match result == 'hello Billie !'
0.9.0 released