how to manage variable inside of json value string? - karate

I have variable cardholder in my karate-config file.
I assigned it to the new entrID variable.
The main thing that i am building JSON as a String..
* def entrID = cardholder
* def requestContactHistoryAdd =
"""
{
"RequestBody": "{ \"ENTR_ID\" : \"entrID\", \"BHVR_ID\" : \"VRU\", }"
}
"""
Now how can i provide it inside of my json RequestBody?

EDIT: since you seem to have a very badly designed API where the JSON has an embedded string (which looks like JSON).
Please note I am using a string type below: https://github.com/intuit/karate#type-conversion
You can do this:
* def entrID = 'foo'
* string temp = { "ENTR_ID" : "#(entrID)", "BHVR_ID" : "VRU" }
# note that you could have done this:
# def temp = '{ "ENTR_ID" : "' + entrID + '", "BHVR_ID" : "VRU" }'
* def body = { RequestBody: '#(temp)' }
* print body
Which gives you:
08:17:25.671 [main] INFO com.intuit.karate - [print] {
"RequestBody": "{\"ENTR_ID\":\"foo\",\"BHVR_ID\":\"VRU\"}"
}

i solved it also like this
* def entrID = someValueFromSomeWhere
* def bodyValue = "{ \"ENTR_ID\":\"" + entrID + "\", \"BHVR_ID\" : \"VRU\" }"
* def requestContactHistoryAdd =
"""
{
"RequestBody": "#(bodyValue)"
}
"""
we can also do this way
* def bodyValue = "{ \"ENTR_ID\":\"" + someValueFromSomeWhere + "\", \"BHVR_ID\" : \"VRU\" }"
* def requestContactHistoryAdd =
"""
{
"RequestBody": "#(bodyValue)"
}
"""

Related

Karate: How to paste and run scenario for each param from array response inside scenario?

I have a range of values, like taskId, extracted from DB.
* def getTasks = db.readRows('SELECT task_id from tasks t WHERE t.status = \'IN_PROGRES\'
')
* def getIds = get getTasks[*].task_id
* 'task', 'setUser'
* request
"""
[{
"task_id": " ",
"assignedUser": {
"user": "someValue"
}
}
]
"""
* method post
* status 200
* def responseResult =
"""
{
"totalCount": '#number',
"successCount": '#number',
"skippedCount": '#number',
"failedCount": '#number',
}
"""
* match response == responseResult
I need to get each value from the list response and paste in into a "task_id"
Could you please clarify this case?
If you mean trying to create a JSON array from a bunch of values that is easy.
* def response = { foo: 1, bar: 2 }
* def task_ids = []
* task_ids.push(response.foo)
* task_ids.push(response.bar)
* match task_ids == [1, 2]
When it comes to JSON manipulation, think of Karate as just like JavaScript.

Wanted to try oneof conditon in JSON schema validation in Karate DSL

I've been using something like this.
* def schema =
"""
{
eligible: #string,
Reason: ##string,
enrolled: '##regex ^\\d{4}-\\d{2}-\\d{2}$',
modifiable: ##string,
Date: '##regex ^\\d{4}-\\d{2}-\\d{2}$',
status: #string,
Id: #string,
email: #string,
serviceAddressDetails: ##[] firstSchema,
DeviceIds: #[] #string
}
"""
The expected response has two possible outcomes, I want to assert that if we get either of them, the test should pass.
First,
DeviceIds : ["abcderfg"]
Second
DeviceIds : [
{
id : "abcd"
}
],
If we get either of them in the response, the test/schema should pass. How can I assert both these scenarios in the same schema?
Any help is much appreciated. Thanks!
Just run a second check. I know, it may not feel like a "single reusable schema" but take my advice, it is not worth it. Here's a solution:
* def response1 = { deviceIds: ['abcd'] }
* def firstDevice = response1.deviceIds[0]
* def isTypeOne = karate.typeOf(firstDevice) == 'string'
* def expectedDevice = isTypeOne ? '#[] #string' : '#object'
* match response1 == { deviceIds: '#(expectedDevice)' }
* def response2 = { deviceIds: { id: 'abcd' } }
* def firstDevice = response2.deviceIds[0]
* def isTypeOne = karate.typeOf(firstDevice) == 'string'
* def expectedDevice = isTypeOne ? '#[] #string' : '#object'
* match response2 == { deviceIds: '#(expectedDevice)' }
Other ideas:
https://stackoverflow.com/a/62567262/143475

Karate Nested Schema contains "Not Required" not working?

i'm trying to understand karat schema fuzsy validation with contains but is not working
if I use ##string for not required it validates required when is null
this is my example
Scenario: Test
* def payload =
"""
{
nested: {
field: 'not required'
}
}
"""
* def payload2 =
"""
{
nested: null
}
"""
* def schema =
"""
{
nested: {
field: '##string'
}
}
"""
* match payload contains schema
* match payload2 contains schema
I get this error in console
path: $.nested, actual: null, expected: {field=##string}, reason: actual value is null
Thanks for help
Pay attention to the structure. I think this is what you are trying:
* def part = { field: '#string' }
* def schema = { nested: '##(part)' }
* def payload = { nested: { field: 'not required' } }
* match payload == schema
* def payload2 = { nested: null }
* match payload2 == schema
And please refer the docs: https://github.com/intuit/karate#schema-validation
yes thanks, also this works
* def schema =
"""
{
'nested.field': '##string'
}
"""

Karate: Write to a text file

I have the following feature file that reads the input and appends the input id with the response and writes to a text file in the below format:
|123|{"products": [ { "pid": "1a"} ] }|
|124|{"products": [ { "pid": "1b"} ] }|
|125|{"products": [ { "pid": "1c"} ] }|
so that I can make the input table with it and dont need copy each response in text format and paste to make Examples:
I have tried the below:
Feature: sample karate test script
Background:
* url BaseUrl
* configure headers = read('classpath:headers.js')
* def jsonFromCsv = read('data.csv')
* def size = karate.sizeOf(jsonFromCsv)
* print size
Scenario Outline: Get All Tests
* def doStorage =
"""
function(args) {
var DataStorage = Java.type('DataStorage.DataStorage'); // Java class that writes to a text file
var dS = new DataStorage();
return dS.write(args);
}"""
Given path '/v1/path'
When method get
Then status 200
* def json = __row.expected
* def id = __row.id
* def app = '|'+<id>+'|'+json+'|'
* print app # prinst it in the expected format
* def result = call doStorage app
Examples:
| jsonFromCsv |
But the issue is only the last read data is being written to the file.
I had tried the below as well but gives the same result as above:
* def js = function (app){karate.write(app,'input.txt')}
DataStorage.java:
package DataStorage;
import java.io.*;
public class DataStorage {
public void write( String text) throws IOException {
BufferedWriter output = null;
try {
File file = new File("input");
output = new BufferedWriter(new FileWriter(file));
output.append(text);
output.close();
} catch ( IOException e ) {
e.printStackTrace();
} finally {
if ( output != null ) {
output.close();
}
}
}
}
You can use CSV files (have to be comma delimited): https://github.com/intuit/karate#csv-files
Also see this example:
Scenario Outline: cat name: <name>
Given url demoBaseUrl
And path 'cats'
And request { name: '<name>', age: <age> }
When method post
Then status 200
And match response == { id: '#number', name: '<name>' }
# the single cell can be any valid karate expression
# and even reference a variable defined in the Background
Examples:
| read('kittens.csv') |

Using karate.forEach and karate.set to extract index of value from json array

I have the below json:
{
"id": [
"1A",
"2B"
],
"name": [
"rs",
"mk"
]
}
I want to extract the id value when name is 'rs' or 'mk'. There will be no duplication of name values and the size of id and name keys will always match.
So i have created the following scenario where:
- I iterate through the name array using forEach.
- Find if the value of name matches rs or mk and if it does, retrieve the index.
- Then use this index to find the retrieve the value from id key.
When I run this, the name_rs_idx and name_mk_idx are not being set and are blank.
Scenario: Using forEach and karate.set
* def vals = { id: ['1A', '2B'], name: ['rs', 'mk'] }
* def name_rs_idx = ''
* def rsFun =
"""
function(x, i) {
if(x == 'rs') {
karate.set(name_rs_idx, i);
}
}
"""
* karate.forEach(vals.name, rsFun)
* print 'RS Index - ' + name_rs_idx
* def name_rs_id = vals.id[name_rs_idx]
* print 'RS id -' + name_rs_id
* def name_mk_idx = ''
* def mkFun =
"""
function(x, i) {
if(x == 'mk') {
karate.set(name_mk_idx, i);
}
}
"""
* karate.forEach(vals.name, mkFun)
* print 'MK Index - ' + name_mk_idx
* def name_mk_id = vals.id[name_mk_idx]
* print 'MK id -' + name_mk_id
Maybe i am not using the forEach function correctly or logic is incorrect.
I think you are over-complicating things :) Here is my solution, take time to read and understand it, it will improve your Karate fundamentals ! To simplify things, we first combine the data into an array of { name: '', id: '' } pairs. Then things become much easier.
* def vals = { id: ['1A', '2B'], name: ['rs', 'mk'] }
* def fun = function(x, i){ return { name: vals.name[i], id: vals.id[i] } }
* def pairs = karate.map(vals.name, fun)
* def fun = function(x){ return x.name == 'rs' || x.name == 'mk' }
* def filtered = karate.filter(pairs, fun)