How to add an element to an array in karate?
I have a string array(not json array) from response and add a string element to it for next request.
I tried a lot with JS functions but with no luck.
Any help is appreciated.
Scenario:123
* def roles = ["role1"]
* def newrole = "role2"
* def addrolefn =
"""
function(role,roles1) {
var fullrole = [];
for (var i=0; i<roles1.length;i++) {
fullrole = fullrole.push(role);
}
return fullrole;
}
"""
* def fullroles = call addrolefn (newrole,roles)
* print fullroles
Please refer to the set keyword.
* def roles = ["role1"]
* def newrole = "role2"
* set roles[1] = newrole
* print karate.pretty(roles)
Result:
06:26:35.324 [main] INFO com.intuit.karate - [print] [
"role1",
"role2"
]
edit: actually I've just raised an enhancement request to add an append keyword to Karate. Meanwhile, this should answer all your questions and act as a workaround.
* def roles = null
# javascript that assigns an empty array if null
* json roles = (roles || [])
* def newrole = "role2"
# javascript to append to an array. the def void is useless
* def void = (roles.add(newrole))
* print karate.pretty(roles)
edit: type cast to json, and using java list api add method
Related
I am trying to have a Karate test where I need to traverse through a json to get the required test data.
I have the below json.
{
"dev":{
"scenario1":{
"data":"data1"
},
"scenario2":{
"data":"data2"
}
},
"qa":{
"scenario1":{
"data":"data1"
},
"scenario2":{
"data":"data2"
}
}
}
Below is my feature file.
Background:
* def env = dev
Scenario:
* Given url someurl
* def inputData = testdata.env.scenario1.data
* And request { input: '#(inputData)'}
* When method post
* Then status 200
I need the test data that matches the value env that I have defined above.
How can I set the json path to my input data. Basically, the json path should take the value from a variable I have defined previously.
For this you don't even need Json-Path, just JS will do:
* def data = { foo: 1, bar: 2 }
* def env = 'bar'
* def res = data[env]
* match res == 2
Also see: https://stackoverflow.com/a/59162760/143475
You can also do dynamic Json-Path, see: https://stackoverflow.com/a/50855425/143475
For some reason a variable with a / character get converted to a \/, how do I prevent this?
I start a echo server that listens on localhost:3000 by running npx http-echo-server
I execute the following:
code:
* def CHALLENGE_USER = '/abc/user'
* def loginJson = { user: '#(CHALLENGE_USER)' , name: 'Some Name'}
* print loginJson
* def TEST_URL = 'http://localhost:3000'
Given url TEST_URL+'/session/loginresponse'
And header Content-Type = 'application/json'
And request loginResponseJson
And method put
Then status 200
It prints { "user": "/abc/user", "name": "Some Name" } like I expect.
The http server logs show "--> {"user":"/schemes/ATT_5_55/CH_1","name":"Some Name"}"
Karate shows the result of the echo {"user":"\/abc\/user","name":"Some Name"}
I have tried:
def CHALLENGE_USER = '/abc/user'
def CHALLENGE_USER = "/abc/user"
def CHALLENGE_USER = '/abc/user'
def CHALLENGE_USER = '//abc//user'
also setting the variable after the fact does not work:
* def loginJson = { name: 'Some Name'}
* loginJson.user = CHALLENGE_USER
Yes this is legal as per the JSON spec: JSON: why are forward slashes escaped?
And the Java libraries we use does that.
Does your server have a problem ? If so - then you have a bug that Karate surfaced.
And if you really want to have full control over the request, please use text but IMO it may be a waste of time: https://stackoverflow.com/a/68344856/143475
A nasty workaround, please forgive me Peter Thomas.
You can convert the json to a string and then remove the \ characters.
I only have one use case for this thank goodness.
* def CHALLENGE_USER = '/abc/user'
* def loginJson = { user: '#(CHALLENGE_USER)' , name: 'Some Name'}
* string json = loginJson
* def loginJsonText = json.replaceAll("\\", "")
* print loginJson
* def TEST_URL = 'http://localhost:3000'
Given url TEST_URL+'/session/loginresponse'
And header Content-Type = 'application/json'
And request loginJsonText
And method put
Then status 200
When using KarateDriver, I want to define and execute JS function in the browser.
Is is possible?
I want to define it like:
* def someFn =
"""
function(param) {
// DOM operation in the browser
// Event handling in the browser
return
}
"""
* assert someFn('param1') == '<span>param1</span>'
Edit1:
I define and execute;
* def keyword = 'karate'
* def formSubmit =
"""
function(formId) {
var formElem = document.getElementById(formId);
formElem.submit();
}
"""
Given driver 'https://github.com/search'
And driver.input('input[name=q]', keyword)
When driver.eval(formSubmit('search_form'))
Then eval driver.waitUntil(driver.location == 'https://github.com/search?utf8=%E2%9C%93&q=' + keyword + '&ref=simplesearch')
but this feature is failure.
javascript evaluation failed: driver.eval(formSubmit('search_form')), ReferenceError: "document" is not defined in <eval> at line number 2
Can it use DOM operations?
Edit2:
I can define and execute the JS function:
* def getSubmitFn =
"""
function(formId) {
return "var formElem = document.getElementById('" + formId + "');"
+ "formElem.submit();"
}
"""
You can do driver.eval() where the argument is raw javascript code as a string. I think this is sufficient for your needs:
* match driver.eval("location.href") == webUrlBase + '/page-01'
* assert driver.eval('1 + 2') == 3
EDIT: the JS engine for Karate and the Browser JS engine is different and there is no connection. So you have to pass JS as raw strings to driver.eval() here is an example that works for submitting a form.
* def getSubmitFn =
"""
function(formId) {
return "document.getElementById('" + formId + "').submit()"
}
"""
* def temp = getSubmitFn('eg02FormId')
* print temp
* driver.eval(temp)
EDIT: I just remembered, * driver.eval() is valid, no need to do * eval karate.eval()
Typically what you pass to driver.eval() can be simple, but it has to be a string, and you cannot use Karate variables (you have to hard-code them when creating the JS dynamically). You can use DOM objects and functions. You can have multiple statements of JS separated by ;.
Run the first.feature file successfully,however, call it from the second.feature failed without any clue to analysis. Do you have any idea help me find the root cause?
The source of my first.feature:
Feature: 采样管理-样本登记
Background: 读取随机生成的条形码、手机号、采样类型等作为入参
* url baseURL
* def randomData = Java.type('utils.RandomData')
* def barcode = randomData.getRandom(11)
* def randomPhone = randomData.getTelephone()
* def sampletype = randomData.getNum(0,1)
Scenario: 输入合法参数进行正常样本登记,确认能够登记成功
Given path 'iEhr/PersonSample'
# * header Content-type = 'application/x-www-form-urlencoded; charset=UTF-8'
* cookies { JSESSIONID: '#(jsessionID)',SESSION: '#(sessionID)', ACMETMP: '#(acmetmpID)'}
* def autoMotherName = "autoMname"+ barcode
# * def confData = {mothername: "#(autoMotherName)", barcode: "#(barcode)", mobile: '#(randomPhone)', sampletype:"#(sampletype)" }
# 设置sampletype为1,已被采样
* def confData = {mothername: "#(autoMotherName)", barcode: "#(barcode)", mobile: '#(randomPhone)', sampletype:"1" }
# 打印入参变量输出
* print confData
# 用例与数据分离
* def paramObj = read('classpath:mainFlow/sampleSaveReqTest.json')
* print paramObj
* form field param = paramObj
When method post
Then status 200
* json result = response[0].result
* def personId = result[0].personid
* def sampleid = result[0].sampleid
* print personId
* print sampleid
The source of my second.feature:
Feature: 提交递送样本
Background:
* def sampleResult = call read('classpath:mainFlow/first.feature')
* print sampleResult
I run the first.feature singly, it works. However, karate reports the error below after running the second.feature. Any idea how can I debug to find the root cause? I have no idea what's wrong with the second read. Many thanks!
* def sampleResult = call read('classpath:mainFlow/first.feature')
-unknown-:14 - javascript evaluation failed: read('classpath:mainFlow/first.feature'), null
Look for some issue with karate-config.js. As Babu said in the comments, it is very hard to make out what the problem is, I suggest you follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
Also try if the latest preview version 0.9.3.RC2 is better at showing what the error is.
If you can replicate the problem as a small example, it will help us - because we really need to do better at showing more useful error logs, instead of just null.
Lets say I created javascript functions in functions js file.
function getReviews(reviews){
var length_reviews = reviews.length
return length_reviews
}
function getReviewsLength(reviewLength){
return reviewLength
}
Here in function getReviews argument reviews is an array.
Now how will I call getReviews function in one feature file.
When I tried below code
* def jsFunction = call read('functions.js')
* def review = jsFunction.getReviews(reviewFromFeatureFile)
I am getting an error of
Cannot read property "length" from undefined
I already printed reviewFromFeatureFile and its coming correctly in print statement.
As Peter mentioned above you can keep you js inline on your feature
* def reviews = [{"r1":2},{"r1":3},{"r1":4}]
* def getReviews = function(reviews){ return reviews.length }
* def getReviewsLength = getReviews(reviews)
* print getReviewsLength
In this example, it should print 3.
For more other options for handling javascript or other reusable modules in karate, please refer to this article
Organizing re-usable functions in karate
In one "common" feature file, define multiple methods like this:
* def uuid = function(){ return java.util.UUID.randomUUID() + '' }
* def now = function(){ return java.lang.System.currentTimeMillis() }
You can now call this feature like this:
* call read('common.feature')
And now all the functions in that feature are available for use:
* def id = uuid()
* def time = now()