How we compare xml file and json in feature file in karate framework [duplicate] - json

I need to match and validate my JSON response with that of downstream XML response. Here are sample responses for both.
Note that Json response parameters are is not in-order with XML response.
JSON RESPONSE
"Main": {
"Cd": "ABC",
"descriptionTxt": "Sample Main",
"type": "A",
"codeType": "P",
"dt": "2018-10-15T00:00:00-05:00",
"validity": "3",
"segment": "Personal"
},
"testList": [
{
"code": "123",
"descriptionTxt": "My Description",
"categoryCd": "DUDU"
},
{
"code": "675",
"descriptionTxt": "His Description"
},
{
"code": "345",
"descriptionTxt": "Your Description",
"categoryCd": "BH"
}
]
XML RESPONSE
<S:Body>
<ns4:code>ABC </ns4:code>
<ns5:description>Sample Main</ns5:description>
<ns5:Date>2018-10-15</ns5:Date>
<ns5:Type>A</ns5:Type>
<ns5:codeType>P</ns5:codeType>
<ns5:validity>3</ns5:validity >
<ns5:Segment>PERSONAL </ns5:Segment>
<ns5:unwanted>Unwanted XML Parameter</ns5:unwanted>
<ns4:Test>
<ns5:code>123 </ns5:code>
<ns5:description>My Description</ns5:description>
<ns5:categoryCode>DUDU</ns5:categoryCode>
<ns5:unwanted>Unwanted XML Parameter</ns5:unwanted>
</ns4:Test>
<ns4:Test>
<ns5:code>345 </ns5:code>
<ns5:description>Your Description</ns5:description>
<ns5:categoryCode>BH</ns5:categoryCode>
</ns4:Test>
<ns4:Test>
<ns5:code>675 </ns5:code>
<ns5:description>His Description</ns5:description>
<ns5:unwanted>Unwanted XML Parameter</ns5:unwanted>
</ns4:Test>

It would have been nice if you took the time to post well-formed JSON and XML, but anyway. I'm focusing on the hard problem here, which is to map repeated XML elements to JSON, if you paste the below into a Scenario you can see it work:
* def json =
"""
{
"Main": {
"Cd":"ABC",
"descriptionTxt":"Sample Main",
"type":"A",
"codeType":"P",
"dt":"2018-10-15T00:00:00-05:00",
"validity":"3",
"segment":"Personal"
},
"testList":[
{
"code":"123",
"descriptionTxt":"My Description",
"categoryCd":"DUDU"
},
{
"code":"675",
"descriptionTxt":"His Description"
},
{
"code":"345",
"descriptionTxt":"Your Description",
"categoryCd":"BH"
}
]
}
"""
* def xml =
"""
<ns4:root xmlns:ns4="http://foo.com" xmlns:ns5="http://bar.com">
<ns4:Test>
<ns5:code>123</ns5:code>
<ns5:description>My Description</ns5:description>
<ns5:categoryCode>DUDU</ns5:categoryCode>
<ns5:unwanted>Unwanted XML Parameter</ns5:unwanted>
</ns4:Test>
<ns4:Test>
<ns5:code>345</ns5:code>
<ns5:description>Your Description</ns5:description>
<ns5:categoryCode>BH</ns5:categoryCode>
</ns4:Test>
<ns4:Test>
<ns5:code>675</ns5:code>
<ns5:description>His Description</ns5:description>
<ns5:unwanted>Unwanted XML Parameter</ns5:unwanted>
</ns4:Test>
</ns4:root>
"""
* def list = $xml/root/Test
* def xpath = function(x, p){ try { return karate.xmlPath(x, p) } catch (e) { return '#notpresent' } }
* def fun = function(x){ return { code: xpath(x, '/Test/code'), descriptionTxt: xpath(x, '/Test/description'), categoryCd: xpath(x, '/Test/categoryCode') } }
* def temp = karate.map(list, fun)
* print temp
* print json.testList
* match json.testList contains temp
Mapping the rest of the JSON is an exercise for you. Please refer to the docs. Also see this answer for more ideas: Karate - Match two dynamic responses

Related

Looping through groovy object(List) using each{it} and pass the the elements into a json payload in Jenkins

I have a list containing the name of workspaces in groovy Jenkinsfile. I wrote an each() loop to iterate through the list and use the names in the endpoint below to get the workspace ID from the api response.
def getWorkspaceId() {
def result = []
Listworkspace.each{
def response = httpRequest(
customHeaders: [
[ name: "Authorization", value: "Bearer " + env.BEARER_TOKEN ],
[ name: "Content-Type", value: "application/vnd.api+json" ]
],
url: "https://app.terraform.io/api/v2/organizations/${TF_ORGNAME}/workspaces/$it
)
def data = new JsonSlurper().parseText(response.content)
println ("Workspace Id: " + data.data.id)
result << data.data.id
}
return result
}
After getting the IDs, I want to pass them as part of a json payload.
def buildPayload() {
def workspaceID = new JsonSlurper().parseText(getWorkspaceId())
workspaceID.each{
def payload = """
{
"data": {
"attributes": {
"is-destroy":false,
"message":
},
"type":"runs",
"relationships": {
"workspace": {
"data": [
{"id": "$it", "type": "workspaces"}
]
}
}
}
}
}
"""
return payload
}
Is there a way I can iterate through the list of IDs returned and append each json object for the key "data" after iteration. See the code below
"relationships": {
"workspace": {
"data": [
{"id": "id1", "type": "workspaces"},
{"id": "id2", "type": "workspaces"},
{"id": "id3", "type": "workspaces"}
]
When making the api call, it throws a 400 Bad request error. I tried to print the payload and I found out it attaches the whole list of IDs to the payload.
Any suggestion will be greatly appreciated. Thank you.
def buildPayload() {
def workspaceID = new JsonSlurper().parseText(getWorkspaceId())
workspaceID.each{
def payload = """
{
"data": {
"attributes": {
"is-destroy":false,
"message":
},
"type":"runs",
"relationships": {
"workspace": {
"data": [
[id1, id2, id3]
]
}
}
}
}
}
"""
return payload
}
I'd recommend using the JsonOutput class to make your life easier. In essence, as long as your getWorkspaceId() method is returning a list of ids, you can do something like this:
import groovy.json.JsonOutput
def buildPayload(def ids) {
def payload = [
data: [
attributes: [
"is-destroy": false,
"message" : "",
],
type: "runs",
relationships: [
workspace: [
data: ids.collect {
return [id: it, type: "workspaces"]
}
]
]
]
]
return JsonOutput.toJson(payload)
}
This will take each id in your ids list and build a map where each id is identified by its number and the type: workspaces key pair. This is all then included in the larger payload.

Policy XML to JSON in Azure APIM not converting to proper JSON format

i am consuming wcf service which returns XML response, in Azure APIM i am transforming those into Json response by using the below APIM policy
<xml-to-json kind="direct" apply="always" consider-accept-header="false" />
It works fine until i get xml response as bleow like contains one title in the titles section,
<TitlesResponse>
<Titles>
<Title>
<Name>BookTitle-1</Name>
<Author>BookTitle-2</Author>
</Title>
<Title>
<Name>BookTitle-1</Name>
<Author>BookTitle-2</Author>
</Title>
</Titles>
<Titles>
<Title>
<Name>BookTitle-1</Name>
</Title>
</Titles>
</TitlesResponse>
The json response for the above xml is as below
{
"TitlesResponse": {
"Titles": [
{
"Title": [
{
"Name": "BookTitle-1",
"Author": "BookTitle-2"
},
{
"Name": "BookTitle-1",
"Author": "BookTitle-2"
}
]
},
{
"Title": {
"Name": "BookTitle-1"
}
}
]
}
}
The client expects always Json array in the Title section but it's returning jsonobject when only one title is there.
I tried this in outbound set-body but not working
string xmlContent = context.Response.Body.As<string>(preserveContent: true);
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlContent);
return JsonConvert.SerializeObject(doc);
Do we have any other way to convert to expected Json format from xml in the APIM
I'm not sure if there's a real solution to this problem.
It would be great if JsonConvert accepts also an XSD for serialization.
But I created a workaround:
The Request body is transformed from XML to JSON.
If the datatype is JOject, it will be replaced with an JArray:
<inbound>
<base />
<xml-to-json kind="direct" apply="always" consider-accept-header="false" />
<set-body>#{
var body = context.Request.Body.As<JObject>(true);
JArray titles = body["TitlesResponse"]["Titles"] as JArray;
for (int i = 0; i < titles.Count; i++)
{
JToken item = titles[i]["Title"];
if(item.Type == JTokenType.Object && item.Type != JTokenType.Array )
{
JObject clone = (JObject)item.DeepClone();
titles[i]["Title"] = new JArray();
((JArray)titles[i]["Title"]).Add(clone);
}
}
return body.ToString();
}</set-body>
</inbound>
Response:
{
"TitlesResponse": {
"Titles": [
{
"Title": [
{
"Name": "BookTitle-1",
"Author": "BookTitle-2"
},
{
"Name": "BookTitle-1",
"Author": "BookTitle-2"
}
]
},
{
"Title": [
{
"Name": "BookTitle-1"
}
]
}
]
}
}

How do I capture a specific array element from json response into a gherkin cucumber attribute?

Am trying to capture from below json response, the ghi[0] element which is x and assign it to a variable in my BDD in gherkin/cucumber language but it is complaining it can't read property.
This is how am capturing:
* def xyz = response.results.payload.abc.def.ghi
Response
{
"results": {
"payload": {
"abc": [
{
"def": [
{
"ghi": "x",
},
{
"ghi": "y",
},
{
"ghi": "y",
}
]
}
]
}
}
}
This is what its complaining:
features.blah: [1.1:50] blah.feature:30 - evaluation (js) failed: response.results.payload.abc.def.ghi, javax.script.ScriptException: TypeError: Cannot read property "ghi" from undefined in <eval> at line number 1
That's because your access is wrong. This below works:
* def xyz = response.results.payload.abc[0].def[0].ghi
* match xyz == 'x'
That said, if you are lazy to traverse deeply nested data, you can do this:
* def xyz = get[0] $..ghi
* match xyz == 'x'
Please read the docs, it will save you time :) https://github.com/karatelabs/karate#get

Ruby: How to parse json to specific types

I have a JSON that I want to parse in Ruby. Ruby is completely new to me, but I have to work with it :-)
Here is my litte snippet, that should do the parsing:
response = File.read("app/helpers/example_announcement.json")
JSON.parse(response)
this works pretty fine. The only downside is, I do not know the properties at the point where I use it, it is not typesafe. So I created the objects for it
class Announcements
##announcements = Hash # a map key => value where key is string and value is type of Announcement
end
class Announcement
##name = ""
##status = ""
##rewards = Array
end
And this is how the json looks like
{
"announcements": {
"id1" : {
"name": "The Diamond Announcement",
"status": "published",
"reward": [
{
"id": "hardCurrency",
"amount": 100
}
]
},
"id2": {
"name": "The Normal Announcement",
"players": [],
"status": "published",
"reward": []
}
}
}
So I tried JSON parsing like this
response = File.read("app/helpers/example_announcement.json")
JSON.parse(response, Announcements)
But this is not how it works^^can anybody help me with this?

Iterate through two loops when building the JSON String

I am invoking a restful service to get the available documents on the the server where I am getting the JSON as s response. I am building the JSON String with the JSONBuilder so when invoking the this link
http://localhost:8080/httpConnector/Rest/Documents?Accept=application/json
I am getting the JSON String below:
{
"results": [
{
"result": {
"name": "Test traisy",
"version": "sdvdsv",
"author": "sdvdsv"
}
},
{
"result": {
"name": "Jaspersoft Ultimate guide",
"version": "sdfdsv",
"author": "sdvdsv"
}
},
{
"result": {
"name": "Dohrn",
"version": "12.19.00",
"author": "sdfdsf"
}
}
]
}
Code
String accept = getValue("Accept");
accept = "application/xml";
if ("application/xml".equals(accept)){
builder=new groovy.xml.MarkupBuilder(writer);
}else{
builder=new groovy.json.JsonBuilder();
}
builder{
results foaList.collect{
[
//Here I want to loop through the otaList to do something like that "ota.getName(), foa.getFlexiObject().getByString(ota.getName())"
result: [
name: it.getFlexiObject().getByString("name"),
version: it.getFlexiObject().getByString("version"),
author: it.getFlexiObject().getByString("author")
]
]
}
}
Now I want to add the properties programatically. Therefore I have to loop through the otaList to do something like that
builder.'results'() {
for(FlexiObjectAttachment foa: foaList){
for(ObjectTypeAttribute ota : otaList){
param.put(ota.getName(), foa.getFlexiObject().getByString(ota.getName()));
}
result(param);
}
}
this version just works for the xml respose.
What you can try is to do the combination of foa and ota directly in your collect call.
That way your initially created dict would have the correct structure.
Something like the example below
def foaList = [1, 2, 3, 4]
def otaList = ['A', 'B', 'C']
foaList.collect { foa ->
result = [name: "Name$foa", version: "v$foa", author: "Author$foa"]
otaList.each { ota -> result[ota] = "$ota$foa" }
[ result: result ]
}