Unable to delete key from a json in karate framework - remove() and delete did not work - karate

I want to delete a key from JSON. I found two examples shared by #Peter Thomas. I tried both and unfortunately, none worked.
Example 1
* def json = { a: 1, b: 2 }
* def key = 'b'
* if (true) karate.remove('json', key)
* match json == { a: 1 }
Error
javascript evaluation failed: if (true) karate.remove('json', key), unexpected path: b
Example 2
* def json = { a: 1, b: 2 }
* def key = 'b'
* if (true) delete json[key]
* match json == { a: 1 }
Error
actual: {a=1, b=2}, expected: {a=1}, reason: actual value has 1 more key(s) than expected: {b=2}

You probably are on an old version. Upgrade. Or maybe it is a bug, so follow this process: https://github.com/karatelabs/karate/wiki/How-to-Submit-an-Issue

Related

How to validate a response in karate when you don't know the structure?

I'm trying to write some karate tests that check a response for some expected structure. For example, there is an object that looks like this:
{
'true|true':'disabled',
'true|false':'locked',
'false|false':'enabled',
'false|true':'disabled',
'default':'enabled'
}
However, the keys and values could be any strings. There must be a way to specify this, but I'm at a loss for how to do this in a generic way.
Essentially, what I would like to test is that 1) the object is not empty, 2) each of the keys and values is a string (not an object and not null).
The basic match looks like this:
* def objects = $fields..objects
And match each objects ==
"""
{
key1: '#? isString(_)',
key2: '#? isString(_)'
}
"""
It looks like the names of the keys must be known in advance, so perhaps match expressions are not the appropriate way to test this.
You can extract all keys like this:
* def keys = karate.keysOf(object)
So once you have that, you are in business:
* def foo = { a: 1, b: 2 }
* def keys = karate.keysOf(foo)
* match each keys == '#string'
* assert keys.length > 0
See JSON tranforms for other ideas, e.g. karate.forEach(): https://github.com/intuit/karate#json-transforms

Is there a way to match dynamic object keys?

I'm looking for a simple technique to match objects where the key may not be known in advance (e.g. we may fetch the schema as part of the test). As a contrived example:
Scenario:
* def result = { foo: 'bar' }
* def key = 'foo'
Then match result == { '#(key)': 'bar' }
...which doesn't currently work.
Once you realize there is a JavaScript engine behind the scenes, you will get even more ideas :)
* def result = { foo: 'bar' }
* def key = 'foo'
* def expected = {}
* expected[key] = 'bar'
Then match result == expected
Also do a search for other answers [karate] dynamic you will find many interesting examples such as this one: https://stackoverflow.com/a/57226061/143475

Index of object in array found with match response[*]

Is it possible to get the index value of a
* match response.Services[*] contains { "Service": "xyz"}
I'm looking to reuse it later for more specific tests on the same Service object.
Theres reference to a __loop variable here but I guess I don't really understand how to apply it.
I love your questions, you are certainly pushing Karate to the limits and I'm having to think hard to answer these as well :)
The match does not allow you to get the "found index" or even the "loop position" which come to think of it - may be actually relevant for a match each - but I digress.
This will take a few extra lines of code, and I really think you need to upgrade to 0.8.0. If it helps, I can confirm that there are no breaking changes (unless you use the stand-alone JAR).
The new karate.forEach() and karate.match() functions allow you to do very complex operations on arrays. Here are 2 examples:
Scenario: karate find index of first match (primitive)
* def list = [1, 2, 3, 4]
* def searchFor = 3
* def foundAt = []
* def fun = function(x, i){ if (x == searchFor) foundAt.add(i) }
* eval karate.forEach(list, fun)
* match foundAt == [2]
Scenario: karate find index of first match (complex)
* def list = [{ a: 1, b: 'x'}, { a: 2, b: 'y'}, { a: 3, b: 'z'}]
* def searchFor = { a: 2, b: '#string'}
* def foundAt = []
* def fun = function(x, i){ if (karate.match(x, searchFor).pass) foundAt.add(i) }
* eval karate.forEach(list, fun)
* match foundAt == [1]
If you really can't upgrade, you can write a function to manually loop over the array and the above examples should get you a solution.

Unable to Parse the variable value to the array variable

I was trying to pass the variable 'i' value to a array index 'locations[i]' using below karate code. but throwing an error saying unable to parse. Please suggest be for any changes.
Feature: Verify Branches
Background: For loop implementation
Given url ''
When method GET
Then status 200
* def i = 0
* def z = $.locations[i].zip
* def p = $.locations[i].phone
* def fun =
"""
function(locations){
for (var i = 0; i < locations.length; i++)
{
print(i)
print('Element at Location ' + i +':' + p)
}
}
"""
Scenario: Validate the locations
Given url ''
When method GET
Then status 200
* call fun p
It is hard to make out anything since you have not provided the value of the response. There are many things wrong here. But I'll try.
Take this line:
* def z = $.locations[i].zip
This will not work, Karate does not support variables within JsonPath by default, refer the docs: https://github.com/intuit/karate#jsonpath-filters
And I think you are un-necessarily using JsonPath where normal JavaScript would have been sufficient:
* def z = response.locations[i].zip
Also it seems you are just trying to loop over an array and call a feature. Please refer to the documentation on Data Driven Features.
Take some time and read the docs and examples please, it will be worth your time. One more tip - before I leave you to understand Karate a little better. There is a way to convert a JSON array into another JSON array should you need it:
* def fun = function(x){ return { value: x } }
* def list = [1, 2, 3]
* def res = karate.map(list, fun)
* match res == [{ value: 1 }, { value: 2 }, { value: 3 }]
So there should never be a need for you to manually do a for loop at all.

Karate - How to validate output with multiple templates?

Is there any way to validate output of a request with one of multiple templates?
for example:
{
"pendingInvitesCount":#number,
"acceptedInvitesCount":#number,
"rejectedInvitesCount":#number
}
or
[]
Not really recommended as testing best practice, but this should give you some ideas:
* def actual = []
* def expected = (actual.size() == 0 ? '#[0]' : { a: '#number', b: '#number' })
* match actual == expected