How to match against list of maps in Karate? - karate

I have a list:
[{
"a": 1
"b": 2
}]
And I would like to match it this way:
And match response contains
"""
[{
"a": 1
}]
"""
However this does not work since the map inside of the list from the response has more keys. I just want to ignore them. Is there easy way to do it?

There are two ways to do this:
* def response = [{ a: 1, b: 2 }]
* def expected = { a: 1 }
* match response contains '#(^expected)'
Or you could use contains deep:
* match response contains deep { a: 1 }

Related

Is there a way to set some values in the multiple dimensional json array

Scenario Outline: Explore Karate '<ID>'
* karate.set($attributesFirstRun[*].created_timestamp,'#present')
* karate.set($attributesSecondRun[*].created_timestamp,'#present')
* match attributesFirstRun == attributesSecondRun
Examples:
| read('Sample.csv') |
I tried this. But I'm getting this error
org.graalvm.polyglot.PolyglotException: SyntaxError: Unnamed:1:42 Expected an operand but found *
I think you are over-thinking this. Karate is actually just plain JS. And sounds like you are trying to do a "bulk update" via JsonPath - sorry, that's not supported, perhaps you would be interested in contributing code.
Here's the solution for updating all elements of an array:
* def before = [{ a: 1 }, { a: 2 }]
* def after = before.map(x => ({ a: x.a * 5 }))
* match after == [{ a: 5 }, { a: 10 }]
Keep in mind updating JSON is easy:
* def data = {}
* data.a = 1
* match data == { a: 1 }
Refer the docs: https://github.com/karatelabs/karate#json-transforms

Matching dynamic keys in karate

I am trying to match a JSON array with a predefined expected json. The problem is that one of the key values in actual JSON is a set of strings delimited by "|". Here is how it looks :
actualJSON = [
{
"a": "varA",
"mix: "X|Y|Z",
},
{
"b": "B",
"c": "C"
} ]
expectedJSON = [
{
"a": "varA",
"mix: "Y|Z|X",
},
{
"b": "B",
"c": "C"
} ]
Issue here is the mix key that represents a set of strings and the value can be any combination of "X|Y|Z" without any specific order like "Z|Y|X" etc. When the value of mix is Y|Z|X then
* match actualJSON contains expectedJSON
works fine but in other cases it fails as expected. Is there a way to do the matching when key value is dynamic?
My first suggestion is as far as possible to write tests where the response is 100% predictable and don't waste time on these weird cases. Also refer: https://stackoverflow.com/a/50350442/143475
That said this is easy to do if you write a JS function:
* def response = { foo: 'X|Y|Z' }
* def hasXyz = function(x){ return x.includes('X') && x.includes('Y') && x.includes('Z') }
* match response == { foo: '#? hasXyz(_)' }
I leave it to you to figure out better logic if you want. Refer: https://github.com/karatelabs/karate#self-validation-expressions

Karate : Dynamically input values from embedded expressions in a JSON file

* def mpRequestJson =
"""
{
"entity": '<entity>',
"consent": {
"PHONE": <updategetPhonePref>,
"EMAIL": true,
"POST": false,
"SMS": <updategetSMSPref>
},
"notices": [{
"title": "Privacy policy",
"version": "NA"
}],
"source": "web"
}
"""
Given path '<entity>'
And request mpRequestJson
When method PUT
Then status 200
And match $.consent.PHONE == '<updategetPhonePref>'
And match $.consent.SMS == '<updategetSMSPref>'
Examples:
|entity | updategetPhonePref|updategetSMSPref|
|xyz| #(updategetPhonePref)|#(updategetSMSPref)|
If i want to store the JSON request in a JSON file rather than in the feature file, what should be my JSON file?
In the JSON use embedded expressions, e.g.
entity: '#(entity)'
Then you can read it from a file:
* def mpRequestJson = read('my.json')
But before the read you should initialize variables that have to be substituted. So you will have some extra lines.
* def entity = '<entity>'
One way to reduce the extra lines is to create a temp JSON:
* def data = { entity: '<entity'>, phone: '<updategetPhonePref>' }
And then you can do this in the JSON:
entity: '#(data.entity)'
Read the docs on data driven tests also please.

Adding new key-value pair into json using karate

My payload looks like this :
{
"override_source": "DS",
"property_code": "0078099",
"stay_date": "2018-11-26T00:00:00.000000",
"sku_prices": [
],
"persistent_override": false
}
There is an array dblist ["2","3"] , it would consists of numbers from 1 to 4. Based on the elements present in the list, I want to add key-values {"sku_price":"1500","sku_code":"2"} to my payload. I am using the following code :
* eval if(contains("3",dblist)) karate.set('pushRatesFromDS.sku_prices[]','{ "sku_price": "1500","sku_code":"3" }')
When I execute my feature file, I do not get any errors but, key-values are not added to my payload. However if I move this code to a new feature file and call it, key-value pairs get added to my payload. The code in my new feature file looks like : * set pushRatesFromDS.sku_prices[] = { "sku_price": "1500","sku_code":"2" }
Try this:
* def foo =
"""
{
"override_source": "DS",
"property_code": "0078099",
"stay_date": "2018-11-26T00:00:00.000000",
"sku_prices": [
],
"persistent_override": false
}
"""
* eval karate.set('foo', '$.sku_prices[]', { foo: 'bar' })

Matching values from response to values from DB

My response looks as follows :
{
"data":[
{
"foo":bar1
"user_email":"user#user.com",
"user_id":1
},
{
"foo":bar2
"user_email":"user#user.com",
"user_id":1
}
]
}
* def DBOutput = #fetching values from DB
* match response.data[*].foo contains [DBOutput1[0][0],DBOutput1[1][0]]
DBOutput1 has data as follows : [["bar1"],["bar2"]]
This match fails, for some reasons value passed into the expected list in match statement is DBOutput1[0][0]
This is the error I am getting actual: ["bar1","bar2"], expected: 'DBOutput1[0][0]',
You have some seriously malformed JSON in your example above. The below snippet works, just paste it into a new Scenario:
* def response =
"""
{
"data":[
{
"foo": "bar1",
"user_email":"user#user.com",
"user_id":1
},
{
"foo": "bar2",
"user_email":"user#user.com",
"user_id":1
}
]
}
"""
* match response.data[*].foo contains ['bar1', 'bar2']
Now it is up to you to fix your test, without knowing what your DBOutput is no one can help further.
I iterated over the DBoutput and stored them in a new array list. I then matched the response to the list and it worked.
match response.data[*].foo contains ListFromDB