This question already has an answer here:
Asserting and using conditions for an array response in Karate
(1 answer)
Closed 2 years ago.
I am having troubles with XML matching, which appears to be working a bit differently from JSON.
I found this code snippet
* def xml = <foo><bar>baz</bar></foo>
* set xml/foo/bar = <hello>world</hello>
* match xml == <foo><bar><hello>world</hello></bar></foo>
But with this, I cannot specify that I'm using a template, and that <hello>world</hello> may be present more than once.
Scenario XML 1 is failing, while the others are working.
Scenario: Scenario XML 1
* def response = <response><foo><bar><msg name="Hello"/><msg name="World"/></bar><bar><msg name="Hello"/><msg name="World"/></bar></foo></response>
* def bar = <bar><msg name="Hello"/><msg name="World"/></bar>
* def foo = <response><foo>#[](bar)</foo></response>
* print foo
* print response
* match response == foo
Scenario: Scenario XML 2
* def response = <response><foo><bar><msg name="Hello"/><msg name="World"/></bar></foo></response>
* def bar = <bar><msg name="Hello"/><msg name="World"/></bar>
* def foo = <response><foo>#(bar)</foo></response>
* print foo
* print response
* match response == foo
Scenario: Scenario JSON 1
* def response = {"response": {"foo": [{"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}, {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}]}}
* def bar = {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}
* def foo = {"response": {"foo": #[](bar)}}
* print foo
* print response
* match response == foo
Scenario: Scenario JSON 2
* def response = {"response": {"foo": {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}}}
* def bar = {"bar": [{"msg": "Hello World"},{"msg": "Hello World"}]}
* def foo = {"response": {"foo": #(bar)}}
* print foo
* print response
* match response == foo
How can I have Scenario XML 1 working?
I admit this can be considered a gap. The fact that XML repeated elements are so different from JSON doesn't help. The best I could do is this:
* def response = <foo><bar><msg name="Hello"/><msg name="World"/></bar><bar><msg name="Hello"/><msg name="World"/></bar></foo>
* def bar = <bar><msg name="Hello"/><msg name="World"/></bar>
* def foo = <foo>#ignore</foo>
* match response == foo
* match /foo/bar/msg[1]/#name == ['Hello', 'Hello']
* def names = $response/foo/bar/msg[1]/#name
* match each names == 'Hello'
Feel free to submit a feature request and suggest based on your experience with JSON what the ideal syntax should look like.
EDIT: thought about it a little and realized because of how Karate converts XML into JSON-like data internally, you have this option.
* json response = <response><foo><bar><msg name="Hello"/><msg name="World"/></bar><bar><msg name="Hello"/><msg name="World"/></bar></foo></response>
* json bar = <bar><msg name="Hello"/><msg name="World"/></bar>
* match each response.response.foo.bar == bar.bar
* match response == { response: { foo: { bar: '#[] bar.bar' } } }
I know it may be a little hard to understand, but will work :) I was looking at the code right now, and because of how involved the JSON matching is - it is unlikely to get re-factored to support XML repeated elements.
EDIT2: actually we made a fix now so this should be possible also:
* match response == <response><foo><bar>#[] bar.bar</bar></foo></response>
https://github.com/intuit/karate/issues/653
Related
For some reason a variable with a / character get converted to a \/, how do I prevent this?
I start a echo server that listens on localhost:3000 by running npx http-echo-server
I execute the following:
code:
* def CHALLENGE_USER = '/abc/user'
* def loginJson = { user: '#(CHALLENGE_USER)' , name: 'Some Name'}
* print loginJson
* def TEST_URL = 'http://localhost:3000'
Given url TEST_URL+'/session/loginresponse'
And header Content-Type = 'application/json'
And request loginResponseJson
And method put
Then status 200
It prints { "user": "/abc/user", "name": "Some Name" } like I expect.
The http server logs show "--> {"user":"/schemes/ATT_5_55/CH_1","name":"Some Name"}"
Karate shows the result of the echo {"user":"\/abc\/user","name":"Some Name"}
I have tried:
def CHALLENGE_USER = '/abc/user'
def CHALLENGE_USER = "/abc/user"
def CHALLENGE_USER = '/abc/user'
def CHALLENGE_USER = '//abc//user'
also setting the variable after the fact does not work:
* def loginJson = { name: 'Some Name'}
* loginJson.user = CHALLENGE_USER
Yes this is legal as per the JSON spec: JSON: why are forward slashes escaped?
And the Java libraries we use does that.
Does your server have a problem ? If so - then you have a bug that Karate surfaced.
And if you really want to have full control over the request, please use text but IMO it may be a waste of time: https://stackoverflow.com/a/68344856/143475
A nasty workaround, please forgive me Peter Thomas.
You can convert the json to a string and then remove the \ characters.
I only have one use case for this thank goodness.
* def CHALLENGE_USER = '/abc/user'
* def loginJson = { user: '#(CHALLENGE_USER)' , name: 'Some Name'}
* string json = loginJson
* def loginJsonText = json.replaceAll("\\", "")
* print loginJson
* def TEST_URL = 'http://localhost:3000'
Given url TEST_URL+'/session/loginresponse'
And header Content-Type = 'application/json'
And request loginJsonText
And method put
Then status 200
I am using karate to test websocket, this worked:
Background:
* def token = TOKEN
* def handler = function(msg){ return msg.startsWith('a[')}
* def socket = karate.webSocket(WS_HOST + 'socket/761/f4t0so3p/websocket', handler)
Scenario: Demo Real
checking dcube-dev
* socket.send('{"type":"1ffe4b5d___AC_GET_MY_AVAILABLE_TASKS___N","token": "myhardcodedtoken","content":{"msg":null,"counter_api_enabled":false}}')
You can see here, I am hard coding the token inside the request body, not good, so I tried to move it out and use environment token instead as below:
Background:
* def token = TOKEN
* def handler = function(msg){ return msg.startsWith('a[')}
* def socket = karate.webSocket(WS_HOST + 'socket/761/f4t0so3p/websocket', handler)
Scenario: Demo Real
checking dcube-dev
* def body = {"type": "1ffe4b5d___AC_GET_MY_AVAILABLE_TASKS___N", "token": '#(token)', "content": {"msg":null,"counter_api_enabled":false} }
* print "Body:", body
* socket.send( '#(body)')
But this is always wrong, seemed the msg never sent out . Can anyone tell me how to resolve this issue?
Thanks
Actually I think you need to make this one change:
* socket.send(body)
Think of the round brackets as being JS - not standard Karate expressions: https://github.com/intuit/karate#enclosed-javascript
Also note, for strings (instead of JSON) you can use replace: https://github.com/intuit/karate#replace
* def text = 'hello <foo> world'
* replace text.foo = 'bar'
* match text == 'hello bar world'
Is there a variable like response for request in karate. I tried to look at the github issues and found the below example, but this does not seem to work for me.
* def temp = (karate.lastRequest)
* print '==============>' +(temp.body)
Its karate.prevRequest
* def temp = karate.prevRequest
* def requestMethod = temp.method
* def requestBody = temp.body
please find more example here
so i created/def a object with
And def memeberIDs = $.users[*].id
And print memeberIDs
and i get a list like so
[
"eOVbGI0XSiabeiLZtB-ROQ",
"iK-Fz_NRSbSt-7AdodjDrA",
"dS2czwVFRZmy8a6oxO7JKw",
"yxH3bmF3THuCgLWLGh7eeQ",
"bqD41MgvSlC94EQH-r1H-Q",
"MrQihYjiR_WmWHA2-Y2cZQ",
"9N7uZdT_RTmePdJ5DMZ7sg",
"qo76PFcSS3-61FwgKCz6Ng",
"tjo3sdj3RMe8RoSBR3U_Ng",
"OuFxQR7KThCBPv2wHtKzhg",
"YmQKkv69Ts2yQ32LIjJN-g",
"A7kRauysQsCtle9G-bMV0g",
"zinHreHLTluUWdFzavssEA",
"UhZt8B_JSVaPBAJdIcPBsw",
"MtT_yR1iQqmDWMWlxXsWmQ",
"y2c9aK17Qouune_c_ZGlYQ",
"xGHOe7wxQru-NruIBPHL7Q",
"sTe8TADNTQ6nmg4UJeXiOQ",
"qC2FJUJeQJmOJPKkE_iehQ",
"4V0a93O8TCK-jjDujVVH-A",
"sk1tDsUmRYWUjyCMWFOqDw",
"ChmxrwHwTcS9I3u-RveBQA",
"ZL3uSx1oQbOc2c5qrFYRew",
"qjxFk-x9SVe-8XkzMbLrBw",
"7uIQVAXuSVe4tcWdv6S7MQ",
"V4mdzUj2SpyVpKlJfSdOEg",
"dU61-sNoQu6Q87hItkGcHw",
"enhFrWkfTDuaFqQCwPetAw",
"Txte_5FtTiaSfsc5k7-HmA",
"7tkMxEglS5qgx6bKObByKg",
"-uv0OuoNRlinnI4HkGsSSg",
"tLxWhEqSSiOcqyGJKsG6tQ",
"8tqnoZ1DQrq0DGzU_4OVmg",
"E9Rjy2euRbaKeaP1INxvGA",
]
My next request looks like
Given url 'https://api.someurl.com/v2/users//meetings?type=all&page_size=30&page_number=1'
Take some time and study this example. And read this part of the documentation: https://github.com/intuit/karate#dynamic-scenario-outline
Background:
* def list = ['foo', 'bar']
* def data = karate.mapWithKey(list, 'name')
Scenario Outline:
* url 'http://httpbin.org'
* path 'anything'
* param test = name
* method get
Examples:
| data |
This example will make 2 requests,
1) GET http://httpbin.org/anything?test=foo
2) GET http://httpbin.org/anything?test=bar
How to add an element to an array in karate?
I have a string array(not json array) from response and add a string element to it for next request.
I tried a lot with JS functions but with no luck.
Any help is appreciated.
Scenario:123
* def roles = ["role1"]
* def newrole = "role2"
* def addrolefn =
"""
function(role,roles1) {
var fullrole = [];
for (var i=0; i<roles1.length;i++) {
fullrole = fullrole.push(role);
}
return fullrole;
}
"""
* def fullroles = call addrolefn (newrole,roles)
* print fullroles
Please refer to the set keyword.
* def roles = ["role1"]
* def newrole = "role2"
* set roles[1] = newrole
* print karate.pretty(roles)
Result:
06:26:35.324 [main] INFO com.intuit.karate - [print] [
"role1",
"role2"
]
edit: actually I've just raised an enhancement request to add an append keyword to Karate. Meanwhile, this should answer all your questions and act as a workaround.
* def roles = null
# javascript that assigns an empty array if null
* json roles = (roles || [])
* def newrole = "role2"
# javascript to append to an array. the def void is useless
* def void = (roles.add(newrole))
* print karate.pretty(roles)
edit: type cast to json, and using java list api add method