Overriding variable in called feature - karate

I'm using Karate to write integration tests for a REST API. In all test scenarios I have to login users to get an authentification token for all calls related to the REST API. So I want to put the login logic into a separate Karate feature, so I don't have to copy and paste the login API call to all other Scenarios.
From the doku I was able to figure out how to call my login.feature in another feature (logout, with needs a logged in user). I'm also able to pass the username and password to the called login.feature from my calling logout.feature. But I also want my login.feature to be executable on it's own, so I have to define username and password in the login.feature. But if I do so, I'm not able to override this variables from the calling feature.
If I run the logout.feature like follows, the login.feature is not using the email parameter I'm providing in the logout.feature If I delete the email variable from login.feature, it is using the parameter from logout.feature, but then I can't run the login.feature on its own.
Calling logout.feature:
Feature: Login/Logout Test
Background:
* url urlBase http://localhost:5000
* def login = call read('classpath:ires/session/login.feature') {email: "user1#test.com", password: "test"}
* def authToken = login.authToken
Scenario: Testing logout via PUT
Given path '/sessions/logout'
Given param TOKEN = authToken
And request {}
When method PUT
Then status 202
Called login.feature:
Feature: Logs in the given user
Background:
* url urlBase http://localhost:5000
* def email = "user2#test.com"
* def password = "test"
Scenario: Test login via POST
Given path '/sessions/login'
And request {email: '#(email)', password: '#(password)'}
And print email
When method post
Then status 200
And def authToken = response

My suggestion is you can create a login-caller.feature that will call the login.feature with the proper argument passed. Another option is to have email and password defined globally in karate-config.js.
I don't recommend depending on undefined variables as it leads to maintainability problems in the long run, but you can do this kind of conditional check:
* def email = typeof email == 'undefined' ? 'user2#test.com' : email

Related

How to access variable declared on Karate mock server or record requests received on mock and somehow send it to main feature file

I have a main feature file which brings up the mock and call an API.
This main API will call other API in the background which goes to my karate mock server. I am able to validate incoming request and send out a response as well.
In this incoming request on mock, I receive a transactionRef, which then appears in the response of my main API.
The flow is something like this
API1 Request
API2 Request (transactionRef) -> API2 Response
API1 Response (transactionRef)
What I want to check is these both are same. Is that possible? I tried setting a variable in mock feature but not able to access it in main feature.
Feature: stateful mock server
Background: Mock
Scenario: pathMatches('/abcd') && bodyPath('/Envelope/Body/infoRequest')!= null
* match karate.typeOf(request) == 'xml'
* xml respInfo = read('classpath:org/xbspro/hos/payloads/infoResponse.xml')
* def tranRef = $request/Envelope/Body/infoRequest/transactionId
* set respInfo/Envelope/Body/infoResponse/transactionId= tranRef
* def response = respInfo
Above is my mock feature. Below is my main feature
* call read('classpath:Abstract.feature')
* xml remResp = response
* match remResponse //transactionId == tranRef
You have 2 options.
You already know how to capture state in the mock by using global variables. Just add a custom end-point which you can call from your API test to get it. Refer: https://stackoverflow.com/a/63512034/143475
Refer to this example where you can use Java to "connect" a mock and the test: https://twitter.com/getkarate/status/1417023536082812935

Store all tokens for different users and run tests in parallel

Bothering again but really need a piece of advice from the community
Imagine I have 3 user types:
read
write
admin
with different permissions and I need to request a token for all 3. Then store each token and then be able to run some tests for read user, other tests for admin and some tests for all 3 profiles.
Is it possible to handle with Karate?
I know there is ScenarioOutline but that would require me to add this ScenarioOutline to every single scenario.
Also thought about having a json.file and run my CreateToken.feature with every single user that is in this users.json but then I don't know how to tell my tests which token to use.
My Create Token feature file for the basic profile is:
Feature: Create Token
Background: URL definition
* url authUrl
Scenario: Create Token for Read user
When path '/v2/u/login'
And request
"""
{
"username": "#(readUser)",
"password": "#(password)"
}
"""
And method Post
Then status 200
* def readAccessToken = response.token
in karate-config.js I have defined the 3 users:
var config = {
readUser: 'readuser#example.com',
writeUser: 'writeuser#example.com',
adminUser: 'adminuser#example.com',
password: karate.properties['password'],
}
const readAccessToken = karate.callSingle('classpath:helpers/CreateToken.feature', config).readAuthToken
karate.configure('headers', {Authorization: 'Bearer ' + readAccessToken})
In the Feature files:
Scenario: Get explore page
#This should run for all 3 types of users
When path '/a/v2/explore'
And method Get
Then status 200
And match response contains exploreResponse
Scenario: Get user list
#This should run only for admin user
When path '/users'
And method Get
Then status 200
Sorry but I can't the best way to setup this
Thanks!
I would just create the 3 tokens using call-single, keep them as global variables in config and then use them the way you see fit.

KARATE - How to get data from response/by running another feature file

I have a feature file that connects to oracle database and gets data and prints in response. Below's the sample piece of code.
dbconnect.feature
def queryDATA = 'QueryData'
When def db = DBConnect.queryDB(host, port, serviceName, username, password, queryDATA)
Then print db
***Note that I have a few more lines of code before this which sets up jdbc and connects to DB with proper credentials
Post this, I need to run real test case which inturn should call dbconnect.feature to get DATA and feed to request. It goes like this;
UserDetails.feature
Background:
* url 'https://soaheader-env-name.com'
* header agent_uid = 'AUTO_TST'
* configure ssl = true
* header Authorization = call read('classpath:ABC/JSFiles/auth.js') {
username: 'XYZ', password: '123' }
* configure logPrettyResponse = true
* configure logPrettyRequest = true
#UserDetails
Scenario Outline: Get User Details
Given path 'somefooterurl/account/<accountno>/user-details-summary'
When method get
Then status 200
Then match response contains 'OK'
I really need to use the data from dbconnect.feature and provide in UserDetails.feature request.
Please suggest a way/ help me with the proper path in karate-github.
A simple example for you,
* def dbCall = call read('dbconnect.feature')
* def db = dbCall.db
please refer karate documentation
Other references if you want to pass values to your feature:
Properly calling an authorization Karate feature with arguments
karate - How to set specific values in a feature file which is called internally

karate | xml post method exeuction

I’m having issue with xml post request where post method is not executed. When I try to post same request body in post man it worked.My test is success with 200 but actual request is not executed.
Please let me know if I’m missing
To pass the request body,I’m calling through java object and payload is correctly constructed and printed.In execution test is success and doesn’t print response.But actually test is not executed.
Only headers are printed.
***************** create-user.feature*****************
Feature: create ims user for provided country
Requires country code,
Background:
# load secrets from json
* def createuser = Java.type('com.user.JavaTestData')
* def create = createuser.createUser("US")
Scenario: get service token
Given url imscreateuserurl
And request create
When method post
Then status 200
* print response
***************** create-user.feature*****************
Here is java class
public class JavaTestData {
private static final Logger logger = LoggerFactory.getLogger(JavaTestData.class);
public static String createUser(String countryCodeInput) {
logger.debug("create user for country code input", countryCodeInput);
Unless you post a full working example, no one can help you. Pretty clear that the value of create is null or empty.
Also I personally think you are wasting your time using Java. The whole point of Karate is to avoid using Java as far as possible.
Look at these examples for ideas: https://github.com/intuit/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/xml/xml.feature
Edit: also refer to the doc on type-conversion: https://github.com/intuit/karate#type-conversion
#Peter, here is my feature file
Feature: create ims user for provided country
Requires country code,
Background:
# load secrets from json
* def createuser = Java.type('com.adobe.imscreateuser.JavaTestData')
* def create = createuser.createUser("US")
Scenario: get service token
Given url imscreateuserurl
And header Content-Type = 'application/xml; charset=utf-8'
And request create
When method post
Then status 200
* print response
I have performed print for create and showing complete payload.At when method post -> statement its going as null or empty...
Not sure where it is missing

Changing Postman request name from prerequest script

I'm currently trying to implement few Postman requests with CSV data sources.
For instance let assume I have request named "Open as user".
In csv file, I have bunch of user credentials with description field that describes user role.
I would like to have the ability to change request names to reflect each user roles.
For instance, if the request is made as the admin user I would like request name in reports and runner to be "Open as user admin".
In documentation, I've found pm.info.requestName variable but seems it is read-only.
I put following in Pre-request Script
pm.info.requestName = "1";
console.log(pm.info.requestName);
but got "Open as user" value instead of assigned "1".
Have anyone tried to do the same trick or know whether it is possible at all?
I was looking for a solution to this as well and i have solved it in the following way:
Use the 'Pre-request Script' to determine what role the user has.
Set the url to a environment- or global-variable
Use that url in the request, like {{url}}
Clear the environment- or global-variable in the 'Tests' tab
In my case i used the environment variable to get the environment, instead of you, using the data variables.
var environment = pm.environment.get("environment");
var url;
switch(environment) {
case "test":
url = pm.globals.get("test-url");
break;
case "acc":
url = pm.globals.get("acc-url");
break;
case "prod":
url = pm.globals.get("prod-url");
break;
default:
url = pm.globals.get("test-url");
break;
}
pm.environment.set("url", url);
Hope this helps!
I'm afraid that you can't do that. pm.request object is available only after request execution. I even think that you can't access the request name the way you want (I though I would find it in the 'id' member, but it was empty)
Have a look here to see what's available in terms of members and methods concerning the request object.
You may find another way of proceeding (maybe duplicate your test, rename it with admin and, under proper condition, launch the admin request instead of the common user request ? it's kind of a hassle just for a test name)
I think about something else: you could just customize your assertions label, that's what I do to have 'readable' test names in TFS reports. In the Tests tab :
test_name = "[ "+ request.name + " ] - ";
and for each assertion (example):
tests[test_name + "Status code is 200"] = responseCode.code === 200;
This gives, in the response Tests tab, something like :
PASS [Get all configuration]-Status code is 200
Under a particular condition, you can replace request.name with a custom string or do request.name + "admin" ...
hope this helps