Is possible to match each element of a nested array response (using contains) using just one schema?
I have a set of yml files with request params and response schemas, like this one:
response:
appId: '#string'
attributes: '#array'
login: '#string'
permissions: '#array'
metadata:
roles: '##array'
userData:
description: '#string'
employeeId: '#string'
employeeNumber: '##string'
id: '#string'
login: '#string'
mail: '#string'
name: '#string'
and then, in a reusable feature:
* def req = read(<testDataFile>)
* match response contains req.response
I can match nested objects with just one schema but I'm not sure if it's possible use the schema to match nested arrays
maybe like:
response:
appId: '##string'
attributes: '##array'
attributes[*]:
key: '#string'
or any other expression
Thanks a lot
You can't do this with a single "schema" and you have to declare the repeating element separately, as a Karate variable: https://github.com/intuit/karate#schema-validation
* def foo = { a: '#number' }
* def bar = { baz: [{ a: 1 }, { a: 2 }, { a: 3 }] }
* match each bar.baz == foo
* match bar == { baz: '#[] foo' }
Related
Is possible to match each element of a nested array response (using contains) using just one schema?
I have a set of yml files with request params and response schemas, like this one:
response:
appId: '#string'
attributes: '#array'
login: '#string'
permissions: '#array'
metadata:
roles: '##array'
userData:
description: '#string'
employeeId: '#string'
employeeNumber: '##string'
id: '#string'
login: '#string'
mail: '#string'
name: '#string'
and then, in a reusable feature:
* def req = read(<testDataFile>)
* match response contains req.response
I can match nested objects with just one schema but I'm not sure if it's possible use the schema to match nested arrays
maybe like:
response:
appId: '##string'
attributes: '##array'
attributes[*]:
key: '#string'
or any other expression
Thanks a lot
You can't do this with a single "schema" and you have to declare the repeating element separately, as a Karate variable: https://github.com/intuit/karate#schema-validation
* def foo = { a: '#number' }
* def bar = { baz: [{ a: 1 }, { a: 2 }, { a: 3 }] }
* match each bar.baz == foo
* match bar == { baz: '#[] foo' }
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' }
Sample Response
{
"data": [
{
"name": "DJ",
"status": "ACTIVE"
}
]
}
Sample Feature File
#ignore
Feature: Sample
#smoke
Scenario: Karate expression to check if value exists in array
Given url url
And path '/test'
When method GET
Then status 200
And def users = response.data
And def possibleStatus = ["ACTIVE", "INACTIVE"]
And def schema =
"""
{
name: '#string',
status: ?
}
"""
And match each users contains schema
Is there a way to check if status is either ACTIVE or INACTIVE using karate expression ?
NOTE: It can be achieved by writing custom JS function.
* def statuses = [ 'ACTIVE', 'INACTIVE' ]
* def response = [{ name: 'DJ', status: 'ACTIVE' }, { name: 'PJ', status: 'INACTIVE' }]
* match each response == { name: '#string', status: '#? statuses.contains(_)' }
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 !
I can have a response as:
{ id: '123', name: 'foo' }`
if the user has not a dog
OR
{ id: '123', name: 'foo', dog: {id: '123', color: 'brown'} }`
if the user has a dog.
In my feature I have:
* def schema = { id: '#string', name: '#string', dog: {id: '#string', color: '#string'} }`
* match response == schema
The prb is that if I have a user without dog in response, I have this error:
path: $[0].dog, actual: null, expected: {id=#string, label=#string}, reason: actual value is null
How can I check the attribute 'dog' in my schema?
Thanks
It is not possible to do this in one step, also refer to the doc on schema validation:
* def dogSchema = { id: '#string', color: '#string' }
* def schema = { id: '#string', name: '#string', dog: '##object' }
* def response1 = { id: '123', name: 'foo' }
* match response1 == schema
* match response1 contains { dog: '##(dogSchema)' }
* def response2 = { id: '123', name: 'foo', dog: { id: '123', color: 'brown' } }
* match response2 == schema
* match response1 contains { dog: '##(dogSchema)' }
Edit: well this is embarassing, I realized this trick is not well documented:
* def dogSchema = { id: '#string', color: '#string' }
* def schema = { id: '#string', name: '#string', dog: "#('##(dogSchema)')" }
* def response1 = { id: '123', name: 'foo' }
* match response1 == schema
* def response2 = { id: '123', name: 'foo', dog: { id: '123', color: 'brown' } }
* match response2 == schema
Edit2: this will be improved in the next version: https://github.com/intuit/karate/issues/248