Unable to update dynamic JSON element in called feature [duplicate] - karate

I have a JSON file as given below:
{
"lastname": {
"displayName": "lastname"
},
"#(dynamicKey)": {
"displayName": "#(dynamicKey)"
}
}
When I try to read the file, the key and values are not getting updated but when I use JSON like below, value got replaced by the def values. If I give dynamic key both key and value are not getting updated. :-(
{
"lastname": {
"displayName": "lastname"
},
"someKey": {
"displayName": "#(dynamicKey)"
}
}
Could you please help me on how to replace dynamic key and value?

This is how you can handle dynamic keys. The #(dynamicKey) embedded-expression approach will not work.
* def dynamicKey = 'bar'
* def test = { someKey: 'foo' }
* test[dynamicKey] = 'baz'
* match test == { someKey: 'foo', bar: 'baz' }

Related

Karate - How change key name in JSON

I have the following JSON. I want to change the keyName 'freeDelivery' to 'isFreeDelivery' but I can't figure out how to do it.
{
"result": [
{
"deliverySlots": [
{
"id": "2DNN",
"date": "2022-04-05",
"freeDelivery": false,
"label": "All day delivery 08:30am to 5pm",
"price": "£5.00",
"fullSlotId": "2DNN"
},
{
"id": "2DPM",
"date": "2022-04-05",
"freeDelivery": false,
"label": "Afternoon 12pm to 5pm",
"price": "£10.00",
"fullSlotId": "2DPM"
}
]
},
{
"deliverySlots": [
{
"id": "2DNN",
"date": "2022-04-06",
"freeDelivery": false,
"label": "All day delivery 08:30am to 5pm",
"price": "£5.00",
"fullSlotId": "2DNN"
},
{
"id": "2DPM",
"date": "2022-04-06",
"freeDelivery": false,
"label": "Afternoon 12pm to 5pm",
"price": "£10.00",
"fullSlotId": "2DPM"
}
]
}
]
}
I've looked at the following pages but still can't figure out how to do it. Do I have to do a transorm or is there an easier way?
https://github.com/karatelabs/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/js-arrays.feature
https://github.com/karatelabs/karate#json-transforms
Here you go:
* def payload = { before: 'foo' }
* remove payload.before
* payload.after = 'bar'
* match payload == { after: 'bar' }
Instead of remove this will also work (using pure JS):
* eval delete payload.before
EDIT: after seeing the comments, I would treat this as a JSON transform.
* def payload = { before: 'foo' }
* def fun = function(x){ var res = {}; res.after = x.before; return res }
* def result = fun(payload)
* match result == { after: 'foo' }
I'm sure now you'll want to "retain" all the existing data. Fine, here you go:
* def payload = { before: 'foo' }
* def fun = function(x){ var res = x; res.after = x.before; delete res.before; return res }
* def result = fun(payload)
* match result == { after: 'foo' }
And you already know that you can run a transform on all array elements like this:
* def result = karate.map(someArray, fun)
Please note that you can create 2 or 3 transforms - and "nest" them.

'match each' one element in the array [duplicate]

This question already has an answer here:
Using match each contains for json array items assertion
(1 answer)
Closed 1 year ago.
My question about selective asserting with 'match each'.
Below is a sample json body:
* def data =
"""
{
"companies": [
{
"companyDetails": {
"name": "companyName",
"location": {
"address": "companyAddress",
"street": "companyStreet"
}
}
},
{
"companyDetails": {
"name": "companyName",
"location": {
"address": "companyAddress",
"street": "companyStreet"
}
}
}
]
}
"""
How can we assert whether each 'companyDetails' object in the response contains a certain element, e.g. name only?
* match each data.companies contains { companyDetails: { name: '#notnull' } }
When I use above step, this returns below error:
$[0] | actual does not contain expected | all key-values did not match, expected has un-matched keys
So, is there any way we can assert only one field inside this object? For example, assert whether each companyDetails object contains name, but ignores the other elements such as location? Thanks
This will work:
* match each data.companies == { companyDetails: { name: '#notnull', location: '#notnull' } }
This will also work:
* match data.companies contains deep { companyDetails: { name: '#notnull' } }
Sometimes it is better to transform the JSON before a match:
* match each data..companyDetails contains { name: '#notnull' }

Karate - Reading data from json file and assing it to a dynamically generated request

I have following data.json file:
{
"ids": {
"id": "a2mx8m6yvksgu3605c7c1a61d"
},
"second": {
"name": "test2"
},
"third": {
"name": "test3"
}
}
I did fetch a variable for the id from the json.
* def id = data.ids.id
I want to use this variable id (defined above) to a request.
Request defined below is dynamically being sent to the xml file i.e xml request is being generated with but the below doesnt work when i try to pass the variable id.
This however works when i hardcode the id value.
* def ARG = {attr: [ { regex: '#(ids)', value: '<id>"#(id)"</id>'} ] }
Please help me how can i pass the data being read from json to the above line of code.
Read the docs: https://github.com/intuit/karate#rules-for-embedded-expressions
* def id = 'foo'
* def val = '<id>' + id + '</id>'
* def arg = { value: '#(val)' }
* match arg == { value: '<id>foo</id>' }

Karate: when I want to set value to $..somewhereInJsonPath I get Path must not end with a '

I want to update a value of somewhereInJsonPath field in my JSON file.
I am using for this: * set myBody $..someWhereInJsonPath = 'AAA'. And when I run test I get: Path must not end with a '.'
But when I am using * set myBody $..firstHere.someWhereInJsonPath = 'AAA' it is working.
I think in first case, where we want to update first value in $.., it must working too.
To clarify:
For example we have JSON:
{
"store": {
"book": [
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"something": 12.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
And when I do: $.store.book[0].something = 13 it is working.
BUT when I do: $..something = 13 it is not working.
Why? And how can I update this?
At http://jsonpath.com/ when I want to find $..something it is find this value. But when I use $..something in karate it is not working.
Realted with https://stackoverflow.com/questions/54928387/karate-jsonpath-wildcards-didnt-work-or-partly-didnt-work
Actually the set command is not really designed for JsonPath wildcards. For example $[*].foo or $..foo are examples of wildcards. And $[0].foo, $.foo or response.foo are pure JS expressions.
So please stick to pure JS expressions like this. Here below, set is interchangeable with eval which is more useful in case you want to use dynamic / variables for e.g. * eval response[foo] where foo is a string.
* def response = { foo: { somePath: 'abc' } }
* eval response.foo.somePath = 'xyz'
* match response == { foo: { somePath: 'xyz' } }
If you really do need to do "bulk" updates, use a transform function:
* def response = [{}, {}]
* def fun = function(x, i){ return { foo: 'bar', index: ~~(i + 1) } }
* def res = karate.map(response, fun)
* match res == [{ foo: 'bar', index: 1 }, { foo: 'bar', index: 2 }]

How to access a particular set of keys in array of Json values which i get as response?

For a particular API , I get a response which is similar to the following .
[
{ "name":"Ford", "model":"Mustang" },
{ "name":"BMW", "model": "320" },
{ "name":"Fiat", "model": "500" }
]
I want to store the values for the key 'name' in a separate variable .
Please read the documentation on using JsonPath carefully: https://github.com/intuit/karate#get
Here is an example which works with your data:
* def response =
"""
[
{ "name":"Ford", "model":"Mustang" },
{ "name":"BMW", "model": "320" },
{ "name":"Fiat", "model": "500" }
]
"""
* def names = $[*].name
* match names == ['Ford', 'BMW', 'Fiat']