Karate - Validating schema for the entire json response - karate

I am working on validating the entire json response for a GET request using Karate.
Here is the sample json response from the request (I have shown only two elements for items )
[
{
"items": [
{
"createdById": "ADMIN",
"createdByName": "ADMIN",
"changedByName": "ADMIN",
"oid": "121212fgfg2123",
"links": {
"self": {
"href": "/internal/organiz/12345"
},
"subcom": []
},
"name": "NewETLTesting"
},
{
"createdById": "ADMIN",
"createdByName": "ADMIN",
"changedByName": "ADMIN",
"oid": "1212dfffg45",
"links": {
"self": {
"href": "/internal/organiz/5a6e0"
},
"subcom": []
},
"name": "FromKarateModified"
}
]
}
]
Here is how I am trying to validate:
And match response.*.* ==
"""
{
"createdById" : '#string',
"createdByName" : '#string',
"changedByName" : '#string',
"oid" : '#string',
"links" : '#object',
"name" : '#string'
}
"""
However, I am getting an assertion error:reason: actual value is not map-like. If I try putting square brackets around the curly braces, I get reason: actual and expected arrays are not the same size. Also I tried to play around with response like $.[*]. etc but couldn't get it working.
Thanks in advance!!

You need to pay attention to your JSON structure and also understand JsonPath better. You can cut and paste the below and see it working:
* def response =
"""
[
{
"items": [
{
"createdById": "ADMIN",
"createdByName": "ADMIN",
"changedByName": "ADMIN",
"oid": "121212fgfg2123",
"links": {
"self": {
"href": "/internal/organiz/12345"
},
"subcom": []
},
"name": "NewETLTesting"
},
{
"createdById": "ADMIN",
"createdByName": "ADMIN",
"changedByName": "ADMIN",
"oid": "1212dfffg45",
"links": {
"self": {
"href": "/internal/organiz/5a6e0"
},
"subcom": []
},
"name": "FromKarateModified"
}
]
}
]
"""
And match each response[0].items ==
"""
{
"createdById" : '#string',
"createdByName" : '#string',
"changedByName" : '#string',
"oid" : '#string',
"links" : '#object',
"name" : '#string'
}
"""

The below Schema will validate the entire reponse properly
* def refSubcom = {<object schema>}
* def refself = {href : '#string'}
* def refLinks = {self : '#object refself', subcom:'##[] refSubcom'}
* def optionalItemArr =
"""
{
createdById:'#string',
createdByName:'#string',
changedByName:'#string',
oid: '#string',
links: '#object refLinks',
name:'#string'
}
###
* def itemData =
"""
{
item : '##[] optionalItemArr'
}
"""
* def reponseSchema = '##object itemData'
* def SuccessSchema = '##[] reponseSchema'
you can refer the below link : karate : Complex JSON Schema matching

Related

Karate- How can I pass a param as a key?

I have the following case and need to use firstKeyStr as a key, my code now is seeing "#firstKeyStr" as the key not the one stored in it
Code
Given path '/api/v1/sites'
When method get
Then status 200
And match response.success == true
And match response.data == "#object"
* def keys = karate.keysOf(response.data)
* def firstKeyStr = keys[0]
And match response.data."#firstKeyStr" == "#object"
Json Response Body
{
"success": true,
"data": {
"5ef34d0ca5a3c56ae14d2a23": {
"devices": [
"5f03192010a47f3e5b714193"
],
"groups": [
"5f0d9f30ef89e22778a2d230"
],
"users": [],
"triggers": [],
"alerts": [
"5f0d92b967bac60b84d3989b"
],
"name": "test",
"country": "US",
]
}
}
I'm looking for a way to pass this dynamic key (5ef34d0ca5a3c56ae14d2a23) in this line (And match response.data."#firstKeyStr" == "#object")
Since you are new to stack overflow, please read the following to best get help:
https://stackoverflow.com/help/how-to-ask
https://stackoverflow.com/help/someone-answers
As Peter said, your JSON is not well formed and the order of keys is not guaranteed (unless you have just a single key). The following code should get you going.
Sample Code:
Feature: firstKey
Scenario: firstKey
* def resp =
"""
{
"success": true,
"data": {
"5ef34d0ca5a3c56ae14d2a23": {
"devices": [
"5f03192010a47f3e5b714193"
],
"groups": [
"5f0d9f30ef89e22778a2d230"
],
"users": [],
"triggers": [],
"alerts": [
"5f0d92b967bac60b84d3989b"
],
"name": "test",
"country": "US"
}
}
}
"""
And match resp.data == "#object"
* def keys = karate.keysOf(resp.data)
* def firstKeyStr = keys[0]
* print firstKeyStr
* print (resp.data[firstKeyStr])
And match (resp.data[firstKeyStr]) == "#object"
Use round brackets so that JS is used instead of JsonPath:
* def response = { data: { a: 1, b: 2 } }
* def keys = karate.keysOf(response.data)
* def first = keys[0]
* match (response.data[first]) == 1

Karate: Is it possible to compare two service responses & exclude some keys in comparison

I am trying to compare responses from two service call(for Migration project) using Karate.
Is it possible to exclude or ignore some keys while comparing whole response at one go for following cases:
1)There are few elements in response where the values is different(marked in bold).
2)There are few elements which is not present in one response but present in other(marked in bold).
Service 1 response -
{
"userKey": "string",
"enabled": true,
"locked": true,
"profile": {},
"roles": [
{
"roleKey": 3,
"name": "Role",
**"links": []**
}
],
"links": [
{
"rel": "self",
**"href": "https://starhub1.com"**
},
{
"rel": "self",
**"href": "https://singtel1.com"**
}
]
}
Service 2 response -
{
"userKey": "string",
"enabled": true,
"locked": true,
"profile": {},
"roles": [
{
"roleKey": 3,
"name": "Role"
}
],
"links": [
{
"rel": "self",
**"href": "https://starhub22.com"**
},
{
"rel": "self",
**"href": "https://singtel22.com"**
}`enter code here`
]
}
Yes Karate is pretty good at this. Just do a transform on one payload before comparison.
Please see this answer for details: https://stackoverflow.com/a/53120851/143475
For your specifc example maybe all you need to do is change one "side" to #string and then do the comparison.
* def response1 = { foo: 'hello' }
* def response2 = { foo: 'world' }
* response2.foo = '#string'
* match response1 == response2

Karate: Get all users and delete with the reference id

After my tests are completed, I would like to delete all the users that were created. I am able to delete one user at a time. Can we do this using conditional logic?
Feature file:
Given path 'users'
And header Authorization = authId
And header Accept = 'application/json;version=2'
When method Get
Then status 200
Then print 'Response Time: '+ responseTime + ' milliseconds'
* def resp = $
* def size = karate.sizeOf(resp)
* print 'Number of users: ' + size
This gives me below response:
[
{
"firstName": "Edit User",
"lastName": "API Test",
"emailAddress": "edituserapitesting#gmail.com",
"ada": true,
"isDeleted": false,
"alerts": [],
"links": [
{
"href": "https://someurl/api/users/0219360d-5ca6-42af-9e9c-10be1e32d219",
"rel": "self"
}
]
},
{
"firstName": "Create",
"lastName": "Test",
"emailAddress": "api#test.com",
"ada": true,
"isDeleted": false,
"alerts": [],
"links": [
{
"href": "https://someurl/api/users/5e3c9be1-2863-4a2d-85e9-966582b127ac",
"rel": "self"
}
]
},
{
"firstName": "Create",
"lastName": "Test",
"emailAddress": "api#test.com",
"ada": true,
"isDeleted": false,
"alerts": [],
"links": [
{
"href": "https://someurl/api/users/b6feb126-bca2-43e6-ba2d-87aaae81fef0",
"rel": "self"
}
]
},
{
"firstName": "Create",
"lastName": "Test",
"emailAddress": "api#test.com",
"ada": true,
"isDeleted": false,
"alerts": [],
"links": [
{
"href": "https://someurl/api/users/4f07f234-9606-4cf5-94ce-3a42fb11a6d7",
"rel": "self"
}
]
}
]
I have to get the id [Eg:4f07f234-9606-4cf5-94ce-3a42fb11a6d7] from each json and pass it to delete path.
Please read about transforms: https://github.com/intuit/karate#json-transforms
Now in one line you can get an array of ids:
* def ids = karate.map(response, function(x){ var link = x.links[0].href; return link.substring(link.lastIndexOf('/') + 1) })
Now you can use this in a loop or data driven test and do what you want.

How to traverse thru a response when it is as below

{
"createDate": "2019-05-15 10:07:44",
"mak": "pokijoklm",
"optStatus": "yujuim",
"partnerAccount": {
"operatorName": "frftcrtii",
"partnerCustomerId": "XXXXX",
"type": "partnerAccount"
},
"transactionId": "hjknhijn1",
"type": "nihnui",
"updateDate": "2019-05-15 11:20:59"
}
For an array we can try as response.partneraccount[*]. but my response is { }
You use [] only when there are arrays. Just observe your JSON structure carefully and you will get it. Try pasting the below into a fresh Scenario and see it work:
* def response =
"""
{
"createDate": "2019-05-15 10:07:44",
"mak": "pokijoklm",
"optStatus": "yujuim",
"partnerAccount": {
"operatorName": "frftcrtii",
"partnerCustomerId": "XXXXX",
"type": "partnerAccount"
},
"transactionId": "hjknhijn1",
"type": "nihnui",
"updateDate": "2019-05-15 11:20:59"
}
"""
* def partnerAccount = response.partnerAccount
* match partnerAccount == { operatorName: 'frftcrtii', partnerCustomerId: 'XXXXX', type: 'partnerAccount' }
* def custId = response.partnerAccount.partnerCustomerId
* match custId == 'XXXXX'

Extract data from json array in Karate

In the below JSON response, I need to extract the 'cid' for the record that has the 'nationalityDecription' as 'USA'. By using this query as a reference, I used the below loc in the karate feature file, but 1st line itself fails with syntax error(tried different combinations). For now, I'm using the custom javascript as a workaround which is working fine. I need help to check if i'm missing anything in syntax. Thanks
Response:
{
"header": {
"Id": "12345678",
"timeStamp": "2018-09-17T10:09:812.000"
},
"dataRecords": [
{
"cid": "31H678",
"cidMeta": "00",
"nationalityDecription": "CHINA"
},
{
"cid": "31S421",
"cidMeta": "01",
"nationalityDecription": "USA"
}
]
}
Feature file:
* def record= $response.dataRecords[?(#.nationalityDecription=='USA')]
* def cid = record.cid
* def response = { "header": { "Id": "12345678", "timeStamp": "2018-09-17T10:09:812.000" }, "dataRecords": [ { "cid": "31H678", "cidMeta": "00", "nationalityDecription": "CHINA" }, { "cid": "31S421", "cidMeta": "01", "nationalityDecription": "USA" } ] }
* def cid = get[0] response.dataRecords[?(#.nationalityDecription=='USA')].cid
* match cid == '31S421'