I have feature with multiple scenarios that are building upon each other. Think of it as the first request fetches some data which is then pumped into the second one and so on.
This works fine, as long as all the requests go to the same host. However the last request in the line goes to a different port on the same host, but of course the port which is called from Karate is the wrong one.
Here the the karate-config.js:
function fn() {
karate.configure('connectTimeout', 10000);
karate.configure('readTimeout', 10000);
return {
tenant: 'ipt',
bank: 'ndb',
baseUrl: karate.properties['mws.baseUrl'] ? karate.properties['mws.baseUrl'] : 'http://localhost:8080',
errorIdentifierMatches: function (actualErrorIdentifier, expectedErrorIdentifier) {
return actualErrorIdentifier.startsWith(expectedErrorIdentifier);
},
sleep: function (millis) {
karate.log('Sleeping for ' + millis + ' ms');
java.lang.Thread.sleep(millis)
},
generateUUID: function() {
return java.util.UUID.randomUUID() + '';
}
}
}
This results in the last call going to http://localhost:8080/ipt/registerkey when it should be http://localhost:9390/ipt/registerkey
The relevant part in the feature is defined in the Background:
Background:
Given url baseUrl
* def s2wKeyExchangeEndpoint = ("/mws/v2/" + tenant + "/" + bank + "/s2w/startkeyexchange")
* def s2wVerifyAndSignEndpoint = ("/mws/v2/" + tenant + "/" + bank + "/s2w/verifyandsign")
* def s2wRegisterKey = ("/ipt/registerkey")
Is there a way to change the baseUrl from within my feature? Are there any other options?
You can use the url keyword any time in a Scenario. It is up to you to manage variables and config.
* url 'http://localhost:8080'
* path 'foo', 'bar'
* method get
* url baseUrl
* path 'blah'
* method get
So it sounds to me that you have misunderstood the syntax or have over-complicated things.
Not sure of your application stack, but is it possible to test each call in isolation (by using a mock) then perform limited integrated e2e black box tests?
Related
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
I am using Karate '* configure afterScenario = ' in feature file and getting results successfully and able to have DB calls as well. How to implement same in Karate-config.js?
Note: I have a Java class call as well.
Any implementation like this?
Code using in feature file
Background:
* def inFluxDb = Java.type('aPITests.InfluxDBCall');
* def dbCDB = new inFluxDb();
* configure afterScenario =
"""
function(){
var info = karate.info;
karate.log('after', info.scenarioType + ':', info.scenarioName);
karate.log('after', info.scenarioType + ':', info.errorMessage);
karate.log('after', info.scenarioType + ':', info.featureDir);
karate.log('after', info.scenarioType + ':', info.featureFileName);
karate.log('after', info.scenarioType + ':', info.scenarioDescription);
var featurenameupdate = info.featureFileName.substring(0, info.featureFileName.length-8);
var status="Fail";
if(!info.errorMessage){
status="Pass";
}
dbCDB.DBConnection( "http://localhost:8086", "root", "root");
dbCDB.DBwrite( featurenameupdate, info.scenarioName, info.errorMessage, status );
dbCDB.connectionClose();
}
"""
Update: Concern after using karate.configure
Scenario: I have two feature files
Feature1: API) contains #smoke #test tags
Feature2: UI) contains #dropdown #Angular
My * def configure afterScenariois declared into Feature2 file
While executing only #smoke test, my karate.configure('afterScenario', 'UI.feature'); is not loading.
is this as expected or else anything need to be updated from my end?
Use the karate.configure() API to move any feature configure step into the JS config.
karate.configure('afterScenario', read('some.feature'));
I don't recommend "bloating" your karate-config.js unless absolutely necessary, because it is called for every Scenario or Examples row. Consider using a ExecutionHook instead.
I discovered after-feature in karate which is very useful. But I didn't find how to pass parameters to after-feature from main feature. Ex: access token to delete a user account or a user_id.
Here is call of after-feature.feature in my main feature:
* configure afterFeature = function(){ karate.call('classpath: AfterFeature.feature'); }
Here is my AfterFeature.feature
Scenario:
* url 'XXX'
* path 'YYY'
* param foo = bar which should come from main feature
* header Authorization = 'Bearer ' + accessToken which should come from main feature
* method delete
* status 204
karate.call() can take parameters.
karate.call('classpath: AfterFeature.feature', { some: 'value' });
Presume I have 2 users and I use basic authentication. I'd like to generate the 2 basic auth tokens once and reuse it per scenario in one feature. On top of that I have scnearios where no authorization is needed. How could I achieve this with the least biolerplate? Currently I have
auth-header.js
function(creds) {
var temp = creds.username + ':' + creds.password;
var Base64 = Java.type('java.util.Base64');
var encoded = Base64.getEncoder().encodeToString(temp.bytes);
return 'Basic ' + encoded;
}
karate-config.js
...
config.apitester1AuthHeader =
karate.call('classpath:auth-headers.js', {username:'apitester1', password:'xxx'});
config.apitester2AuthHeader =
karate.call('classpath:auth-headers.js', {username:'apitester2', password:'xxx'});
...
project-get.feature
Feature: project end-point
Background:
* url baseUrl
Scenario: get projects user has right to
* configure headers = {Authorization : '#(apitester1AuthHeader)'}
Given path 'project'
...
What you have looks reasonable.
Note that if you do:
* configure headers = null
It will have the effect of temporary no authorization. I would recommend stick with what you have and it is quite modular already.
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