Using placeholders in feature file of Behat - testing

I have a feature file as below
Feature: Test send API request
In order to test my API
As a Tester
I want to be able to perform HTTP request
Scenario:Sending GET request to activate user after registration api to verify whether the response code is 403 when 'X-Auth-Token' is missing
When I have a request "GET /api/activateuser?token=:tokenhash"
And I set the "Accept" header to "application/json"
And I set the "X-Auth-Token" header to "0125ee8dfe42bafbec95aa0d2676c91d8a780715b76504cf798aae6e74c08a30"
.
.
Scenario:Sending GET request to activate user after registration api to verify whether the response code is 403 when 'X-Auth-Token' is invalid
When I have a request "GET /api/activateuser?token=:tokenhash"
And I set the "Accept" header to "application/json"
And I set the "X-Auth-Token" header to "0125ee8dfe42bafbec95aa0d2676c91d8a780715b76504cf798aae6e74c08a30"
.
.
Scenario:Sending GET request to activate user after registration api to verify whether the response code is 404 when userid is invalid
When I have a request "GET /api/activateuser?token=:tokenhash"
And I set the "Accept" header to "application/json"
And I set the "X-Auth-Token" header to "0125ee8dfe42bafbec95aa0d2676c91d8a780715b76504cf798aae6e74c08a30"
.
.
In the request 'X-Auth-Token' parameter will be same for all scnerios, which will not change frequently. So I was thinking of setting it to some variable and use that variable in the scenarios. But havent found any method to do this in behat. It is okay evenif we can set the value in behat.yml and use it in the scenario, but even that was not possible.
Also i have more than one parameters that needed to be set like this.
So is there any method to set the value once and resuse it in every scenario?

You can use combination of two.
A Background where you run all common steps for all scenarios.
A BeforeFeature hook that prepares your current test scope.
What happens below is this.
#BeforeScenario tag runs prepare() method before everything else to set your variable for current feature session.
Step definitions under Background task run before each scenarios so you don't have to duplicate them in each scenarios.
NOTE: If your X-Auth-Token won't change frequently then just hard-code the value in your FeatureContext file and don't implement step 2 above at all. My example is there to give you an idea of some useful features of Behat.
EXAMPLE
Adjust it for your need!
FeatureContext
namespace Your\Bundle\Features\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
...
class FeatureContext ...
{
private static $xAuthToken;
/**
* #BeforeFeature
*/
public static function prepare()
{
self::setXAuthToken();
}
private static function setXAuthToken()
{
self::$xAuthToken = 123;
}
/**
* #Given /^I set the header "([^"]*)" to "([^"]*)"$/
*/
public function iSetTheHeader($header, $value)
{
// Do whatever you want
}
/**
* #Given /^I send "([^"]*)" request to "([^"]*)"$/
*/
public function iSendRequest($method, $url)
{
// Do whatever you want
}
/**
* #Given /^the X-Auth-Token is available$/
*/
public function theXAuthTokenIsAvailable()
{
echo self::$xAuthToken;
}
}
Feature file
Feature: Shared token
Background: I am common to all scenarios
Given I set the header "Accept" to "application/json"
When I send "GET" request to "/api/hello-world"
Scenario: 1
Given the X-Auth-Token is available
Scenario: 2
Given the X-Auth-Token is available
RESULT

Related

Can you define headers in Karate tests? [duplicate]

So I've managed to write a bunch of tests and in every feature file I set the same request headers.
For example:
Given url appUrl
And path '/path'
* header Accept = 'application/json'
I'd like to know if there's a way to set a header once so that it is set before each scenario is run. I've read the documentation and tried the callSingle method as follows in karate-config.js:
karate.callSingle('classpath:api/Utilities/Feature/header.feature');
header.feature looks like:
Feature: common routing that sets the headers for all features
Background:
* configure headers = { Accept : 'application/json' }
And example feature where I expect the headers to be preset:
Feature: Header Preset
Scenario: I expect the header to be set
Given url appUrl
And path '/path'
When method get
Then status 200
* print response
#I expect the response to be returned in JSON format
However I'm unable to get this working. I don't think I've understood how the callSingle method works. Some pointers would be helpful. Thanks.
Ignore callSingle for now and focus on configure headers.
I think you are missing one step - which is to ensure that configure headers has been "applied" before each Scenario. If you are 100% sure that this applies "globally", just do this in karate-config.js:
karate.configure('headers', { Accept: 'application/json' });
Else you use the Background (in each feature):
* configure headers = { Accept: 'application/json' }
Typically you have more steps that are common, so you have them in a "common" feature file and call that for every test. Refer: https://github.com/intuit/karate#shared-scope

Advice for implementing custom authentication scheme [duplicate]

First of all, thanks for build karate it's a very useful for test API's and UI's. We are using it to test a lot of our endpoints but we would like to know if there is a way or which is the best approach to handle requests with signature as part of the request in the header.
In our case we have two headers:
ApiKey: this value is always the same
Signature: this value depends on the request body content
Is there any way to inject the signature value just before the request is executed based on the request body content?
Here you can see two samples of the requests
Sample 1:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'YYY'
And request { }
When method POST
Then status 200
Sample 2:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'ZZZ'
And request { name: 'John' }
When method POST
Then status 200
Thanks
Karate has a "hook" for generating headers, but as of now it is not "aware" of the currently built request body + headers: https://github.com/intuit/karate#configure-headers
We got a similar request here, and are thinking of adding this capability: How to retrieve raw request contents before making a REST call in Karate DSL?
Maybe the OAuth examples will give you the way forward for your case for now: https://stackoverflow.com/a/55055111/143475
Feel free to raise an enhancement request, and we can get this in to the next version (with your help to test it). I'm thinking - what if you are able to call karate.get('request') from within the header JS function.
But for now all you need to do is do something like this:
* def body = { some: 'json' }
* karate.set('requestBody', body)
* url someUrl
* request body
* method post
And in the header.js function
function fn() {
var body = karate.get('requestBody');
var sign = Utils.sign(body);
return { Signature: sign };
}
EDIT: this will be implemented in Karate 1.0 onwards: https://github.com/intuit/karate/issues/1385

How to handle requests with signatures on karate tests?

First of all, thanks for build karate it's a very useful for test API's and UI's. We are using it to test a lot of our endpoints but we would like to know if there is a way or which is the best approach to handle requests with signature as part of the request in the header.
In our case we have two headers:
ApiKey: this value is always the same
Signature: this value depends on the request body content
Is there any way to inject the signature value just before the request is executed based on the request body content?
Here you can see two samples of the requests
Sample 1:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'YYY'
And request { }
When method POST
Then status 200
Sample 2:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'ZZZ'
And request { name: 'John' }
When method POST
Then status 200
Thanks
Karate has a "hook" for generating headers, but as of now it is not "aware" of the currently built request body + headers: https://github.com/intuit/karate#configure-headers
We got a similar request here, and are thinking of adding this capability: How to retrieve raw request contents before making a REST call in Karate DSL?
Maybe the OAuth examples will give you the way forward for your case for now: https://stackoverflow.com/a/55055111/143475
Feel free to raise an enhancement request, and we can get this in to the next version (with your help to test it). I'm thinking - what if you are able to call karate.get('request') from within the header JS function.
But for now all you need to do is do something like this:
* def body = { some: 'json' }
* karate.set('requestBody', body)
* url someUrl
* request body
* method post
And in the header.js function
function fn() {
var body = karate.get('requestBody');
var sign = Utils.sign(body);
return { Signature: sign };
}
EDIT: this will be implemented in Karate 1.0 onwards: https://github.com/intuit/karate/issues/1385

Karate - Setting global request headers

So I've managed to write a bunch of tests and in every feature file I set the same request headers.
For example:
Given url appUrl
And path '/path'
* header Accept = 'application/json'
I'd like to know if there's a way to set a header once so that it is set before each scenario is run. I've read the documentation and tried the callSingle method as follows in karate-config.js:
karate.callSingle('classpath:api/Utilities/Feature/header.feature');
header.feature looks like:
Feature: common routing that sets the headers for all features
Background:
* configure headers = { Accept : 'application/json' }
And example feature where I expect the headers to be preset:
Feature: Header Preset
Scenario: I expect the header to be set
Given url appUrl
And path '/path'
When method get
Then status 200
* print response
#I expect the response to be returned in JSON format
However I'm unable to get this working. I don't think I've understood how the callSingle method works. Some pointers would be helpful. Thanks.
Ignore callSingle for now and focus on configure headers.
I think you are missing one step - which is to ensure that configure headers has been "applied" before each Scenario. If you are 100% sure that this applies "globally", just do this in karate-config.js:
karate.configure('headers', { Accept: 'application/json' });
Else you use the Background (in each feature):
* configure headers = { Accept: 'application/json' }
Typically you have more steps that are common, so you have them in a "common" feature file and call that for every test. Refer: https://github.com/intuit/karate#shared-scope

SoapUI correlation (property transfer)

I have a REST request that respond with the following:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlQwWE8xNnAtMmZzMWxremV5",
"expires_in": 2592000,
"token_type": "Bearer"
}
I want to take the value of access_token, store it in a property and reuse it for two subsequent requests.
Following some tutorial here, when running the request that obtains the access_token I get a:
error parsing target property: error unexpected element CDATA
But why?
There is no CDATA in my raw response.
If you've problems using transfer properties step to get the JSON value from your response, you can use a groovy test step to achieve your goal.
So create a groovy test step to parse your response, get your value and set it as a property (for example at testCase level) with the follow code:
import groovy.json.JsonSlurper
// get response using the name of your test step
def response = context.expand('${REST Test Request#Response}')
// parse response
def jsonResp = new JsonSlurper().parseText(response)
// get the token an set as a property in the testCase
testRunner.testCase.setPropertyValue('access_token',jsonResp.access_token)
Then in the other testSteps (REST or SOAP...) you can use the follow code to get the access_token value you set in the testCase:
${#TestCase#access_token}
Hope this helps,