How to configure karate afterScenario in karate-config.js file - karate

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.

Related

How to access karate ui automation driver details like sessionid in afterScenario? [duplicate]

This question already has an answer here:
KARATE integration with SauceLabs
(1 answer)
Closed 1 year ago.
I am reading the json file which contains the array of configurations of browserstack browsers or devices on which I want run my UI automation tests and defining it in karate-config.js as a global variable, for ex: config.envrironments. That variable I am calling it in Examples Table as envrironments and using it in dynamic scenario outline to initialize driver for different browser/device sessions as envrironments[__num]. The execution is working fine as expected.
After execution, I want to call the browserstack api which updates the test scenario status as passed or failed with a reason in their dashboard or in the browserstack report integrated in jenkins for clear understanding. The api requires driver sessionId as api path param, status(passed or failed) and reason(if failed) as body.
I am able to get the status and reason from karate.info.errorMessage after configuring afterScenario for the feature. But my problem is to get the browserstack sessionId.
To get the driver.sessionId in afterScenario, i'm getting error as "driver" is not defined. I guess driver object is getting killed in between each execution of scenario outline and the afterScenario.
Is there any way to keep the driver alive until the afterScenario is completed?
or
any other alternatives like implementing ExecutionHook class or any other class through which we can get the driver details?
Please help. Thanks in advance.
UPDATE:
I'm using Java 8 and karate version 0.9.6
Below is my code:
Test Feature -
Feature: Test Feature
Background:
* def scenarioStatus =
"""
{
"status": "passed",
"reason": ""
}
"""
* configure afterScenario =
"""
function(){
if(karate.info.errorMessage){
scenarioStatus.status = 'failed';
scenarioStatus.reason = karate.info.errorMessage;
}
karate.log('session id : ' + karate.get('sessionId'));
// karate.call('browserstack.feature', scenarioStatus);
}
"""
#dummyMobileBrowser
Scenario Outline: Dummy Scenario
* def browserTestName = karate.info.scenarioName + ' - '
* call read('driver.feature#initializeDriver')
* def sessionId = driver.sessionId
* call read('loginPage.feature#login')
# I'm defining array of device or browser configs in karate-config.js
Examples:
| deviceConfigs |
driver.feature
Feature: Driver Related Feature
Background:
* def jsUtils = read('classpath:jsUtils.js')
* def getDriverConfig =
"""
function(){
if(browserstack == "yes"){
var configResult = karate.call('driver.feature#createBrowserStackConfig');
var browserstackConfig = configResult.browserstackConfig;
return browserstackConfig;
}else{
return deviceConfigs[__num];
}
}
"""
#initializeDriver
Scenario: Initialize Driver
* def driverConfig = getDriverConfig()
* configure driver = driverConfig
* print 'Driver Config: ', driverConfig
* driver envHost
# also tried to def here
# * def sessionId = driver.sessionId
# * eval scenarioStatus.browserstackSessionId = sessionId
# * karate.write(sessionId, 'classpath:browserstackSessionId.txt')
* driver.fullscreen()
#takeScreenshot
Scenario: Take screenshot
* driver.screenshot()
#createBrowserStackConfig
Scenario: Create Browserstack Config
* def deviceCapabilities = deviceConfigs[__num]
* def driverUrl = 'https://' + browserstackUsername + ':' + browserstackKey + '#' + browserstackUrl + '/wd/hub'
* eval commonCapabilities.build = (karate.match(typeof browserstackBuildName, 'undefined').pass) ? commonCapabilities.build + currentEpochTime : browserstackBuildName
* def desiredCapabilities = karate.merge(deviceCapabilities, commonCapabilities)
* def driverType = (karate.match(desiredCapabilities.browserName, "#notnull").pass) ? desiredCapabilities.browserName : desiredCapabilities.browser + 'driver'
* eval driverType = (karate.match(driverType, 'firefoxdriver').pass) ? 'geckodriver' : driverType
* eval desiredCapabilities.name = (karate.match(desiredCapabilities.browserName, "#notnull").pass) ? desiredCapabilities.browserName : desiredCapabilities.browser
* eval desiredCapabilities.name = browserTestName + desiredCapabilities.name
* def capabilities = karate.merge(deviceCapabilities, commonCapabilities)
* eval capabilities.name = (karate.match(capabilities.browserName, "#notnull").pass) ? capabilities.browserName : capabilities.browser
* eval capabilities.name = browserTestName + capabilities.name
* def browserSession = { desiredCapabilities: '#(desiredCapabilities)', capabilities: '#(capabilities)' }
* def browserstackConfig = { type: '#(driverType)', webDriverSession: '#(browserSession)', start: false, webDriverUrl: '#(driverUrl)' }
Even if the driver is not callable - you should be able to access variables, right ?
So if you did this within the normal test-flow:
* def sessionId = driver.sessionId
Then the sessionId variable should be directly accessible in the after-hooks. Do karate.get('sessionId') if needed, try it and please comment below if it works.

Karate feature using different ports

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?

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

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

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

Is it possible to have multiple JS functions inside one JS file of karate framework?

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