is it possible to overwrite parameters in a called feature file, which have been defined in background or scenario? - karate

https://github.com/intuit/karate#calling-other-feature-files
The link above contains an example of calling a feature file in order to reuse the code. The feature file which is reused is called with the inputs
Background:
* configure headers = read('classpath:my-headers.js')
* def signIn = call read('classpath:my-signin.feature') { username:'john', password: 'secret' }
* def authToken = signIn.authToken
The called my-signin.feature:
Scenario:
Given url loginUrlBase
And request { userId: '#(username)', userPass: '#(password)' }
When method post
Then status 200
And def authToken = response
...
In this example the my-signin.feature must be run with the inputs username and password. I know that if you had the following:
Background:
* def username = "foo"
* def password = "secret"
at the top of the my-signing.feature file, the parameters input by the feature attempting to reuse the feature file would be overwritten.
My question is:
If reuse is the main interest of being able to call other feature files, is there a way to have the calling feature file overwrite the username and password parameters if they had been defined in the background?
It seems to me that having the background overwrite the input parameters instead of vice versa makes it harder to reuse *.feature files. I know I found it a little frustrating on my project not being able to reuse tests I had already written without refactoring out the reusable code into another file.

Any called feature in karate will have a magic variable __arg, you can check for this before assigning values to your variables in your called script.
Background:
* def username = (__arg == null) ? "foo" : __arg.username
* def password = (__arg == null)? "secret" : __arg.password
this will check for values passed,
if none passed it will assign default
* def signIn = call read('classpath:my-signin.feature')
if passed with arguments passed arguments will be assigned
* def signIn = call read('classpath:my-signin.feature') { username: 'notfoo', password: 'notsecret' }
For simplicity don't have anyother parameters that need to passed other than this.

Related

get the params value from a variable

i have one feature file as
Feature: Getting the Token
Background:
header Content-Type 'application/json'
def CookieGenerator = Java.type('com.ade.Helpers.CookiesGenerator');
def endpoints read('classpath: src/test/java/com/ade/resources/endpoints.json')
Given url endpoints.token
Scenario: To check the Schema of the response
Given cookies (new CookieGenerator().getCookieValue())
When method GET
Then status 200
def txnToken = response
#print token
from above code i am getting Token's value as something like this "gdjsgjshjhsjfhsg646"
now i have another feature file where i have to use above Token's value in my query parameter value as
Feature: Testing datent Name and Client
Background:
header Content-Type 'application/json""
def endpoints read('classpath:src/test/java/com/ade/resources/endpoints.json") def CookieGenerator Java.type('com.ade.Helpers.CookiesGenerator");
call read('Token.feature')
Given url baseUrl+endpoints.dit.Client.path
Scenario: To check the Schema of the response
Given def head read('classpath:src/test/java/com/ade/resources/reqpay.json") =
def req head.data[1]
And cookies (new CookieGenerator().getCookieValue())
And request req
And param {txntoken = txnToken}
When method post
Then status 200
from above my endpoint should be like https://something.com/clients?txntoken='gdjsgjshjhsjfhsg646'
but i am getting as https://something.com/clients?txntoken=txnToken
https://something.com/clients?txntoken='gdjsgjshjhsjfhsg646'
Your post is hard to read, as #peter-thomas said, please try formatting it better in the future, or edit the post if I haven't answered your question.
I believe what you're looking for is described in the documentation here
* def signIn = call read('classpath:my-signin.feature') { username: 'john', password: 'secret' }
* def authToken = signIn.authToken
you can see how information can be passed
I also asked a similar question fairly recently here
relevant bit here:
* def key = karate.call('ReadRoundUpSubscription.feature');
* def keyvalue = key.acckey
i prefer to call features like this, and not defining things in the reusable feature.

How to reuse assertions for scenarios in single feature file using Karate?

I want to assert responseTime of all scenarios. But i do not want to repeat the assertion code in every scenario. Below is my feature file:
Feature: Reqres api test cases
Background: base url
Given url base_url
Scenario: list single user get request
Given path single_user_path
When method get
Then status 200
And assert responseTime < 4000
Scenario: create user using post and inline json payload
* def path = '/users'
Given path path
And request {"name": "morpheus","job": "leader"}
When method post
Then status 201
And assert responseTime < 4000
In the above code block, I want to avoid responseTime assertion duplication. How to achieve this in karate?. Please help.
No this is not supported and not planned either. It is unlikely every API call will have the exact same SLA. Also this is what the Gatling integration is for: https://stackoverflow.com/a/55146463/143475
EDIT as an example of how you can do "reuse" of response assertions:
Feature:
Background:
* def validateResponse =
"""
function() {
var contentType = karate.get("responseHeaders['Content-Type'][0]");
if (contentType !== 'application/json') {
karate.fail('content type is not json');
}
var responseType = karate.get('responseType');
if (responseType !== 'json') {
karate.fail('response type is not json');
}
}
"""
Scenario:
* url 'https://httpbin.org/post'
* request { foo: 'bar' }
* method post
* validateResponse()
Please note that I absolutely don't recommend the above approach because of reasons best explained here: https://stackoverflow.com/a/54126724/143475

Using karate built-in functions and api

Ok, so I am going to explain what my scenario is and how I have implemented it using karate. But i am looking for a better way of doing things which make my tests more readable and also want to use karate's api rather than too much javascript.
Scenario: I have a filter parameter for the api endpoint that i am testing and this filter param takes a json object of key-value pairs. So i have done the following:
Have created a filter-template.js as below:
function() {
var filter_params = {
jobId:null,
customerIds:[],
filterValues1:[],
filterValues2:[],
};
return filter_params;
}
I read this template in my karate scenario and because this is a template, at runtime i set the values in this template and run the test. I will have different values for key-value pairs so each test will set its own filter condition.
This is done by writing custom js function that takes the template as argument and also the filter condition values (referring to arg function argument below), sets the passed conditions to specific key's and then returns json object. Code below:
Scenario: Set filter scenario
* def filter_template = call read('filter-template.js')
* def filter_vals_list = [1001,1002]
* def filter_condition = { cnd1: 'foo', cnd2: '#(filter_vals_list)' }
* def setFilter =
"""
function(arg) {
var i;
var filter = arg.template;
filter.jobId = arg.condition.cnd1;
for(i=0;i<arg.condition.cnd2.length;i++)
{
filter.filterValues1.add(arg.condition.cnd2.get(i));
}
return filter;
}
"""
* def getFilter = call setFilter { template: '#(filter_template)',
condition: '#(filter_condition)' }
I then pass the getFilter as a param to my api request.
What I am hoping to understand is:
How can i get away from using JS loops above when setting filter?
Use karate's in-built functions like karate.map(), karate.forEach() to simplify the tests.
Any better approach if possible on tackling this scenario.
Help and guidance much appreciated.
From what I understood, I have simplified your scenario below:
* def filter_vals_list = [ 1001, 1002 ]
* def job_id = 'foo'
* def filter_template =
"""
{
jobId: '#(job_id)',
customerIds: [],
filterValues1: '#(filter_vals_list)',
filterValues2: [],
}
"""
Let me know if I missed anything. Please refer embedded expressions: https://github.com/intuit/karate#embedded-expressions
Now, you can easily use a re-usable JSON for the template, by changing the last step to the below, and yes - embedded expressions work even in re-usable JSON files !
* def filter_template = read('filter-template.json')
You may get even better ideas once you try the data-driven Scenario Outline. So hope that makes it clear how you are un-necessarily complicating things with JS ! You don't even need karate.map() etc.

How to pass parameters from one feature to another for form field?

I have a feature A with:
* form field username = 'user#gire.com'
* form field password = 'usergire'
And another one with:
* def token = call read ('A.feature') here I would like to send username and password.
I followed examples in Calling other *.feature files but it doesn't work? Is it possible to do this in Karate? Because I need to call A.feature in other features and send 2 paremeters. thanks
Read the doc carefully: Calling other Feature files. In feature A:
* form field username = email
* form field password = password
And call this:
* call read('A.feature') { email: 'user#gire.com', password: 'usergire' }

How can I have a domain object's .save() method fail in an integration test?

For an integration test, I want to have a .save() intentionally in order to test the according else-condition.
My class under test does this:
From UserService.groovy:
User user = User.findByXyz(xyz)
if (user) {
// foo
if (user.save()) {
// bar
} else {
// I WANT TO GET HERE
}
}
The approaches I've tried so far failed:
What I've tried in in UserServiceTests.groovy:
def uControl = mockFor(User)
uControl.demand.save { flush -> null } // in order to test a failing user.save()
def enabledUser = userService.enableUser(u.confirmationToken)
uControl.verify()
// or the following:
User.metaClass.'static'.save = { flush -> null } // fails *all* other tests too
How can I get to the else-block from an integration test correctly?
You should almost never have a need for mocking or altering the metaclass in integration tests - only unit tests.
If you want to fail the save() call just pass in data that doesn't validate. For example all fields are not-null by default, so using def user = new User() should fail.
maybe you could try changing the 'validate' to be something else - by using the same meta class programming that u have shown .
That way, if the validate fails, the save will certainly fail
What I do in such cases:
I always have at least one field which is not null.
I simply don't set it and then call .save()
If you want to achieve this on an object already in the database, just load it using find or get and set one of the not null values to null and then try to save it.
If you don't have Config.groovy configured to throw exceptions on failures when saving it will not throw the exception, it simply won't save it [you can call .validate() upfront to determine whether it will save or not and check object_instance.errors.allErrors list to see the errors].