How to Print Index value for matching JSON data using Karate - karate

I would like to print the index value for matching JSON data using Karate.
For below code the expected answer should be 2, but I got -1, not sure what I am missing
[
{"aaa": 101},
{"bbb": 102},
{"ccc": 103}
]
Feature: Rough
Scenario: Rough
* def myData = read('roughTestData.json')
* print "Index ->>", myData.indexOf('ccc')

You have a JSON object within an array (not a plain string), and the complication here is you are interested in keys not values, so you need to do this instead:
* def response = [{"aaa":101},{"bbb":102},{"ccc":103}]
* def keys = response.map(x => Object.keys(x)[0])
* def index = keys.indexOf('ccc')
* match index == 2
We are using JS array methods such as map(), Object.keys() and indexOf() above
That said, I personally think you are over-complicating things because Karate allows you to match without caring about the order. For example:
* def response = [{"aaa":101},{"bbb":102},{"ccc":103}]
* def expected = [{ccc:'#number'},{bbb:'#number'},{aaa:'#number'}]
* match response contains only expected
So read the docs, and be creative: https://github.com/karatelabs/karate#json-arrays

Related

How to assert a list in which each value should be one the values of the expected list?

I am trying to assert a list using match contains any, match each but it is not working.
def actualList = ["CABLE_MODEM","SET_TOP_BOX","SET_TOP_BOX","CABLE_MODEM","CBE"]
def expectedList = ["CABLE_CARD","SET_TOP_BOX","CABLE_MODEM","MTA","OTHER","IP_SET_TOP_BOX"]
match each actualList contains any expectedList
Basically, every value of the actualList should be any one of the expectedList value. But it is directly comparing the first value of the 2 lists. Kindly help me
I'm not sure I understand the question. But sometimes these crazy assertions are best done in JS:
* def actualList = ["CABLE_MODEM","SET_TOP_BOX","SET_TOP_BOX","CABLE_MODEM","CBE"]
* def expectedList = ["CABLE_CARD","SET_TOP_BOX","CABLE_MODEM","MTA","OTHER","IP_SET_TOP_BOX"]
* def unexpected = actualList.filter(x => !expectedList.includes(x))
* match unexpected == []
Please take the help of a friend who knows JS if the above is not clear.
EDIT: for completeness, here's the "karate style" way to solve this. For more complex custom checks, karate.match() can be used.
* def valid = function(x){ return expectedList.includes(x) }
* match each actualList == '#? valid(_)'

Change type from string to float/double for a key value of any json object in an array

i have a json as follows:
* def first = [{"country":"X","code":"XY","cityName":"XYZN","city":"XYZ","timezone":"XYZT","latitude":"57.0928","name":"XYZN","longitude":"9.8492"}, {"country":"A","code":"AB","cityName":"ABCN","city":"ABC","timezone":"ABCT","latitude":"1.234","name":"ABCN","longitude":"29.8482"}]
def second = [{"country":"X","code":"XY","cityName":"XYZN","city":"XYZ","timezone":"XYZT","latitude":57.0928,"name":"XYZN","longitude":9.8492}, {"country":"A","code":"AB","cityName":"ABCN","city":"ABC","timezone":"ABCT","latitude":1.234,"name":"ABCN","longitude":29.8482}]
i want to compare these two, but its failing because the first json has longitude and latitude as string while second json has them as numbers.
Also, i dont want to change second json and has to be used as it is.
Please suggest how can i change the type from string to number in first?
I tried https://github.com/intuit/karate#floats-and-integers
but it didnt work out for object array.
Sample Code:
Feature:
Scenario:
* def first = [{"country":"X","code":"XY","cityName":"XYZN","city":"XYZ","timezone":"XYZT","latitude":"57.0928","name":"XYZN","longitude":"9.8492"}, {"country":"A","code":"AB","cityName":"ABCN","city":"ABC","timezone":"ABCT","latitude":"1.234","name":"ABCN","longitude":"29.8482"}]
* def second = [{"country":"X","code":"XY","cityName":"XYZN","city":"XYZ","timezone":"XYZT","latitude":57.0928,"name":"XYZN","longitude":9.8492}, {"country":"A","code":"AB","cityName":"ABCN","city":"ABC","timezone":"ABCT","latitude":1.234,"name":"ABCN","longitude":29.8482}]
* def first_formatted = []
* def fun = function(x){x.latitude = Number(x.latitude); x.longitude = Number(x.longitude); karate.appendTo(first_formatted, x); }
* karate.forEach(first, fun)
* print first_formatted
* match first_formatted == second

Trimming zeros in JSONArray in Karate DSL

I am getting a JSON response with JSONArray having leading zeros. Example, registrationnumber = ["0000012345", "0000001234", "000123456"]
I want to remove these zeros and compare with another json response where I get the registrationNumber =["12345", "1234", "123456"]
I am trying to do this with my automation in karate-dsl.
Can someone help?
Thanks.
To convert to a number just multiply by 1. You should read the docs: https://github.com/intuit/karate#type-conversion
* def data = ["0000012345", "0000001234", "000123456"]
* def nums = karate.map(data, function(x){ return parseInt(x) })
* match nums == [12345, 1234, 123456]

How to validate a response in karate when you don't know the structure?

I'm trying to write some karate tests that check a response for some expected structure. For example, there is an object that looks like this:
{
'true|true':'disabled',
'true|false':'locked',
'false|false':'enabled',
'false|true':'disabled',
'default':'enabled'
}
However, the keys and values could be any strings. There must be a way to specify this, but I'm at a loss for how to do this in a generic way.
Essentially, what I would like to test is that 1) the object is not empty, 2) each of the keys and values is a string (not an object and not null).
The basic match looks like this:
* def objects = $fields..objects
And match each objects ==
"""
{
key1: '#? isString(_)',
key2: '#? isString(_)'
}
"""
It looks like the names of the keys must be known in advance, so perhaps match expressions are not the appropriate way to test this.
You can extract all keys like this:
* def keys = karate.keysOf(object)
So once you have that, you are in business:
* def foo = { a: 1, b: 2 }
* def keys = karate.keysOf(foo)
* match each keys == '#string'
* assert keys.length > 0
See JSON tranforms for other ideas, e.g. karate.forEach(): https://github.com/intuit/karate#json-transforms

Unable to Parse the variable value to the array variable

I was trying to pass the variable 'i' value to a array index 'locations[i]' using below karate code. but throwing an error saying unable to parse. Please suggest be for any changes.
Feature: Verify Branches
Background: For loop implementation
Given url ''
When method GET
Then status 200
* def i = 0
* def z = $.locations[i].zip
* def p = $.locations[i].phone
* def fun =
"""
function(locations){
for (var i = 0; i < locations.length; i++)
{
print(i)
print('Element at Location ' + i +':' + p)
}
}
"""
Scenario: Validate the locations
Given url ''
When method GET
Then status 200
* call fun p
It is hard to make out anything since you have not provided the value of the response. There are many things wrong here. But I'll try.
Take this line:
* def z = $.locations[i].zip
This will not work, Karate does not support variables within JsonPath by default, refer the docs: https://github.com/intuit/karate#jsonpath-filters
And I think you are un-necessarily using JsonPath where normal JavaScript would have been sufficient:
* def z = response.locations[i].zip
Also it seems you are just trying to loop over an array and call a feature. Please refer to the documentation on Data Driven Features.
Take some time and read the docs and examples please, it will be worth your time. One more tip - before I leave you to understand Karate a little better. There is a way to convert a JSON array into another JSON array should you need it:
* def fun = function(x){ return { value: x } }
* def list = [1, 2, 3]
* def res = karate.map(list, fun)
* match res == [{ value: 1 }, { value: 2 }, { value: 3 }]
So there should never be a need for you to manually do a for loop at all.