Json response validation based on substring presence in Karate Framework [duplicate] - json

This question already has an answer here:
Karate API json response - How to validate the presence of a key which sometimes come and sometimes not in the API response
(1 answer)
Closed 2 years ago.
I am trying to validate a JSON which has Optional keys depending on a condition.
Json response is as follows:
{ "hits": [
{
"_type": "sessions",
"_source": {
"movie_name": "The Greatest Showman (U/A) - English",
"session_data": {
"freeSeating": false,
"mandatoryItems": [],
"areas": [
{
"seatingType": "fixed"
},
{
"seatingType": "free"
},
{
"seatingType": "mixed"
}
]
}
}
},
{
"_type": "sessions",
"_source": {
"movie_name": "The Greatest Showman (U/A) - English",
"session_data": {
"freeSeating": false,
"mandatoryItems": [],
"areas": [
{
"seatingType": "fixed"
},
{
"seatingType": "free"
}
]
}
}
},
{
"_type": "sessions",
"_source": {
"movie_name": "The Greatest Showman 3D (U/A) - English",
"session_data": {
"freeSeating": false,
"mandatoryItems": [
{
"quantity": 1,
"level": "ticket",
"price": 30,
"type": "3dglasses"
}
],
"areas": [
{
"seatingType": "fixed"
}
]
}
}
}
]
}
If movie_name contains "3D" in it then mandatoryItems = [{"quantity": 1,"level": "ticket", "price": 30, "type": "3dglasses"}]
If movie_name does not contains "3D" in it then mandatoryItems = []
I want to achieve above assertions in my feature file.
Note: "movie_name" and "mandatoryItems" are present each element of an array. So I want to assert this condition on entire array.
Thanks in advance!!

Sorry #Peter for the inconvenience caused by me. I worked on this problem statement by referring all possible sources and wrote following code which is giving me desired output:
Given url api_url
When method Get
And def mandatoryItems_present =
"""
{
"quantity": 1,
"level": "ticket",
"price": '#number',
"type": "3dglasses",
}
"""
Then status 200
And print response
And def source_list = karate.jsonPath(response, '$.._source')
And print source_list
And match each source_list[*].session_data contains {'freeSeating': '#boolean','mandatoryItems':'##[] mandatoryItems_present'}
And def movie_names = get source_list[*].movie_name
And def mandatoryItems_list = get source_list[*].session_data.mandatoryItems
And def name_size = names.size();
And print name_size
And def threeD_movie_list = new ArrayList()
And eval for(var i = 0; i < name_size; i++) {if (names[i].match('3D')) threeD_movie_list.add(names[i])}
And print threeD_movie_list
And def threeD_movies_array_size = threeD_movie_list.size();
And print threeD_movies_array_size
And print expected
And def expected = (threeD_movies_array_size == 0 ? {"mandatoryItems" : []} : {'mandatoryItems' : [mandatoryItems_present]} )
And print expected
And match each response.hits[*]._source.session_data[*].mandatoryItems == expected
Please let me know whether this approach is correct.

Related

How to get the All index values in Groovy JSON xpath

Please find the attached Groovy code which I am using to get the particular filed from the response body.
Query 1 :
It is retrieving the results when the I am using the correct Index value like if the data.RenewalDetails[o], will give output as Value 1 and if the data.RenewalDetails[1], output as Value 2.
But in my real case, I will never know about number of blocks in the response, so I want to get all the values that are satisficing the condition, I tried data.RenewalDetails[*] but it is not working. Can you please help ?
Query 2:
Apart from the above condition, I want to add one more filter, where "FamilyCode": "PREMIUM" in the Itemdetails, Can you help on the same ?
def BoundId = new groovy.json.JsonSlurper().parseText('{"data":{"RenewalDetails":[{"ExpiryDetails":{"duration":"xxxxx","destination":"LHR","from":"AUH","value":2,"segments":[{"valudeid":"xxx-xx6262-xxxyyy-1111-11-11-1111"}]},"Itemdetails":[{"BoundId":"Value1","isexpired":true,"FamilyCode":"PREMIUM","availabilityDetails":[{"travelID":"AAA-AB1234-AAABBB-2022-11-10-1111","quota":"X","scale":"XXX","class":"X"}]}]},{"ExpiryDetails":{"duration":"xxxxx","destination":"LHR","from":"AUH","value":2,"segments":[{"valudeid":"xxx-xx6262-xxxyyy-1111-11-11-1111"}]},"Itemdetails":[{"BoundId":"Value2","isexpired":true,"FamilyCode":"PREMIUM","availabilityDetails":[{"travelID":"AAA-AB1234-AAABBB-2022-11-10-1111","quota":"X","scale":"XXX","class":"X"}]}]}]},"warnings":[{"code":"xxxx","detail":"xxxxxxxx","title":"xxxxxxxx"}]}')
.data.RenewalDetails[0].Itemdetails.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33
}?.BoundId
println "Hello " + BoundId
Something like this:
def txt = '''\
{
"data": {
"RenewalDetails": [
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "LHR",
"from": "AUH",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "Value1",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
},
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "LHR",
"from": "AUH",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "Value2",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
}
]
},
"warnings": [
{
"code": "xxxx",
"detail": "xxxxxxxx",
"title": "xxxxxxxx"
}
]
}'''
def json = new groovy.json.JsonSlurper().parseText txt
List<String> BoundIds = json.data.RenewalDetails.Itemdetails*.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.size() == 33 && itemDetail.FamilyCode == 'PREMIUM'
}?.BoundId
assert BoundIds.toString() == '[Value1, Value2]'
Note, that you will get the BoundIds as a List
If you amend your code like this:
def json = new groovy.json.JsonSlurper().parse(prev.getResponseData()
you would be able to access the number of returned items as:
def size = json.data.RenewalDetails.size()
as RenewalDetails represents a List
Just add as many queries you want using Groovy's && operator:
find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33 &&
itemDetail.FamilyCode.equals('PREMIUM')
}
More information:
Apache Groovy - Parsing and producing JSON
Apache Groovy: What Is Groovy Used For?

Json Extractor in JMeter

I am using JSON extractor in JMeter. Below is my Response Body. I am using the Json path expression to capture the value, which is working fine.
Apart from the above condition, I need to add one more condition.
If the "travelID" length is equal to 33, then only I need to get the BoundID.
Example : AAA-AB1234-AAABBB-2022-11-10-1111
Total length or count of the above travelID is 33, but sometime I used to get 31,32 also but I need to capture the Bound ID only when the length is 33. Is that feasible ? Please help on the same
PFB sample response body.
{
"data": {
"RenewalDetails": [
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "XXX",
"from": "XXX",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "xxx-1-xxx1-111111111111-1",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
}
]
},
"warnings": [
{
"code": "xxxx",
"detail": "xxxxxxxx",
"title": "xxxxxxxx"
}
]
}
I don't think it's possible with JSON Extractor, I would rather suggest going for JSR223 PostProcessor and the following Groovy code:
def BoundId = new groovy.json.JsonSlurper().parse(prev.getResponseData())
.data.RenewalDetails[0].Itemdetails.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33
}?.BoundId
vars.put('BoundId', BoundId ?: 'Not Found')
You will be able to refer extracted value as ${BoundId} later on where required.

pyjq - how to use "select" with both query and value as variables

I am writing a code in python3 where i am struggling with usage of variables with "pyjq", the code works without variables but variables are not getting parsed inside pyjq.
The documentation referred is https://github.com/doloopwhile/pyjq/blob/master/README.md#api
Please check the code given below and suggest -
My code
import json, os
import pyjq
from flask import Flask, request, jsonify
def query_records():
args = {"meta.antivirus.enabled": "true"}
for key, value in args.items():
with open('/tmp/data.txt', 'r') as f:
print (key)
print (value)
data = f.read()
records = json.loads(data)
query = ("." + key)
print (query)
#jq '.[]|select(.meta.antivirus.enabled=="true")' filename.json works,issue with variable substitution in python
match = pyjq.all('.[]|select(["$query"]==$value)', records, vars={"value": value,"query": query})
print (match)
query_records()
Content of file "/tmp/data.txt"
[
{
"name": "alpharetta",
"meta": {
"antivirus": {
"enabled": "true"
},
"limits": {
"cpu": {
"enabled": "true",
"value": "250m"
}
}
}
},
{
"meta": {
"allergens": {
"eggs": "true",
"nuts": "false",
"seafood": "false"
},
"calories": 230,
"carbohydrates": {
"dietary-fiber": "4g",
"sugars": "1g"
},
"fats": {
"saturated-fat": "0g",
"trans-fat": "1g"
}
},
"name": "sandwich-nutrition"
},
{
"meta": {
"allergens": {
"eggs": "true",
"nuts": "false",
"seafood": "true"
},
"calories": 440,
"carbohydrates": {
"dietary-fiber": "4g",
"sugars": "2g"
},
"fats": {
"saturated-fat": "0g",
"trans-fat": "1g"
}
},
"name": "random-nutrition"
}
]
Expected output(which works without variables)
{
"name": "alpharetta",
"meta": {
"antivirus": {
"enabled": "true"
},
"limits": {
"cpu": {
"enabled": "true",
"value": "250m"
}
}
}
}
Current output []
seems like some issue with variables not being passed in case of "query" , help would be appreciated.
Edit 1
It works if I hardcode "query" -
match = pyjq.all('.[]|select(.meta.antivirus.enabled==$value)', records, vars={"value": value,"query": query})
but not vice-versa
which probably narrows it down to issue with the variable "query"
JQ is not a necessity and I can use other libraries too,given that json is returned
Variables are intended to be used for values, not for jq expressions (at least not directly).
I think the easiest option here is to go for an fstring:
match = pyjq.all(f'.[]|select({query}==$value)', records, vars={"value": value})
and it probably makes sense to prepend the period inside the fstring:
match = pyjq.all(f'.[]|select(.{key}==$value)', records, vars={"value": value})

Karate API framework - How to assert the empty value of a key and if that value is empty then assert that some other key should not present

Is there any way in Karate through which I can check that if any value is coming as empty string then some other key in the response should not present -
For example if you see below sample json response one of the results[*].source.Descriptions[*].text is empty and at the same node the preview results[*].source.preview is not present
So any straight forward solution in karate which can check that if Descriptions.text is '' then preview should not be present at that node
{
"total": 10,
"count": 10,
"results": [
{
"id": "1",
"source": {
"type": "general",
"Description": [
{
"text": ""
}
]
}
},
{
"id": "2",
"source": {
"type": "general",
"preview": "Your name",
"Description": [
{
"text": "Your name is Karate"
}
]
}
}
]
}
Here you go. Read the docs in case anything is not clear:
* def isValid = function(x){ var desc = x.source.Description[0].text; return desc === '' ? !x.preview : true }
* match each response.results == '#? isValid(_)'

Groovy: How to parse the json specific key's value into list/array

I am new to groovy and trying
1) from the output of prettyPrint(toJson()), I am trying to get a list of values from a specific key inside an json array using groovy. Using the below JSON output from prettyPrint example below, I am trying to create a list which consists only the values of the name key.
My Code:
def string1 = jiraGetIssueTransitions(idOrKey: jira_id)
echo prettyPrint(toJson(string1.data))
def pretty = prettyPrint(toJson(string1.data))
def valid_strings = readJSON text: "${pretty}"
echo "valid_strings.name : ${valid_strings.name}"
Output of prettyPrint(toJson(string1.data))is below JSON:
{
"expand": "places",
"places": [
{
"id": 1,
"name": "Bulbasaur",
"type": {
"grass",
"poison"
}
},
{
"id": 2,
"name": "Ivysaur",
"type": {
"grass",
"poison"
}
}
}
Expected result
valid_strings.name : ["Bulbasaur", "Ivysaur"]
Current output
valid_strings.name : null
The pretty printed JSON content is invalid.
If the JSON is valid, then names can be accessed as follows:
import groovy.json.JsonSlurper
def text = """
{
"expand": "places",
"places": [{
"id": 1,
"name": "Bulbasaur",
"type": [
"grass",
"poison"
]
},
{
"id": 2,
"name": "Ivysaur",
"type": [
"grass",
"poison"
]
}
]
}
"""
def json = new JsonSlurper().parseText(text)
println(json.places*.name)
Basically, use spray the attribute lookup (i.e., *.name) on the appropriate object (i.e., json.places).
I've used something similar to print out elements within the response in ReadyAPI
import groovy.json.*
import groovy.util.*
def json='[
{ "message" : "Success",
"bookings" : [
{ "bookingId" : 60002172,
"bookingDate" : "1900-01-01T00:00:00" },
{ "bookingId" : 59935582,
"bookingDate" : "1900-01-01" },
{ "bookingId" : 53184048,
"bookingDate" : "2019-01-15",
"testId" : "12803798123",
"overallScore" : "PASS" },
{ "bookingId" : 53183765,
"bookingDate" : "2019-01-15T13:45:00" },
{ "bookingId" : 52783312,
"bookingDate" : "1900-01-01" }
]
}
]
def response = context.expand( json )
def parsedjson = new groovy.json.JsonSlurper().parseText(response)
log.info parsedjson
log.info " Count of records returned: " + parsedjson.size()
log.info " List of bookingIDs in this response: " + parsedjson.bookings*.bookingId