Can anyone explain how to get all the mismatch between two Array of JSON Object responses in karate? [duplicate] - karate

Like if I have two JSON as below and I want to check the mismatch between those
JSON 1:
{
name:'john',
contact:'123',
country:'america'
}
JSON 2:
{
name:'vishal',
contact:'123',
country:'India'
}
Now it will return me with the mismatch between name and country not only the name?

No this is not supported. We feel this is not needed, because in your regular CI runs you only care if the test passed or failed, and you see the details in the log.
Also note that you can simulate this if you really want using a Scenario Outline: https://stackoverflow.com/a/54108755/143475
Finally, if you care so much about this, kindly contribute code, this is open-source after all.
EDIT: you can easily do this by iterating over keys. Here is the code:
EDIT2: Setting up data via a Background is no longer supported in version 1.3.0 onwards, please look at the #setup tag: https://github.com/karatelabs/karate#setup
Feature:
Background:
* def json1 = { name: 'john', contact: '123', country: 'america' }
* def json2 = { name: 'vishal', contact: '123', country: 'India' }
* def keys = karate.keysOf(json1)
* def data = karate.mapWithKey(keys, 'key')
Scenario Outline: <key>
* match (json1[key]) == json2[key]
Examples:
| data |
And here is the report:

Related

How to loop new request according to response data list from previous step [duplicate]

I am using Karate version 0.8.0.1 and I want to perform following steps to test some responses.
I make a Get to web service 1
find the value for currencies from the response of web service 1 using jsonpath: $.currencies
Step 2 gives me following result: ["USD","HKD","SGD","INR","GBP"]
Now I use Get method for web service 2
From the response of web service 2 I want to get the value of price field with json-path something like below(passing the values from step 3 above):
$.holding[?(#.currency=='USD')].price
$.holding[?(#.currency=='HKD')].price
$.holding[?(#.currency=='SGD')].price
$.holding[?(#.currency=='INR')].price
$.holding[?(#.currency=='GBP')].price
So there are so many currencies but I want to verify price for only the currencies returned by web service 1(which will be always random) and pass it on to the the output of web service 2 to get the price.
Once i get the price I will match each price value with the value returned from DB.
I am not sure if there is any simple way in which I can pass the values returned by service 1 into the json-path of service 2 one by one and get the results required. Any suggestions for doing this will be helpful As this will be the case for most of the web services I will be automating.
There are multiple ways to do this in Karate. The below should give you a few pointers. Note how there is a magic variable _$ when you use match each. And since you can reference any other JSON in scope, you have some very powerful options.
* def expected = { HKD: 1, INR: 2, USD: 3}
* def response1 = ['USD', 'HKD', 'INR']
* def response2 = [{ currency: 'INR', price: 2 }, { currency: 'USD', price: 3 }, { currency: 'HKD', price: 1 }]
* match response2[*].currency contains only response1
* match each response2 contains { price: '#(expected[_$.currency])' }
You probably already have seen how you can call a second feature file in a loop which may be needed for your particular use case. One more piece of the puzzle may be this - it is very easy to transform any JSON array into the form Karate expects for calling a feature file in a loop:
* def response = ['USD', 'HKD', 'INR']
* def data = karate.map(response, function(x){ return { code: x } })
* match data == [{code: 'USD'}, {code: 'HKD'}, {code: 'INR'}]
EDIT - there is a short-cut to convert an array of primitives to an array of objects now: https://stackoverflow.com/a/58985917/143475
Also see this answer: https://stackoverflow.com/a/52845718/143475

karate: how to validate complex Api responses using karate?

i have two different responses as below, where i want to match only title of the type "Top-Tier Category" in response1 with "category_name" of the response2. here i don't want to match "type": "Top-Tier Top-List" in response1.
Note : "title" in response1 is equal to "category_name" in response2
Please let me know how to do this validations in karate. thanks in advance
Are you sure you have read all the documentation ? This should be straightforward, for example:
* def response = { title: 'foo' }
* def response1 = response
# make second request
* def response = { category_name: 'foo' }
* match response.category_name == response1.title
If the above is not clear, I strongly advise you consider using other tools that may be simpler for you.

Is there a way to test response is contained in schema?

In Karate, I'd like to have a schema variable which is a superset of the response data so that I can test multiple requests with the same schema.
This should be specially useful for GraphQL, where the request itself defines the returned fields.
Expected schema:
{
id: '#notnull',
name: '#notnull',
description: '##string',
nonNullStringField: '#string'
...
}
Given url ...
When request ...
Then match response.data <contained in> '#(mySchema)'
Response.data:
{
id: 'someId',
name: 'some name'
}
In this case, all keys returned by the response.data should be in the schema, but any key in the schema not in the response.data should be ignored.
Is there a way to do that in Karate or some plan to add this feature going forward?
Edit: updated the example, since the only attribute being missed was a nullable one.
I'm not convinced an enhancement is needed, because the optional marker ##foo was designed for this purpose, and this already works:
* def schema = { id: '#notnull', name: '#notnull', description: '##string' }
* def response = { id: 'someId', name: 'some name' }
* match response == schema
EDIT: but since you want to limit your schema to the keys in the response in a "generic" way, you can do this:
* def expected = {}
* def fun = function(k, v){ expected.put(k, schema[k]) }
* eval karate.forEach(response, fun)
* match response == expected
You should be able to easily create a re-usable JS or Java utility that achieves the above. A few reasons I'm not in favor of adding another syntax / match keyword is that nested JSON may have some interesting edge cases that will make this complex. And I don't want to complicate match any further. As I said in the comments, IMO schema validation is the last thing you need to test for in GraphQL, it is pretty much guaranteed. This is the first time anyone has requested this in 2 years, so there's that. You could consider submitting a PR of course :)

Karate contains and all key-values did not match error

I try to learn Karate but have some issue and I can't resolve it by myself.
So my Feature is looking rather simple:
Feature: Alerting get the list of all alerts
Background:
* url 'url'
Scenario: Retrieve all alerts
Given path '5c348c553a892c000bb1f2dd'
When method get
Then status 200
And match response contains {id: 5c348c553a892c000bb1f2dd}
The case here is to fetch a response and make sure that given ID is on the list. As far I understand this documentation keyword contains should lookup only for the given phrase but I get an error: reason: all key-values did not match
This is my console output:
allAlertsGet.feature:10 - path: $, actual: {data={name=Baelish of Harrenhal, user=griffin, id=5c348c553a892c000bb1f2dd, tags=["Gared"], triggers={prometheus=[{"js_id":"Qarth","labels":["Harry Potter and the Sorcerer's Stone"],"operator":"==","query":"up","value":"1"}]}, trigger_interval=398s, receivers={slack=[{"holdoffTime":"0s","id":"Stalls","message":"Dark and difficult times lie ahead. Soon we must all face the choice between what is right and what is easy.","revokeMessage":"Every flight begins with a fall.","token":"Buckbeak"}]}, hold_cap=4, max_cap=16, factor=2, createDate=1546947669, triggered_date=1546948867, mute_until=0, muted=false, status=3}}, expected: {id=5c348c553a892c000bb1f2dd}, reason: all key-values did not match
What I have missed? I use karate 0.9.0.
Pay attention to the nested structure of your JSON. You can paste this snippet into a Scenario and try it, this is a tip - you can experiment quickly without making HTTP requests like this:
* def response = { data: { name: 'Baelish of Harrenhal', user: 'griffin', id: '5c348c553a892c000bb1f2dd' } }
* match response.data contains { id: '5c348c553a892c000bb1f2dd' }
EDIT: just to show off a few other ways to do assertions:
* match response.data.id == '5c348c553a892c000bb1f2dd'
* match response..id contains '5c348c553a892c000bb1f2dd'
* def id = { id: '5c348c553a892c000bb1f2dd' }
* match response == { data: '#(^id)' }
* match response contains { data: '#(^id)' }

How to loop through karate response array and pass this in json path of another web service response

I am using Karate version 0.8.0.1 and I want to perform following steps to test some responses.
I make a Get to web service 1
find the value for currencies from the response of web service 1 using jsonpath: $.currencies
Step 2 gives me following result: ["USD","HKD","SGD","INR","GBP"]
Now I use Get method for web service 2
From the response of web service 2 I want to get the value of price field with json-path something like below(passing the values from step 3 above):
$.holding[?(#.currency=='USD')].price
$.holding[?(#.currency=='HKD')].price
$.holding[?(#.currency=='SGD')].price
$.holding[?(#.currency=='INR')].price
$.holding[?(#.currency=='GBP')].price
So there are so many currencies but I want to verify price for only the currencies returned by web service 1(which will be always random) and pass it on to the the output of web service 2 to get the price.
Once i get the price I will match each price value with the value returned from DB.
I am not sure if there is any simple way in which I can pass the values returned by service 1 into the json-path of service 2 one by one and get the results required. Any suggestions for doing this will be helpful As this will be the case for most of the web services I will be automating.
There are multiple ways to do this in Karate. The below should give you a few pointers. Note how there is a magic variable _$ when you use match each. And since you can reference any other JSON in scope, you have some very powerful options.
* def expected = { HKD: 1, INR: 2, USD: 3}
* def response1 = ['USD', 'HKD', 'INR']
* def response2 = [{ currency: 'INR', price: 2 }, { currency: 'USD', price: 3 }, { currency: 'HKD', price: 1 }]
* match response2[*].currency contains only response1
* match each response2 contains { price: '#(expected[_$.currency])' }
You probably already have seen how you can call a second feature file in a loop which may be needed for your particular use case. One more piece of the puzzle may be this - it is very easy to transform any JSON array into the form Karate expects for calling a feature file in a loop:
* def response = ['USD', 'HKD', 'INR']
* def data = karate.map(response, function(x){ return { code: x } })
* match data == [{code: 'USD'}, {code: 'HKD'}, {code: 'INR'}]
EDIT - there is a short-cut to convert an array of primitives to an array of objects now: https://stackoverflow.com/a/58985917/143475
Also see this answer: https://stackoverflow.com/a/52845718/143475