How to add Multiple JSON array Element depends on Example Data Set - karate

During my Karate scenario automation got the below problem statement. Could anyone please help me on this?
My JSON file will contain,
{
"schema_id": 25,
"records": [
{
"value": {
"NUM_CHARGE_ID": "#(numChargeID)",
"DTE_START": "2017-05-26",
"NUM_DAY": "#(numDay)"
}
}
]
}
From my Karate feature file I want to pass data from Example and depends on the data set it should create multiple array element in the json. Like,
Examples:
| numChargeID | numDay|
|C10,C21,C15,C18|1,2,3,4|
{
"schema_id": 25,
"records": [
{
"value": {
"NUM_CHARGE_ID": "C10",
"DTE_START": "2017-05-26",
"NUM_DAY": "1"
},
{
"NUM_CHARGE_ID": "C21",
"DTE_START": "2017-05-26",
"NUM_DAY": "2"
},
{
"NUM_CHARGE_ID": "C15",
"DTE_START": "2017-05-26",
"NUM_DAY": "3"
},
{
"NUM_CHARGE_ID": "C18",
"DTE_START": "2017-05-26",
"NUM_DAY": "4"
}
}
]
}
Is there any way in Karate that i can handle this type of situation?

There are plenty of ways to solve this and maybe you shouldn't try to force everything into Examples:. For instance:
* def chargeIds = ['C1', 'C2']
* def dayNums = [1, 2]
* def fun = function(x, i){ return { NUM_CHARGE_ID: x, NUM_DAY: dayNums[i] } }
* def records = karate.map(chargeIds, fun)
* print records
Which gives you:
[
{
"NUM_CHARGE_ID": "C1",
"NUM_DAY": 1
},
{
"NUM_CHARGE_ID": "C2",
"NUM_DAY": 2
}
]
What I would recommend is something like this:
* table records
| NUM_CHARGE_ID | NUM_DAY |
| 'C1' | 1 |
| 'C2' | 2 |
* print records
Which gives you the exact same thing.
Also look at the possible use of set: https://github.com/intuit/karate#set-multiple

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 loop returns Json array as objects {}

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

Error while matchig nested json array in Karate

Can anybody help me with the below error? I am not sure what I am missing. I guess something very simple I am missing.
assertion failed: path: $[0].drives[*], actual: [{"partitionData":[{"label":"Recovery"},{"label":""},{"label":"New Volume"},{"label":""}]}], expected: {partitionData=[{"label":"#present"}]}, reason: actual value does not contain expected
Below is my schema code:
* set schema
| path | 0 |
| drives | [{"partitionData": [{"label":"#present"}] }] |
Below is the output:
[
{
"drives": [
{
"partitionData": [
{
"label": "Recovery"
},
{
"label": ""
},
{
"label": "New Volume"
},
{
"label": ""
}
]
}
]
}
]
And match each output contains schema[0]
Since your question is confusing, here is a simple example. Don't use set if not needed.
* def schema = { "partitionData": [ { "label" : "#present" } ] }
* def response = { drives: [ { "partitionData": [ { "label" : "foo" } ] } ] }
* match each response.drives == schema

Getting the maximum value from an array in a JSON response in Karate

I have the following Json as a response from a API call
{
"location": {
"name": "London",
"region": "City of London, Greater London",
"country": "United Kingdom",
"lat": 51.52,
"lon": -0.11,
"tz_id": "Europe/London",
"localtime_epoch": 1583594426,
"localtime": "2020-03-07 15:20"
},
"forecast": {
"forecastday": [
{
"date": "2020-03-03",
"day": {
"maxtemp_c": 9,
"mintemp_c": 4
}
},
{
"date": "2020-03-04",
"day": {
"maxtemp_c": 8,
"mintemp_c": 4.1
}
},
{
"date": "2020-03-05",
"day": {
"maxtemp_c": 7,
"mintemp_c": 5.6
}
}
]
}
}
I want to find out which date had the highest temperature amongst the 3 days.
The way I am currently doing feels inefficient as I am checking for the temperature element within my js function and it is as follows
* def hottest =
"""
function(array) {
var greatest;
var indexOfGreatest;
for (var i = 0; i < array.length; i++) {
if (!greatest || array[i].day.maxtemp_c > greatest) {
greatest = array[i].day.maxtemp_c;
indexOfGreatest = i;
}
}
return indexOfGreatest;
}
"""
* def index = call hottest response.forecast.forecastday
* def hottestdate = response.forecast.forecastday[index].date
* print hottestdate
With this I am getting the correct result but can someone kindly suggest a better way of doing this?
Best practice in Karate is to NOT use JS for loops at all. It results in cleaner, more readable code:
* def fun = function(x){ return { max: x.day.maxtemp_c, date: x.date } }
* def list = karate.map(response.forecast.forecastday, fun)
* def max = 0
* def index = 0
* def finder =
"""
function(x, i) {
var max = karate.get('max');
if (x.max > max) {
karate.set('max', x.max);
karate.set('index', i);
}
}
"""
* karate.forEach(list, finder)
* print 'found at index', index
* print 'item:', list[index]
Note how easy it is to re-shape a given JSON, the result of list here would be:
[
{
"max": 9,
"date": "2020-03-03"
},
{
"max": 8,
"date": "2020-03-04"
},
{
"max": 7,
"date": "2020-03-05"
}
]

Karate: Traverse thru a complex JSON to find a match

I am hitting an API end point and getting something like below.
{
"emp": {
"id": "123",
"firstNm": "test",
"lastNm": "last",
"dob": "200-01-01",
"gender": {
"code": "F",
"name": "Female",
"description": "Female"
},
"test1": [
{
"tes2": "F50045A3B994FB2BDF4E3D3FC906F592",
"t2": "a23",
"test3": {
"code": "432",
},
"ind": [
"ABC",
"BCD",
]
}
]
}
}
I want to match the elements in the array
"ind": [
"ABC",
"BCD",
]
I have tried the below:
Feature: test
Background:
* url BaseUrl
* configure headers = read('classpath:headers.js')
Scenario Outline: test
Given path '/path'
And param id = <id>
When method get
Then status 200
* def json = response
* def has = {ind:['#string'] }
* def indicator = { ind: '#[] has' }
* match json.member == '#[] indicator'
Examples:
| id |
| '1234' |
But observed the below exception:
expected: '#[] ind', reason: not an array or list
Can someone please help?
I am not really following your logic since indicators is not in the json response or defined variable but to get to the ind array the path is emp.test1[0].ind
if you want to match that the array has ABC and BCD you would do the following
* match response.emp.test1[0].ind == ['ABC', 'BCD']