String replacement inside json not working with complex objects - karate

I have this Javascript object:
{ person: { name: "john", age: 32 }}
And an endpoint returning:
{
"name": "john",
"age": 32
}
I have this steps:
Given path 'endpoint/'
When method get
Then status 200
And match response ==
"""
{
"name": #(person.name),
"age": #(person.age)
}
"""
This is not working because #(person.name) and #(person.age) both evaluate to null, how can I fix it? (putting them in a new variable is not the fix I'm looking for)

Here you go:
* def data = { person: { name: 'john', age: 32 } }
* def response = { name: 'john', age: 32 }
* match response == data.person
Since you appear to be confused, let me add this (but not recommended because of the above):
* match response == { name: '#(data.person.name)', age: '#(data.person.age)' }

Related

'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 match each on response assertion is failing to identify missing keys in response

I have a match each assertion like below in my code. Just tried creating similar examples as my code, just to explain the issue.
Scenario: Example scenario 1
* def response =
"""
[
{
id: 1,
name: "John",
password: "abc123"
},
{
id: 2,
name: "David",
password: "abc123"
},
{
id: 3,
name: "Mike",
password: "abc123"
},
{
id: 4,
name: "Johny"
}
]
"""
* match each response[*].password contains 'abc123'
Test status : Pass
Password field is missing in object 4(where id=4). Above test is passing for me. I am expecting Karate to fail the test in this case. How can I make my test fail in this case?
Scenario: Example scenario 2
* def response =
"""
[
{
id: 1,
name: "John",
},
{
id: 2,
name: "David",
},
{
id: 3,
name: "Mike",
},
{
id: 4,
name: "Johny"
}
]
"""
* match each response[*].password contains 'abc123'
Test status : Pass
Here, there is no password field at all in response. But my test is passing.
Need a work around to fail these kind of scenarios.
Example 3 :
* def response =
"""
[
{
id: 1,
name: "John",
password: "abc123",
skills :[ "training", "management"
]
},
{
id: 2,
name: "David",
password: "abc123",
skills :[ "training", "management"
]
},
{
id: 3,
name: "David",
password: "abc123",
skills :[ "training", "coding"
]
},
{
id: 4,
name: "David",
password: "abc123",
skills :[ "training", "management"
]
}
]
"""
Considering * match each response contains { password: 'abc123' } format(mentioned by #peter) to check example 1 and 2, what if I want to check skills array having 'training' in each object under response? How can I achieve this?
you can use match each to validate the json schema
https://github.com/intuit/karate#match-each
Note that response[*].password is a JsonPath expression that will return an array of all the password key-values found and will return only 3 in your case.
What you are looking for is this:
* match each response contains { password: 'abc123' }

Un-named JSON array field validation in Karate

I have a un-named JSON array like this from the response and would like to check whether it contains "confirmationNumber": "pqrs" or not. May I know how can I check that in Karate?
[
{
"id": 145,
"confirmationNumber": "abcd"
},{
"id": 723
"confirmationNumber": "pqrs"
}
,{
"id": 7342
"confirmationNumber": "sfeq"
}
]
karate.filter() is good for these situations:
* def response =
"""
[
{
"id":145,
"confirmationNumber":"abcd"
},
{
"id":723,
"confirmationNumber":"pqrs"
},
{
"id":7342,
"confirmationNumber":"sfeq"
}
]
"""
* def fun = function(x){ return x.confirmationNumber == 'pqrs' }
* def found = karate.filter(response, fun)
* match found == '#[1]'
Also see examples of JsonPath: https://github.com/intuit/karate#jsonpath-filters
EDIT: apologies, there is a much simpler way, please read the docs !
* match response contains { id: '#number', confirmationNumber: 'pqrs' }
* def item = { confirmationNumber: 'pqrs' }
* match response contains '#(^item)'

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 }]

Cannot match schema from a file which has nested array [duplicate]

This question already has an answer here:
Karate Tests: How to match contains each nested array response with just one schema
(1 answer)
Closed 1 year ago.
Assume that I have a response-Json look like below
def resJson =
"""
{
"id": 1,
"code": "OU82883",
"features":
[
{
"id": 12,
"class": "OU8811",
"school": "parent",
"course": "abc",
"sortOrder": 123
}
]
}
"""
To be easily manage file to compare, I am placing the expected schema - expected result in a file ("getCourseDetails.txt"), with structure below
{
id: '#number',
code: '#string',
features: ##[{
id: '#number',
class: '##string',
school: '##string',
course: '##string',
sortOrder: '#number'
}
]
}
Then in executed feature file, perform the code as
* json expSchema= read ('../Data/Schema/getCourseDetails.txt')
* match resJson == expSchema
The system informs AssertionFailed Error
To find another way to validate schema, I kept only the structure inside of "features" in "getCourseDetails". The outside of "features", I put into executed feature file. So my code now is:
GetCourseDetails file:
{
id: '#number',
class: '##string',
school: '##string',
course: '##string',
sortOrder: '#number'
}
Feature file:
* json courseDetails= read ('../Data/Schema/getCourseDetails.txt')
* def expSchema = {id: '#number', code: '#string', features: '##[] courseDetails'}
* match resJson == expSchema
There is no error and validate works well, but this approach is not my expected.
I would like to know is there a way to centralize all things in a file, and user just calls the file to validate against actual response's schema
Thank you so much.
I think you are over-engineering your tests, but you can use JS to do advanced set-up and building the schema the way you want, and it will be re-usable. For example:
first.json:
{ "foo": "#string" }
second.json:
{ "value": "#number" }
schema.js:
function() {
var first = read('first.json');
karate.set('second', read('second.json'));
first.bar = '##[] second';
return first;
}
now your feature file can be:
* def schema = call read('schema.js')
* def response = { foo: 'test', bar: [{value: 1}, {value: 2}] }
* match response == schema
Above, if you * print schema you will see:
{
"foo": "#string",
"bar": "##[] second"
}
And if you want a one-liner - * match response == call read('schema.js') should work !