Karate loop returns Json array as objects {} - testing

I'm using Karate loops to generate dynamic Json.
One of my test data contains array within an object. When I use karate loop on this data, the array is returned as an object.
* def fun = function(i){ return { "name": "userName"+ i, "email": "Tester#test.com", "id": "ID"+i, "testSheet": [{"sheetId" : "123"}]} }
* def jsonBody = karate.repeat(3, fun)
* print jsonBody
I'm expecting below:
[
{
"name": "userName0",
"email": "Tester#test.com",
"id": "ID1",
"testSheet": [
{
"sheetId": "123"
}
]
}
]
But it returns this
[
{
"name": "userName0",
"email": "Tester#test.com",
"id": "ID1",
"testSheet": {
"0": {
"sheetId": "123"
}
}
}
]
Expected path: jsonBody[0].testSheet[0].sheetId
Actual path: jsonBody[0].testSheet.0.sheetId

Unfortunately this is a bug, which will be fixed in the next release: https://github.com/intuit/karate/issues/1187
This is the work-around. Define the array part outside the JS block for now, and use copy:
* def testSheet = [{"sheetId" : "123"}]
* def fun = function(i){ return { "name": "userName"+ i, "email": "Tester#test.com", "id": "ID"+i, "testSheet": testSheet } }
* copy jsonBody = karate.repeat(3, fun)
* print jsonBody

Related

Karate - How change key name in JSON

I have the following JSON. I want to change the keyName 'freeDelivery' to 'isFreeDelivery' but I can't figure out how to do it.
{
"result": [
{
"deliverySlots": [
{
"id": "2DNN",
"date": "2022-04-05",
"freeDelivery": false,
"label": "All day delivery 08:30am to 5pm",
"price": "£5.00",
"fullSlotId": "2DNN"
},
{
"id": "2DPM",
"date": "2022-04-05",
"freeDelivery": false,
"label": "Afternoon 12pm to 5pm",
"price": "£10.00",
"fullSlotId": "2DPM"
}
]
},
{
"deliverySlots": [
{
"id": "2DNN",
"date": "2022-04-06",
"freeDelivery": false,
"label": "All day delivery 08:30am to 5pm",
"price": "£5.00",
"fullSlotId": "2DNN"
},
{
"id": "2DPM",
"date": "2022-04-06",
"freeDelivery": false,
"label": "Afternoon 12pm to 5pm",
"price": "£10.00",
"fullSlotId": "2DPM"
}
]
}
]
}
I've looked at the following pages but still can't figure out how to do it. Do I have to do a transorm or is there an easier way?
https://github.com/karatelabs/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/js-arrays.feature
https://github.com/karatelabs/karate#json-transforms
Here you go:
* def payload = { before: 'foo' }
* remove payload.before
* payload.after = 'bar'
* match payload == { after: 'bar' }
Instead of remove this will also work (using pure JS):
* eval delete payload.before
EDIT: after seeing the comments, I would treat this as a JSON transform.
* def payload = { before: 'foo' }
* def fun = function(x){ var res = {}; res.after = x.before; return res }
* def result = fun(payload)
* match result == { after: 'foo' }
I'm sure now you'll want to "retain" all the existing data. Fine, here you go:
* def payload = { before: 'foo' }
* def fun = function(x){ var res = x; res.after = x.before; delete res.before; return res }
* def result = fun(payload)
* match result == { after: 'foo' }
And you already know that you can run a transform on all array elements like this:
* def result = karate.map(someArray, fun)
Please note that you can create 2 or 3 transforms - and "nest" them.

Karate- How can I pass a param as a key?

I have the following case and need to use firstKeyStr as a key, my code now is seeing "#firstKeyStr" as the key not the one stored in it
Code
Given path '/api/v1/sites'
When method get
Then status 200
And match response.success == true
And match response.data == "#object"
* def keys = karate.keysOf(response.data)
* def firstKeyStr = keys[0]
And match response.data."#firstKeyStr" == "#object"
Json Response Body
{
"success": true,
"data": {
"5ef34d0ca5a3c56ae14d2a23": {
"devices": [
"5f03192010a47f3e5b714193"
],
"groups": [
"5f0d9f30ef89e22778a2d230"
],
"users": [],
"triggers": [],
"alerts": [
"5f0d92b967bac60b84d3989b"
],
"name": "test",
"country": "US",
]
}
}
I'm looking for a way to pass this dynamic key (5ef34d0ca5a3c56ae14d2a23) in this line (And match response.data."#firstKeyStr" == "#object")
Since you are new to stack overflow, please read the following to best get help:
https://stackoverflow.com/help/how-to-ask
https://stackoverflow.com/help/someone-answers
As Peter said, your JSON is not well formed and the order of keys is not guaranteed (unless you have just a single key). The following code should get you going.
Sample Code:
Feature: firstKey
Scenario: firstKey
* def resp =
"""
{
"success": true,
"data": {
"5ef34d0ca5a3c56ae14d2a23": {
"devices": [
"5f03192010a47f3e5b714193"
],
"groups": [
"5f0d9f30ef89e22778a2d230"
],
"users": [],
"triggers": [],
"alerts": [
"5f0d92b967bac60b84d3989b"
],
"name": "test",
"country": "US"
}
}
}
"""
And match resp.data == "#object"
* def keys = karate.keysOf(resp.data)
* def firstKeyStr = keys[0]
* print firstKeyStr
* print (resp.data[firstKeyStr])
And match (resp.data[firstKeyStr]) == "#object"
Use round brackets so that JS is used instead of JsonPath:
* def response = { data: { a: 1, b: 2 } }
* def keys = karate.keysOf(response.data)
* def first = keys[0]
* match (response.data[first]) == 1

How to traverse thru a response when it is as below

{
"createDate": "2019-05-15 10:07:44",
"mak": "pokijoklm",
"optStatus": "yujuim",
"partnerAccount": {
"operatorName": "frftcrtii",
"partnerCustomerId": "XXXXX",
"type": "partnerAccount"
},
"transactionId": "hjknhijn1",
"type": "nihnui",
"updateDate": "2019-05-15 11:20:59"
}
For an array we can try as response.partneraccount[*]. but my response is { }
You use [] only when there are arrays. Just observe your JSON structure carefully and you will get it. Try pasting the below into a fresh Scenario and see it work:
* def response =
"""
{
"createDate": "2019-05-15 10:07:44",
"mak": "pokijoklm",
"optStatus": "yujuim",
"partnerAccount": {
"operatorName": "frftcrtii",
"partnerCustomerId": "XXXXX",
"type": "partnerAccount"
},
"transactionId": "hjknhijn1",
"type": "nihnui",
"updateDate": "2019-05-15 11:20:59"
}
"""
* def partnerAccount = response.partnerAccount
* match partnerAccount == { operatorName: 'frftcrtii', partnerCustomerId: 'XXXXX', type: 'partnerAccount' }
* def custId = response.partnerAccount.partnerCustomerId
* match custId == 'XXXXX'

Extract data from json array in Karate

In the below JSON response, I need to extract the 'cid' for the record that has the 'nationalityDecription' as 'USA'. By using this query as a reference, I used the below loc in the karate feature file, but 1st line itself fails with syntax error(tried different combinations). For now, I'm using the custom javascript as a workaround which is working fine. I need help to check if i'm missing anything in syntax. Thanks
Response:
{
"header": {
"Id": "12345678",
"timeStamp": "2018-09-17T10:09:812.000"
},
"dataRecords": [
{
"cid": "31H678",
"cidMeta": "00",
"nationalityDecription": "CHINA"
},
{
"cid": "31S421",
"cidMeta": "01",
"nationalityDecription": "USA"
}
]
}
Feature file:
* def record= $response.dataRecords[?(#.nationalityDecription=='USA')]
* def cid = record.cid
* def response = { "header": { "Id": "12345678", "timeStamp": "2018-09-17T10:09:812.000" }, "dataRecords": [ { "cid": "31H678", "cidMeta": "00", "nationalityDecription": "CHINA" }, { "cid": "31S421", "cidMeta": "01", "nationalityDecription": "USA" } ] }
* def cid = get[0] response.dataRecords[?(#.nationalityDecription=='USA')].cid
* match cid == '31S421'

How to convert SQL result set to JSON in Groovy?

I have this simple Groovy script to export SQL result set to JSON. Though the below one works, it is not in the format I would like to have. Any help here please?
def resultset = Sql.newInstance(...).rows('select * from client')
println new JsonBuilder(resultset).toPrettyString()
Above code prints
[
{
"ID":1,
"NAME: "ABC"
},
{
"ID":2,
"NAME: "XYZ"
},
{
"ID":3,
"NAME: "MSFT"
}
]
Expected output
{
"clients": [
{
"ID": 1,
"NAME": "ABC"
},
{
"ID": 2,
"NAME": "XYZ"
},
{
"ID": 3,
"NAME": "MSFT"
}
]
}
Wouldn't is just be:
println new JsonBuilder(clients:resultset).toPrettyString()
You know what's going on here? You pass an instance of a Map to JsonBuilder and that's all.