karate: finding index of the particular element value from API response - karate

my code for finding index as below
* def list = nestActual #this is API response value which is given at the end
* def searchFor = { category_name: 'books3'}
* def foundAt = []
* def fun = function(x, i){ if (karate.match(x, searchFor).pass) foundAt.add(i) }
* eval karate.forEach(list, fun)
* print "==========foundAt=======" +foundAt
i have tried the above code for finding index where im getting foundAt index as null.
Below is my response where i want to find index of "category_name":"books3"
[
{
"category_id":1, "parent_cat_id":0, "category_name":"books", "slug_name":"books_1", "popular":true,
}, {
"category_id":2, "parent_cat_id":1, "category_name":"books2", "slug_name":"books_2", "popular":false,
}, {
"category_id":3, "parent_cat_id":1, "category_name":"books3", "slug_name":"books3_2", "popular":false,
}, {
"category_id":4, "parent_cat_id":3, "category_name":"mp3", "slug_name":"mp_3", "popular":false, }, {
"category_id":5, "parent_cat_id":3, "category_name":"mp4", "slug_name":"humoristiska_deckare_mysi_deck_3", "popular":false, }, {
"category_id":6, "parent_cat_id":3, "category_name":"video", "slug_name":"video3", "popular":false,
} ]
Please let me know how to find index of "category_name":"books3" using karate

Guess what, there is a far simpler way, the trick is to convert your search target into an array of primitives. Then you can use the List.indexOf() Java method:
Scenario: using the java indexOf api (will change with graal)
* def response = [{ name: 'a' }, { name: 'b' }, { name: 'c' }]
* def names = $[*].name
* def index = names.indexOf('b')
* match index == 1

Related

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

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.

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

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

How to retrieve all values for a particular key in karate

How to retrieve partNumbers from below response. In below response
"10000061","10000062","10000063"
are dynamic in nature. I have to match these partNumbers with data table partnumbers.( In a response there could be more than 10 part numbers(based on input) and i have to validate them.)
{ "added": true, "lineItems": { "1111111": { "itemCore": { "partNumber":
"10000061" } }, "222222": { "itemCore": { "partNumber": "10000061" } },
"3333333": { "itemCore": { "partNumber": "10000063" } } } }
Tried below
def partNum= get[0] response..itemCore.partNumber[*] but getting empty array.
def partNum= get[0] response..itemCore.partNumber but getting empty value.
My below second approach also giving me empty value.
* def keys = function(obj){ return response.lineItems.keySet() }
* json dynamicValue= keys(response)
* print 'dynamic value '+dynamicValue
* def first = dynamicValue[0]
* print response.lineItems.dynamicValue[0].itemCore.partNumber
* print response.lineItems.first.itemCore.partNumber
For retrieving data for a particular key, you can use deep scan operator in jsonPath,
* def partNumbers = karate.jsonPath(response,"$..partNumber")
Here's another solution, using karate.forEach() which can also operate on a map, not just a list:
* def keys = []
* eval karate.forEach(response.lineItems, function(k){ keys.add(k) })
* print keys