In Karate - Feature file calling from another feature file along with variable value - karate

My apologies it seems repetitive question but it is really troubling me.
I am trying to call one feature file from another feature file along with variable values. and it is not working at all.
Below is the structure I am using.
my request json having variable name. Filename:InputRequest.json
{
"transaction" : "123",
"transactionDateTime" : "#(sTransDateTime)"
}
my featurefile1 : ABC.Feature
Background:
* def envValue = env
* def config = { username: '#(dbUserName)', password: '#(dbPassword)', url: '#(dbJDBCUrl)', driverClassName: "oracle.jdbc.driver.OracleDriver"};
* def dbUtils = Java.type('Common.DbUtils')
* def request1= read(karate.properties['user.dir'] + 'InputRequest.json')
* def endpoint= '/v1/ABC'
* def appDb = new dbUtils(config);
Scenario: ABC call
* configure cookies = null
Given url endpoint
And request request1
When method Post
Then status 200
Feature file from which I am calling ABC.Feature
#tag1
**my featurefile1: XYZ.Feature**
`Background`:
* def envValue = env
Scenario: XYZ call
* def sTransDateTime = function() { var SimpleDateFormat = Java.type('java.text.SimpleDateFormat'); var sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'+00:00'"); return sdf.format(new java.util.Date()); }
* def result = call read(karate.properties['user.dir'] + 'ABC.feature') { sTransDateTime: sTransDateTime }
Problem is,
While executing it, runnerTest has tag1 configured to execute.
Currently, it is ignoring entire ABC.feature to execute and also not generating cucumber report.
If I mention the same tag for ABC.feature (Which is not expected for me as this is just reusable component for me ) then it is being executed but sTransDateTime value is not being passed from XYZ.feature to ABC.feature. Eventually, InputRequest.json should have that value while communicating with the server as a part of the request.
I am using 0.9.4 Karate version. Any help please.

Change to this:
{ sTransDateTime: '#(sTransDateTime)' }
And read this explanation: https://github.com/intuit/karate#call-vs-read
I'm sorry the other part doesn't make sense and shouldn't happen, please follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue

Related

Karate: How can we retrieve the value from called feature file

I have two parameter in feature file A and I pass those values to another feature file called B.
But I am unable to retrieve the values as expected in Feature file B
CODE:
Feature File A:
And def Response = response
And def token = response.metaData.paging.token
And def totalPages = response.metaData.paging.totalPages
* def xyz =
"""
function(times){
for(currentPage=1;currentPage<=times;currentPage++){
karate.log('Run test round: '+(currentPage));
karate.call('ABC.feature', {getToken:token, page:currentPage});
}
java.lang.Thread.sleep(1*1000);
}
"""
* call xyz totalPages
Feature File B:
* def token = '#(getToken)'
* def currentPage = '#(page)'
But the output was
#getToken
#page
What would be the best way? to these values for further utilization.
Try this:
* def token = getToken
* def currentPage = page
Here's another thing, any variable defined in the calling feature will be visible, e.g. token so most of the time you don't need to pass arguments:
* print token
* print totalPages
Please avoid JS for loops as far as possible: https://github.com/intuit/karate#loops - and actually you seem to have missed the data-driven testing approach that Karate recommends: https://github.com/intuit/karate#the-karate-way
If you are still stuck, please follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue

If then else implementation to chose baseURL in Karate DSL

I have a little tricky requirement in Karate. I have a set of baseURL's in my karate.config which are chosen based on the implementation. Here is the snippet of it:
if (env == 'qa') {
config.apiKey = apiKey;
config.tsp_api = 'https://api.qa.tceu.net';
config.svt_dcm = 'https://svt.qa.tceu.net';
config.acn_dcm = 'https://acn.qa.tceu.net';
config.sos_dcm = 'https://sos.qa.tceu.net';
config.cust_dcm = 'https://cust.qa.tceu.net';
Here tsp,svt,acn,sos,cust are some actions.
I have a feature file which passes the action as a parameter:
# Vehicle Initiates the action
When def Perform_Report_Notification = call read('./../common/performActionNotification.feature') { action: '#(action)' }
In the called performActionNotification.feature, I need to pick up the url from the karate.config file based on the action that is passed. For example if the action is sos, then the url should be sos_dcm. If the action is svt then the url should be svt_dcm
Here is the snippet from performActionNotification.feature and what I am currently doing for sos:
Given url sos_dcm
And path '/AU/v1.0/TSP/'+ action
And request RequestPayload
When method post
Then status 200
I want to implement something like an if then else similar to:
if (action == 'sos')
then myurl == 'sos_dcm'
else if (action == 'acn')
then myurl == 'acn_dcm'
else if (action == 'svt')
then myurl == 'svt_dcm'
Given url myurl
And...
And...
...
I tried a sort of a hack and it works but its not a clean way of doing it. Instead of reading the URL from karate.config I am hardcoding it this way:
Given url 'https://'+act+'.qa.tceu.net'
One more thing I tried was
* def myurl = action +'_dcm' #so if action is acn then the variable myurl would be acn_dcm
Given url myurl
...
....
But this hardcodes the url as 'acn_dcm' instead of picking the defined url up from karate.config.
Can someone kindly suggest the best way to implement this?
Here is a hint. JSON is actually a pretty useful data-structure (think hash-map or dictionary) and you can lookup a value without needing an if statement.
* def data =
"""
{
qa: {
sos: 'https://sos.qa.tceu.net',
acn: 'https://acn.qa.tceu.net'
}
}
"""
* def env = 'qa'
* def urls = data[env]
* def action = 'sos'
* def actionUrl = urls[action]
* match actionUrl == 'https://sos.qa.tceu.net'
This should get you on your way :)
EDIT - also see this: https://stackoverflow.com/a/67868935/143475
I've finally used Peter's most elegant solution and it works like a charm!
Here's what I've finally implemented that does not need hardcoding of the endpoint URL's and is driven by endpoints in the karate.config file.
* def data =
"""
{
qa: {
sos: '#(sos_dcm)', # sos_dcm endpoint defined in karate.config file
acn: '#(acn_dcm)',
svt: '#(svt_dcm)'
}
}
"""
* def env = karate.properties['env']; # Driven by maven commandline arg -Denv=qa as an example
* def urls = data[env]
* def action = act # act comes from the calling feature file and has values - sos/acn/svt
* def myUrl = urls[action]
Given url myUrl
...
...
I would suggest looking into using javascript for your conditional logic
So the javascript function takes a param of action and then the if and else statements returns the variable of the url that you need.
Perform the javascript function before you make the request call. and use the variable that is returned by js to determine the logic.
make that js file a common function that can be accessed by multiple feature files.
function determineUrl(action) {
var url = "${urDefaultUrl}";
if (action == "sos") url == "${full url}";
else if (action == "acn") url == "${full url}";
return url;
}
Then in your feature file
* def urlDecider = 'classpath to your js function'
* myUrl = urlDecider(action)
* url myUrl
* Given path ....
For the sake of the community learning, there is one other way I figured out on similar lines of Jawad's solution is using a Java function. They do exactly the same thing as Jawad's solution but just that its a java class doing it. If a project has java class files, then to maintain consistency this solution can be used too.
Here is the how the class file looks:
public class DCMUrlDecider {
static String dcmURL="";
public static String getDCMUrl(String action) {
if (action.matches("sos"))
{
dcmURL = "https://sos.qa.tceu.net";
}
else if (action.matches("acn"))
{
dcmURL = "https://acn.qa.tceu.net";
}
else if (action.matches("svt"))
{
dcmURL = "https://svt.qa.tceu.net";
}
return dcmURL;
}
}
And here is the associated code snippet from the feature file:
* def dcmURLDecider = Java.type('com.TCEU.KarateTests.DCMUrlDecider')
* def myUrl = dcmURLDecider.getDCMUrl(act)
Given url myUrl
....
.....
Once again this means we are still hardcoding URLs in the java class files. Need to learn a way of doing it via karate.config files if possible.

How to do conditional variables definition on Karate

I had written karate tests for one environment only (staging). Since the tests are successful on capturing bugs (thanks a lot Karate and Intuit team!), there is now request to run the tests on production.
Our tests are graphql-based where most of the requests are query. I wonder if it is possible for us to switch variables based on karate.env we passed on terminal?
Most of our requests look like this:
And def variables = {objectID:"1234566", cursor:"1", cursorType:PAGE, size:'10', objectType:USER}
And request { query: '#(query)', variables: '#(variables)' }
When method POST
Then status 200
I had tried reading the conditional-logic page on github page but haven't yet found a success.
What I tried so far is:
* if (karate.env == 'staging') * def variables = {objectID:"1234566", cursor:"1", cursorType:PAGE, size:'10', objectType:USER}
But to no success.
Any help will be greatly appreciated. Thanks a lot!
We keep our graphql queries & variables in separate json files, but, we're attempting to solve the same issue. Based on what Peter wrote I came up with this, though it will likely get cleaned up before deployment.
Given def query = read('graphqlQuery.graphql')
And def prodVariable = read('prod-variables.json')
And def stageVariable = read('stage-variables.json')
And def variables = karate.env == 'prod' ? prodV : stageV
And path 'api/' + 'graphql'
And request { query: '#(query)', variables: '#(variables)' }
When method post
Then status 200
This should be easy:
* def variables = karate.env == 'staging' ? { objectID: "1234566", cursor: "1", cursorType: 'PAGE', size: '10', objectType: 'USER' } : { }
Here is another hint:
* def data = { staging: { foo: 'bar }, production: { foo: 'baz' } }
* def variables = data[karate.env]
EDIT: also see this explanation: https://stackoverflow.com/a/59162760/143475

How to pass the json list response of one feature file as parameter to another feature file

My requirement is, I want to pass the response of first feature file as input to second feature file. The first feature file response is a json list, so the expectation is second feature file should be called for each value of json list.
Feature:
Scenario: identify the reference account
* def initTestData = read('../inputData.feature')
* def accountData = $initTestData.response
* print “Account Details”+accountData // output of this is a json list [“SB987658”,”SB984345”]
* def reqRes = karate.call('../Request.feature', { accountData : accountData })
In Request.feature file we are constructing the url dynamically
Given url BaseUrl + '/account/'+'#(accountId)' - here am facing issue http://10.34.145.126/account/[“SB987658”,”SB984345”]
My requirement is Request.feature should be called for each value in ‘accountData’ Json list
I have tried:
* def resAccountList = karate.map(accountData, function(x){accountId.add(x) })
* def testcaseDetails = call read('../requests/scenarios.feature') resAccountList.accountId
Result is same, accountId got replaced as [“SB987658”,”SB984345”]
my I need to call Request.feature twice http://10.34.145.126/account/SB987658 http://10.34.145.126/account/SB984345 and use the response of each call to the subsequent feature file calls.
I think you have a mistake in karate.map() look at the below example:
* def array = ['SB987658', 'SB984345']
* def data = karate.map(array, function(x){ return { value: x } })
* def result = call read('called.feature') data
And called.feature is:
Feature:
Scenario:
Given url 'https://httpbin.org'
And path 'anything', value
When method get
Then status 200
Which makes 2 requests:
https://httpbin.org/anything/SB987658
https://httpbin.org/anything/SB984345

How to call a specific function from JS file to feature file in karate [duplicate]

I need to perform two operations on the result of JSON responses.so can we have those different operations inside single JS file? or do we need to have mapping like one JS file for one operation.
Please help on this
I don't recommend trying to create complicated JavaScript in Karate, it just leads to maintainability issues. If you really want an object with multiple utility methods on it, write a Java class with static methods, and it will be much easier to maintain / debug.
That said, if you really insist - look at this answer: https://stackoverflow.com/a/47002604/143475
But this is what I recommend for most projects. In one "common" feature file, define multiple methods like this:
Scenario:
* def now = function(){ return java.lang.System.currentTimeMillis() }
* def uuid = function(){ return java.util.UUID.randomUUID() + '' }
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 time = now()
* def id = uuid()
#kmancusi This is how I did a common.feature file with my common functions and then the following my.test.feature shows how I import that to use it in another feature.
common.feature
#ignore
Feature:
Scenario:
* def now =
"""
function() {
return java.lang.System.currentTimeMillis()
}
"""
* def uuid =
"""
function() {
return java.util.UUID.randomUUID() + ''
}
"""
my.test.feature
Feature: my tests
Background:
* configure logPrettyRequest = true
* configure logPrettyResponse = true
* configure ssl = true
Scenario: basic test
* def util = call read('common.feature')
* def sessionId = util.uuid()
* print sessionId