how to dynamically set an value in json read from file in Karate - karate

I want to dynamically set value for some elements in JSON(read from a file) using data driven feature of KARATE framework. Here are more details:
request.json -> { wheels : <wheel>, color: '<color>' }
Feature: Read json input from file and iterate over data table values
Background:
* url ''
* def reqJson = read('request.json')
* print reqJson
Scenario Outline: Test file read
# I want to avoid writing below set statements for each element in request
#* set reqJson.wheels = <wheel>
#* set reqJson.color = '<color>'
Given path ''
And request reqJson
When method POST
Then status 200
And match response contains {mode: '<result>'}
Examples:
| wheel | color | result |
| 4 | red | car |
| 2 | any | bicycle |
I am developing automation framework using Karate, my intention is to save sample request in JSON file for a given API and then during execution I want element values to be replaced with the ones given in the table above.I don't want to write set statement for each element either(commented lines above)
P.S.: I tried with calling other feature file using table approach. However, I want to keep one feature file per API, hence want to know if there is any way possible for the above approach

I think you have missed embedded expressions which is simpler than the set keyword in many cases, especially when reading from files.
For example:
request.json -> { wheels : '#(wheels)', color: '#(color)' }
And then this would work:
* def wheels = 4
* def color = 'blue'
* def reqJson = read('request.json')
* match reqJson == { wheels: 4, color: 'blue' }
If you go through the demo examples you will get plenty of other ideas. For example:
* table rows
| wheels | color | result |
| 4 | 'blue' | 'car' |
| 2 | 'red' | 'bike' |
* call read('make-request.feature') rows
And where make-request.feature is:
Given path ''
And request { wheels: '#(wheels)', color: '#(color)' }
When method POST
Then status 200
And match response contains { mode: '#(result)' }

Related

I want to run Scenario Outline in loop for one of the variable configurable

I have use case in which I am making server name configurable using Scenario outline for get call. But I also want to make another variable like ID configurable. I want using that id it should run for all server name mentioned in Scenario Outline. How can we achieve that?
Example
Scenario Outline: Test one get call
Given url: 'https://' + server+ 'v1/share/12345/profit'
When method get
Then status 200
Examples:
|server|
|server1|
|server2|
|server3|
|server4|
In above example server name, I made it configurable using scenario outline, but I want to make number entered in URL configurable & want that to run for all servers. How I will achieve that?
Just use another variable.
Examples:
| server | id |
| foo | 1 |
| foo | 2 |
| bar | 1 |
| bar | 2 |
And if you want to dynamically generate data using a function, all that is possible. Refer: https://github.com/karatelabs/karate#json-function-data-source

Converting Datatable to object with null values

Hi Everyone just wondering if I am following best practices here.
I have step defintions like the following
public class StepDefinitions {
#DataTableType
public Author authorEntry(Map<String, String> entry) {
return new Author(
entry.get("firstName"),
entry.get("lastName"),
entry.get("famousBook"));
}
#Given("There are my favorite authors")
public void these_are_my_favourite_authors(List<Author> authors) {
// step implementation
}
}
and my feature file could then be something like
Feature: this is a feature
Scenario: this is a scenario
Given There are my favorite authors
|firstName| lastName |
| first | last |
Scenario: this is another scenario
Given There are my favorite authors
|firstName| lastName | famousBook |
| first | last | book |
So in the first step it will create an Author object but with famousBook == null.
Since I am creating objects used for REST requests and jackson will ignore null values is it okay to create objects like this?
You are using wrong data structure for your examples. You can refer to this resource giving the examples of different table types.
In your case you have a table
|firstName| lastName |
| first | last |
and try to parse it into Map<String, String> entry which would result in the following map:
[key1 = firstName, value1 = lastName]
[key2 = first, value2 = last]
If you need to treat it like header in top line then you need to parse it into List<Map<String, String>>

How to parameterise externally saved sql query in karate-dsl

I have a situation where I need to use DB and I am storing qll queries externally as .txt. I want to execute these queries with different iterations hence I am using a Scenario outline.
I would like to know what is the better way to achieve this. Currently, I am using the below code but need to repeat replace code for all the parameters.
SELECT REWARDS_POINTS
FROM ABC Table
WHERE IS_ACTIVE = <active>
AND DISCOUNT_TYPE = <discount>
AND PRODUCT_TYPE = <product>
Scenario Outline: sample
* def query = read("classpath:priceQuery.txt")
* replace query.active = <active>
* replace query.discount = <discount>
* replace query.product = <product>
* print 'query is > ', query
Examples:
|discount|active|product|
| 5 |1|toy|
I think it is fine as it is. You can also do this, refer docs: https://github.com/intuit/karate#replace
* replace query
| token | value |
| active | active |
| discount | discount |
| product | product |
But please note that replace is just a convenience built-in to Karate. You can easily write a JS or Java utility and use it. So assuming you have defined a re-usable function called prepare() which can retrieve variables e.g. using karate.get() and even update using karate.set() you can end up with this:
* def query = prepare('classpath:priceQuery.txt')
There are many options. It is up to your knowledge of Karate and some creativity.

karate - Can we fetch data from excel file in karate? if yes then can we set the fetch data in examples in scenario outline?

Examples:
|sku_code |property_code |sale_price |override_source|persistent_override | stay_date|
|'48' | '0001661' | 2000 |'DASHBOARD' | 'true' | 2 |
like I have this data hardcoded , I want this data to fetched from excel sheet!
Yes you can use csv to do it using Dynamic scenario outline in karate
Example from karate demo:
Scenario Outline: cat name: <name>
Given url demoBaseUrl
And path 'cats'
And request { name: '<name>', age: <age> }
When method post
Then status 200
And match response == { id: '#number', name: '<name>' }
Examples:
| read('kittens.csv') |
Links:
Dynamic csv demo
Dynamic scenario outline doc

Use random var in behat tests to produce unique usernames

Right now I am creating users using something like the following
Given users:
| name | status | roles |
| kyle | 1 | authenticated user |
| cartman | 1 | admin |
Is there a possibility to add random strings in these names?
If I didn't misunderstand, you can do this instead.
Gherkin
Scenario: Create random users
Given I create "3" users
FeatureContext
var $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
var $status = [0, 1];
var $roles = ['authenticated user', 'admin', 'superman'];
/**
* #Given /^I create "([^"]*)" users$/
*/
public function createDummyUsers($count)
{
for ($i = 0; $i < $count; $i++) {
$name = substr(str_shuffle($this->str), 0, 8);
$status = $this->status[array_rand($this->status, 1)];
$role = $this->roles[array_rand($this->roles, 1)];
echo "You've just created $name - $status -$role" . PHP_EOL;
}
}
Prints
You've just created mqBWAQJK - 1 - superman
You've just created WYuAZSco - 0 - admin
You've just created HCNWvVth - 1 - admin
You've just created EmLkVRpO - 1 -superman
You've just created pxWcsuPl - 1 -authenticated user
You've just created mLYrlKdz - 0 -superman
The RandomContext functionality from drupal/drupal-extension allows for usage like this:
Given I fill in "E-mail address" with "<?username>#example.org"
or
Given users:
| name | email | status | roles |
| <?standard> | <?standard>#example.org | 1 | authenticated |
| <?admin> | <?admin>#example.org | 1 | admin |
Each token (eg <?username>, <?firstname>) used in a feature will be randomly transformed with a (random string) value for that feature execution. This is implemented with the use of Behat's #Transform functionality, meaning that your tokens will be substituted before execution of that step - so it works to generate random inputs anywhere you might need to use random input as part of your feature.
You can reference the same token later in your feature, eg to verify that the random value input earlier has been returned correctly, and the randomly generated value will be recalled. So, the first and second usages of <?admin> in the example above will both be replaced by the same generated value.
If you are using drupal/drupal-extension then this can be enabled by adding Drupal\DrupalExtension\Context\RandomContext to the enabled contexts in your behat.yml.
If you aren't using Drupal, then the source linked above will demonstrate how you could implement the same for your own usage.
I've created a solution on that you can try.
https://github.com/JordiGiros/MinkFieldRandomizer
MinkFieldRandomizer is a random (with sense) information generator for filling browser form fields in Behat Mink Selenium tests. It brings the option to run your tests in a more realistic way changing the information you use to fill in the forms in every test you run.
You can easily add it to your project by Composer.
One example:
Then Fills in form fields with provided table
| "f_outbound_accommodation_name" | "{RandomName(10)}" |
| "f_outbound_accommodation_phone_number" | "{RandomPhone(9)}" |
| "f_outbound_accommodation_address_1" | "{RandomText(10)}" |
I hope you try it!
And you're welcome to add new functionalities or fork it or do wathever you want.
Cheers