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

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 !

Related

Check for attribute value from JSON response

I am trying to validate the below conditions in the sample response
Based on subjectType attribute if it is either Person or Organization.
If subjectType is Person, check if it has a birthDate attribute
Sample response:
{
"subject": "ABC",
"subjectType": "Person",
"birthDate": "1951-03-07"
},
{
"subject": "ABC",
"subjectType": "Organization"
}
I tried this, but no luck.
def expected = {subjectType: 'Person', birthDate: '#present'}
def schema = { subjectType: '#? _ == "Person" || _ == "Organization"', birthDate: '#($.subjectType == "Person" ? "#present" : "#present")' }
match expected == schema
Any help is appreciated!
There are many answers that give you solutions, please start here:
https://stackoverflow.com/a/50350442/143475
Since I just came up with a new idea to solve this, I'm posting it below. Note that there is no right answer, and there are many, many ways to do what you want.
* def schemas =
"""
{
Person: { subject: '#string', subjectType: 'Person', birthDate: '#string' },
Organization: { subject: '#string', subjectType: 'Organization' }
}
"""
* def response = { "subject": "ABC", "subjectType": "Person", "birthDate": "1951-03-07" }
* def expected = schemas[response.subjectType]
* match response == expected
Also search slack overflow if you want to validate dates later.

'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 - Nested JSON object schema validation causes KarateException

Feature: Test Karate schema validation
Scenario: Test nested json objects
* def response = read('tasks.json')
* def schema = { ab: "##[] string", c: "##[] string" }
* match response ==
"""
{
id: '#string',
name: '#string',
obj1: '#(schema)' ,
obj2: '##(schema)' ,
obj3: '#(schema)' ,
obj4: '#null'
}
"""
Following is json file used (tasks.json)
{
"id": "ad:p2:53456:4634:yu",
"name": "name",
"obj1": {
"ab": [
"test"
],
"c": null
},
"obj2": null,
"obj3": {
"ab": [
"tester"
],
"c": [
"t1", "t2"
]
},
"obj4": null
}
Error: com.intuit.karate.exception.KarateException: javascript evaluation failed: string, ReferenceError: "string" is not defined in at line number 1
I have tried multiple ways like :
obj1: '#(^schema)',
obj1: '#object schema'
but not able to fix the issue.
It should be ##[] #string , read the docs: https://github.com/intuit/karate#schema-validation

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)'

Schema Validation - Karate expression to check if value exists in array

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(_)' }