Karate: How to paste and run scenario for each param from array response inside scenario? - testing

I have a range of values, like taskId, extracted from DB.
* def getTasks = db.readRows('SELECT task_id from tasks t WHERE t.status = \'IN_PROGRES\'
')
* def getIds = get getTasks[*].task_id
* 'task', 'setUser'
* request
"""
[{
"task_id": " ",
"assignedUser": {
"user": "someValue"
}
}
]
"""
* method post
* status 200
* def responseResult =
"""
{
"totalCount": '#number',
"successCount": '#number',
"skippedCount": '#number',
"failedCount": '#number',
}
"""
* match response == responseResult
I need to get each value from the list response and paste in into a "task_id"
Could you please clarify this case?

If you mean trying to create a JSON array from a bunch of values that is easy.
* def response = { foo: 1, bar: 2 }
* def task_ids = []
* task_ids.push(response.foo)
* task_ids.push(response.bar)
* match task_ids == [1, 2]
When it comes to JSON manipulation, think of Karate as just like JavaScript.

Related

Wanted to try oneof conditon in JSON schema validation in Karate DSL

I've been using something like this.
* def schema =
"""
{
eligible: #string,
Reason: ##string,
enrolled: '##regex ^\\d{4}-\\d{2}-\\d{2}$',
modifiable: ##string,
Date: '##regex ^\\d{4}-\\d{2}-\\d{2}$',
status: #string,
Id: #string,
email: #string,
serviceAddressDetails: ##[] firstSchema,
DeviceIds: #[] #string
}
"""
The expected response has two possible outcomes, I want to assert that if we get either of them, the test should pass.
First,
DeviceIds : ["abcderfg"]
Second
DeviceIds : [
{
id : "abcd"
}
],
If we get either of them in the response, the test/schema should pass. How can I assert both these scenarios in the same schema?
Any help is much appreciated. Thanks!
Just run a second check. I know, it may not feel like a "single reusable schema" but take my advice, it is not worth it. Here's a solution:
* def response1 = { deviceIds: ['abcd'] }
* def firstDevice = response1.deviceIds[0]
* def isTypeOne = karate.typeOf(firstDevice) == 'string'
* def expectedDevice = isTypeOne ? '#[] #string' : '#object'
* match response1 == { deviceIds: '#(expectedDevice)' }
* def response2 = { deviceIds: { id: 'abcd' } }
* def firstDevice = response2.deviceIds[0]
* def isTypeOne = karate.typeOf(firstDevice) == 'string'
* def expectedDevice = isTypeOne ? '#[] #string' : '#object'
* match response2 == { deviceIds: '#(expectedDevice)' }
Other ideas:
https://stackoverflow.com/a/62567262/143475

how to manage variable inside of json value string?

I have variable cardholder in my karate-config file.
I assigned it to the new entrID variable.
The main thing that i am building JSON as a String..
* def entrID = cardholder
* def requestContactHistoryAdd =
"""
{
"RequestBody": "{ \"ENTR_ID\" : \"entrID\", \"BHVR_ID\" : \"VRU\", }"
}
"""
Now how can i provide it inside of my json RequestBody?
EDIT: since you seem to have a very badly designed API where the JSON has an embedded string (which looks like JSON).
Please note I am using a string type below: https://github.com/intuit/karate#type-conversion
You can do this:
* def entrID = 'foo'
* string temp = { "ENTR_ID" : "#(entrID)", "BHVR_ID" : "VRU" }
# note that you could have done this:
# def temp = '{ "ENTR_ID" : "' + entrID + '", "BHVR_ID" : "VRU" }'
* def body = { RequestBody: '#(temp)' }
* print body
Which gives you:
08:17:25.671 [main] INFO com.intuit.karate - [print] {
"RequestBody": "{\"ENTR_ID\":\"foo\",\"BHVR_ID\":\"VRU\"}"
}
i solved it also like this
* def entrID = someValueFromSomeWhere
* def bodyValue = "{ \"ENTR_ID\":\"" + entrID + "\", \"BHVR_ID\" : \"VRU\" }"
* def requestContactHistoryAdd =
"""
{
"RequestBody": "#(bodyValue)"
}
"""
we can also do this way
* def bodyValue = "{ \"ENTR_ID\":\"" + someValueFromSomeWhere + "\", \"BHVR_ID\" : \"VRU\" }"
* def requestContactHistoryAdd =
"""
{
"RequestBody": "#(bodyValue)"
}
"""

Karate - Exception raises for invalid jsonpath

I have a Json response like below. The difference here is my Json body has a number as the parent node.
def response =
"""
{
"22388043":[
{
"firstName":"Romin",
"lastName":"Irani",
"phoneNumber":"408-1234567",
"emailAddress":"romin.k.irani#gmail.com"
}
]
}
"""
I want to return the mobileNumber attribute value from the response body. In this scenario I don't have that attribute in my response. So here I want to get a null value.
So when I use * def mobile = $.22388043[0].mobileNumber, I'm getting below error.
No results for path: $['22388043'][0]['mobileNumber']
Please advise on this.
Karate does give you a way to get the values of JSON keys.
Hopefully this example answers all your other questions as well:
* def response =
"""
{
"22388043":[
{
"firstName":"Romin",
"lastName":"Irani",
"phoneNumber":"408-1234567",
"emailAddress":"romin.k.irani#gmail.com"
}
]
}
"""
* def id = karate.keysOf(response)[0]
* match id == '22388043'
* def person = response[id][0]
* match person contains { firstName: 'Romin', lastName: 'Irani' }
* match person.mobileNumber == '#notpresent'

Using karate.forEach and karate.set to extract index of value from json array

I have the below json:
{
"id": [
"1A",
"2B"
],
"name": [
"rs",
"mk"
]
}
I want to extract the id value when name is 'rs' or 'mk'. There will be no duplication of name values and the size of id and name keys will always match.
So i have created the following scenario where:
- I iterate through the name array using forEach.
- Find if the value of name matches rs or mk and if it does, retrieve the index.
- Then use this index to find the retrieve the value from id key.
When I run this, the name_rs_idx and name_mk_idx are not being set and are blank.
Scenario: Using forEach and karate.set
* def vals = { id: ['1A', '2B'], name: ['rs', 'mk'] }
* def name_rs_idx = ''
* def rsFun =
"""
function(x, i) {
if(x == 'rs') {
karate.set(name_rs_idx, i);
}
}
"""
* karate.forEach(vals.name, rsFun)
* print 'RS Index - ' + name_rs_idx
* def name_rs_id = vals.id[name_rs_idx]
* print 'RS id -' + name_rs_id
* def name_mk_idx = ''
* def mkFun =
"""
function(x, i) {
if(x == 'mk') {
karate.set(name_mk_idx, i);
}
}
"""
* karate.forEach(vals.name, mkFun)
* print 'MK Index - ' + name_mk_idx
* def name_mk_id = vals.id[name_mk_idx]
* print 'MK id -' + name_mk_id
Maybe i am not using the forEach function correctly or logic is incorrect.
I think you are over-complicating things :) Here is my solution, take time to read and understand it, it will improve your Karate fundamentals ! To simplify things, we first combine the data into an array of { name: '', id: '' } pairs. Then things become much easier.
* def vals = { id: ['1A', '2B'], name: ['rs', 'mk'] }
* def fun = function(x, i){ return { name: vals.name[i], id: vals.id[i] } }
* def pairs = karate.map(vals.name, fun)
* def fun = function(x){ return x.name == 'rs' || x.name == 'mk' }
* def filtered = karate.filter(pairs, fun)

Check if an array contains a specific object only once

Given the following input:
* def response = [{ a: 1 }, { a: 2 }]
* def item = { a: 1 }
How to check that item is present only once in response?
There's no direct way to do this, since less common. You can do this in 2 steps by filtering the list and then using contains only.
* def response = [{ a: 1 }, { a: 2 }]
* def item = { a: 1 }
* match response contains item
* def fun = function(x){ return karate.match(x, item).pass }
* def filt = karate.filter(response, fun)
* match filt contains only item