I have the following response coming from a request
[
{
"id": 3767,
"sellerName": "abc",
"siteActivity": [
{
"siteId": -1,
"siteName": "example.com",
"categories": [
{
"categoryId": 79654,
"parentId": null,
"name": "Photo & Picture Frames",
"siteName": null,
"channelType": null
},
{
"categoryId": 114397,
"parentId": null,
"name": "Chests of Drawers",
"siteName": null,
"channelType": null
},
{
"categoryId": 11707,
"parentId": null,
"name": "Jewellery Boxes",
"siteName": null,
"channelType": null
},
{
"categoryId": 45505,
"parentId": null,
"name": "Serving Trays",
"siteName": null,
"channelType": null
}
]
}
]
},
{
"id": 118156,
"sellerName": "xyz",
"siteActivity": [
{
"categoryId": 45505,
"parentId": null,
"name": "Serving Trays",
"siteName": null,
"channelType": null
}
]
}
]
Now, I need to extract "id" values and "categoryId" values and send them as list in the next request body.
Currently, I am using JSON Path Extractor with the expression
$.[*].id
to get my hand on all ids and
$.[*].siteActivity.[categoryId]
for category ids.
Next, I want to use the above values and send them as parameters in request body.
Currently, I am able to extract only one id with
$.[0].id
and then assigning it to variable "id" and using the following in request body
{"ids":[{"id":"${id}"}]}
but I want to be able to send
{"ids":[{"id":"${id}"},{"id":"${id2}"}....]}
There is no limit on how many ids can be there, so I cannot hardcode and need something dynamic to do the aggregation. What kind of processor can help me here? Please add some example if you can.
I believe that you should be able to use Beanshell PostProcessor for building the request.
Given your sample data your $.[*].id JSONPath Expression should return the following values:
id=[3767,118156]
id_1=3767
id_2=118156
So basically you need to:
Determine "id" count
Populate dynamic JSON Object to send
Store it to JMeter variable for later use
In order to do so add a Beanshell PostProcessor after JSONPath Extractor and put the following code into its "Script" area
import net.sf.json.JSONArray;
import net.sf.json.JSONObject; // necessary imports
JSONObject data2Send = new JSONObject();
JSONArray array = new JSONArray(); // instantiate JSON-related classes
int idCount = vars.get("id").split(",").length; // get "id" variables count
for (int i = 1; i <= idCount; i++) { // for each "id" variable
JSONObject id = new JSONObject(); // construct a new JSON Object
id.put("id", vars.get("id_" + i));// with name "id" and value id_X
array.add(id); // add object to array
}
data2Send.put("ids",array); // add array to "ids" JSON Object
vars.put("myJSON", data2Send.toString()); // store value as "myJSON" variable
You can refer to your {"ids":[{"id":"3767"},{"id":"118156"}]} data as ${myJSON} where required.
The approach will play for any number of "id" variables.
References:
Welcome to Json-lib
How to use json-lib
Json-lib JavaDoc
How to use BeanShell: JMeter's favorite built-in component
Related
At the moment we get JSON back with references to objects that were rendered previous. We expect that JSON objects are full rendered.
When we get the result of a function in a controller we get a $ref id in stead of the full JSON object. For example:
This is what we expect:
"TaxCode": {
"Name": "Hoog (21%)",
"Rate": 21,
"CreatedOn": "2020-01-06T14:45:28",
"ModifiedOn": "2020-01-23T09:11:27.653",
"DeletedOn": null,
"Id": 1,
"SqlLabelTemplate": null,
"Label": "Hoog (21%)"
},
This is what we get:
"TaxCode": {
"$ref": "15"
},
This is the config setting we currently have:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
We tried different values in the config with no result.
Somehow there was a config added to the WebApiConfig.cs. So the config in the global.asax was overwritten.
After removing this line from the webapiconfig.cs:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
And adding the following config to the Global.asax:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;
solved all issues.
I have a JSON response that looks like this:
{
"results": [
{
"entityType": "PERSON",
"id": 679,
"graphId": "679.PERSON",
"details": [
{
"entityType": "PERSON",
"id": 679,
"graphId": "679.PERSON",
"parentId": 594,
"role": "Unspecified Person",
"relatedEntityType": "DOCUMENT",
"relatedId": 058,
"relatedGraphId": "058.DOCUMENT",
"relatedParentId": null
}
]
},
{
"entityType": "PERSON",
"id": 69678,
"graphId": "69678.PERSON",
"details": [
{
"entityType": "PERSON",
"id": 678,
"graphId": "678.PERSON",
"parentId": 594,
"role": "UNKNOWN",
"relatedEntityType": "DOCUMENT",
"relatedId": 145,
"relatedGraphId": "145.DOCUMENT",
"relatedParentId": null
}
]
}
The problem with this JSON response is that $.results[0] is not always the same, and it can have dozens of results. I know I can do individual JSON Assertion calls where I do the JSON with a wild card
$.results[*].details[0].entityType
$.results[*].details[0].relatedEntityType
etc
However I need to verify that both "PERSON" and "DOCUMENT" match correctly in the same path on one api call since the results come back in a different path each time.
Is there a way to do multiple calls in one JSON Assertion or am I using the wrong tool?
Thanks in advance for any help.
-Grav
I don't think JSON Assertion is flexible enough, consider switching to JSR223 Assertion where you have the full flexibility in terms of defining whatever pass/fail criteria you need.
Example code which checks that:
all attributes values which match $.results[*].details[0].entityType query are equal to PERSON
and all attributes values which match $.results[*].details[0].relatedEntityType are equal to DOCUMENT
would be:
def entityTypes = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(), '$.results[*].details[0].entityType').collect().find { !it.equals('PERSON') }
def relatedEntityTypes = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(), '$.results[*].details[0].relatedEntityType').collect().find { !it.equals('DOCUMENT') }
if (entityTypes.size() != 1) {
SampleResult.setSuccessful(false)
SampleResult.setResponseMessage('Entity type mismatch, one or more entries are not "PERSON" ' + entityTypes)
}
if (relatedEntityTypes.size() != 1) {
SampleResult.setSuccessful(false)
SampleResult.setResponseMessage('Entity type mismatch, one or more entries are not "DOCUMENT" ' + relatedEntityTypes)
}
More information:
SampleResult class JavaDoc
Groovy: Working with collections
Scripting JMeter Assertions in Groovy - A Tutorial
I am trying to add a new bloc to my JSON
I have this JSON that I got after a GET :
{
"name": "John",
"age": 30,
"Deleted": false
}
What I want to do is to add a block trips to this Json using RobotFrameWOrk to get this result:
{
"name": "John",
"age": 30,
"trips": [
{
"dateTime": "2020-01-24T15:28:29.7073727Z",
"FirstName": "John",
"Comment": "TestMe"
}
],
"Deleted": false
}
My questions are:
The object Trips doesn't exist I have to create it manually
and then I should add this object to my JSON after the age and before Deleted
${JsonFinall}= Add String ${FirstJson} ${BlockTrips}
Log ${JsonFinall}
I imagine it would be something like that but I am blocked on the first step I don't know how to create and fill the object trips?
Do you think that I have to work with Regex?
Thanks for your help
***********************EDIT**********
I tried with add object to json : `# Bloc ActionR
${jsonFinall}= Add Object To Json ${JsonAvecAR} Course/AR.txt`
the file AR.txt is the file where I put my object trips :
"trips": [
{
"dateTime": "2020-01-24T15:28:29.7073727Z",
"FirstName": "Alicia",
"Comment": "TestMe"
}
],[![enter image description here][1]][1]
I am new to Ember and JSON. I want to parse a JSON object that is below with typeahead library
and access nested object values by searching their keys.
I have this Json format:
return [
{
"id": 1,
"category_name": "Supermarket",
"category_description": "SUPER MARKET",
"image_url": "",
"merchants": [
{
"name": "CARREFOUR",
"id": 12,
"merchant_type_id": 1,
"merchant_type_description": "Gold",
"merchant_redeption_rate": 0.002500,
"image_url": "https://jpg",
"branches": [
{
"id": 123456,
"latitude": 37.939483,
"area": "ΑΓ. ΔΗΜΗΤΡΙΟΣ",
"zip": "12345"
},
{
"id": 4567890,
"longitude": 23.650622,
"area": "ΑΓ. ΙΩΑΝΝΗΣ ΡΕΝΤΗΣ",
"zip": "12345"
}
]
},
{
"name": "CAFCO",
"id": 13,
"merchant_type_id": 3,
"merchant_type_description": "None",
"merchant_redeption_rate": 0.002500,
"image_url": "https:.jpg",
"branches": [
{
"id": 127890,
"latitude": 38.027870,
"area": "ΠΕΡΙΣΤΕΡΙ",
"zip": "12345"
}
]
}
]
},
{
"id": 2,
"category_name": "Πολυκαταστήματα",
"category_description": "ΠΟΛΥΚΑΤΑΣΤΗΜΑ",
"image_url": "",
"merchants": [
{
"name": "AGGELOPOYLOS CHR.",
"id": 15,
"merchant_type_id": 2,
"merchant_type_description": "Silver",
"merchant_redeption_rate": 0.002500,
"image_url": "https://www.nbg.gr/greek/retail/cards/reward-programmes/gonational/PublishingImages/aggelopoulos.jpg",
"branches": [
{
"id": 234780,
"latitude": 35.366118,
"longitude": 24.479461,
"address": "ΕΘΝ. ΜΑΚΑΡΙΟΥ 9 & ΕΛ. ΒΕΝΙΖΕΛΟΥ 1",
"area": "Ν. ΦΑΛΗΡΟ",
"zip": "12345"
}
]
}
]
}
];
--------------------------Updated----------------------------
For example, i want to search using typeahead the name of merchants and when the letter we write to search matches the name of merchants it will appear the corresponding category_name and backwards.
Example -> when i keyboard the s it will appear :
Category : Supermarket,
Name: CARREFOUR
Name: CAFCO
And the same output on the dropdown of search when i keyboard the letter c.
Any help?
New Jsbin example
The simplest way (in my mind) to get this to work is to create a computed property that will contain an array of latitudes. But how do we get there?
To get to latitude, you need to go through array of merchants and then array of branches. Being that this will be across multiple elements, you are going to end up with "array of arrays" type data structure, which is annoying to deal with. So, to simplify this, we can create a simple flatten function as follows:
flatten: function(origArray){
var newArr = [];
origArray.forEach(function(el) {
el.forEach(function(eachEl){
newArr.push(eachEl);
});
});
return newArr;
},
In addition to our function above, Ember already provides us with many other useful functions that can be used on arrays (see here). One of those is mapBy(property) which transforms an array into another array only keeping the values of the property we specified.
So, to create a lats (for latitudes) property, we can just do this:
lats: function(){
var merchantsArr = this.get('model').mapBy('merchants');
merchantsArr = this.flatten(merchantsArr);
var branchesArr = merchantsArr.mapBy('branches');
branchesArr = this.flatten(branchesArr);
return branchesArr.mapBy("latitude").compact();
}.property('model')
Above, I am basically using mapBy, flatten (see above) and compact which
Returns a copy of the array with all null and undefined elements removed.
Once you have the lats property with all the necessary data, the rest is easy.
Your call to component becomes:
{{x-typeahead data=lats name='category_name' selection=myColor}}
Note lats instead of model you originally were passing into the component.
And now, to access the value of data property in the component, you do
`this.get('data')`
which you can just pass in as the source like so:
source: substringMatcher(self.get('data'))
Working solution here
Update
Updating my answer based on your updated question.
OK, so this is getting a little more complicated. You now need more than just one property (latitude) from the object. You need category_name and merchant name.
In addition to mapBy, which just grabs one property out of array, Ember also has map which lets you transform the array into pretty much anything you want to:
lats: function(){
var merchantsArr = this.get('model').map(function(thing){
var category_name = thing.category_name;
return thing.merchants.map(function(merchant){
return {
"name": merchant.name,
"category": category_name
};
});
});
merchantsArr = this.flatten(merchantsArr);
return merchantsArr;
}.property('model')
The code above looks complicated, but it's basically just returning an array of top level objects' merchants accompanied by category_name. Since this is an array of arrays, we will need to flatten it.
Then, inside the component, we need to keep in mind that we are not just passing in an array of strings, but rather we are passing in an array of objects. Therefore, we need to look through object's properties (name and category) for a match
$.each(strs, function(i, str) {
if (substrRegex.test(str.name) || substrRegex.test(str.category)) {
matches.push(str);
}
});
Lastly, to actually display both category and merchant name, you need to tell Typeahead how to do that:
templates: {
suggestion: Handlebars.compile('<p>{{name}} – {{category}}</p>')
}
Working solution here
how do I loop through this json object to get each item value? I know this is easy but I need to undestand why there is two brackets ([]) in the first and end of this json object.
[// I'm talking about this
[
{
"id": 2,
"title": "xxxxxxxxx",
"author": "mike123",
"postdate": "March 12, 2013 at 6:46 pm",
"postdatecreation": "2013-03-12",
"posteditdate": null,
"postcontent": "eeeeee",
"userID": 34
}
]
]// and this
if I remove them the json still remain valid.
you can loop through your json object using $.each loop. here is the fiddle:
http://jsfiddle.net/Ay2UB/
here results is an array of array of an object. i've passed that object by accessing index
results[0] will give you an array
results[0][0] will give you object
code below:
var results=[
[
{
"id": 2,
"title": "xxxxxxxxx",
"author": "mike123",
"postdate": "March 12, 2013 at 6:46 pm",
"postdatecreation": "2013-03-12",
"posteditdate": null,
"postcontent": "eeeeee",
"userID": 34
}
]
]
$.each(results[0][0],function(key, value){
alert(value);
});
$.each can be used to loop through array or objects follow below link for more information:
http://api.jquery.com/jQuery.each/
Hope it helps. please correct me if I'm wrong.