Support passing from Scenario Outline to JSON file - karate

I am going to reuse some features and calling multiple features in a Scenario Outline.
Since the features being called are common, we would like to define its parameters in its own parameter file, while the parameter values are defined in placeholder.
We hope the placeholder can get the value from the Outline Examples.
How to make it?
Feature: verify parameter passing
Scenario Outline: verify 2 calls
* def result1 = call read('baseFeature1.feature')
* def result2 = call read('baseFeature2.feature') result1
* print result2
Examples:
| fooValue |
| value1 |
| value2 |
Feature: feature to verify the parameter passing, no input parameter
Scenario: feature 1
Given def payload = read('classpath:feature_1.json')
* print 'feature 1' + payload
Given def result = { "barValue": "barValue"}
Feature: feature to verify the parameter passing, with input parameter from last step
Scenario: feature 2
Given def payload = read('classpath:feature_2.json')
* print payload
feature_1.json
{
"foo": "#(fooValue)"
}
feature_2.json
{
"foo": "fooValue",
"bar": "#(result1.barValue)"
}

I think the version currently in development will make this possible. Can you take a look at this GitHub issue and see if this addresses your question: https://github.com/intuit/karate/issues/717
It will also be great if you can build from source and try this new capability.
Scenario Outline: magic variables with embedded expressions
* def expected = __num == 0 ? { name: 'Bob', alive: false } : { name: 'Nyan', alive: true }
* match expected == { name: '#(__row.name)', alive: '#(__row.alive)' }
* eval karate.set(__row)
# you can read from a re-usable JSON file instead of the line below
* match expected == { name: '#(name)', alive: '#(alive)' }
Examples:
| name | alive! |
| Bob | false |
| Nyan | true |

Related

how to call a feature file to generated a Get request , for each element in an ArrayList or JsonArray ( Created by Java function )

basically I want to achieve below result , where the list used in Examples: is dynamic
Scenario Outline:
def ss = 'https:testingurl/'+ < spaceCode > + 'trailPath';
Given url ss
And header Authorization = autGetToken()
When method get
Then status 200
Examples:
| spaceCode |
| space1|
| spac2|
| spaceAbc05|
| space.o2|
| spacesacc|
| spacere |
So I created one.feture and tried to call it from other feature file
one.feature
Background:
def ss = 'https:testingurl/'+ < spaceCode > + 'trailPath';
Scenario: need to run this scenario for each member of the spaceList ArrayList / JsonArray
Given url ss
And header Authorization = autGetToken()
When method get
Then status 200
* print response
* def count = response.value.length
* print count
* karate.set('total', karate.get('total') + karate.get('count') )
* print total
question
how to run above file for each element of the "spaceList" which is an Java ArrayList, i am creating this ArrayList by calling method getSpaceList()
i have tried to call it from other feature file like below
Method1
caller.feature
Background:
* def total = 0
* def helper = Java.type('shared.Helper')
Scenario Outline: calling other feature file for each element of the spaceList Array
def result = call read('one.feature')
Examples:
| spaceCode |
| helper.getSpaceList() |
Method2
caller.feature
Background:
* def total = 0
* def helper = Java.type('shared.Helper')
* def spaceList = helper.getSpaceList() // this returns around 20 different elements from a sql
Scenario Outline: calling other feature file for each element of the spaceList Array
def result = call read('one.feature')
Examples:
| spaceCode |
| spaceList |
i have also tried karate.forEach and karate.setUp
Try this example. Note how it will make two POST requests. Once you understand this, you should be able to do what you want.
Feature:
Scenario Outline:
* url 'https://httpbin.org/anything'
* request __row
* method post
* status 200
Examples:
| [{ a: 1 }, { a: 2 }] |

Use map object in karate framework

I am trying to create a scenario where:
Scenario Outline: Create a request
Given print 'reason=<reason>, detail=<detail>, metainfo=<metainfo>'
When call create_request
Then match response.message == "#notnull"
* call json_to_proto request
* print 'response \n', response
Examples:
reason | detail | metainfo
test | Testing | { foo: bar }
My concern is metainfo is defined as a map, "metainfo": "#(karate.get('metainfo', {}))" how do I set values for it as the current logic gives me error: org.graalvm.polyglot.PolyglotException: Expect a map object but found...
Please read this section of the docs: https://github.com/karatelabs/karate#scenario-outline-enhancements
You can use JSON like this. And note that you don't need the <foo> placeholder system. Normal variables work:
Scenario Outline: ${payload.foo}
* match payload == { foo: 'bar' }
Examples:
| payload! |
| { foo: 'bar' } |

Can we pass dynamic values within values in Scenario Outline in Karate

Scenario Outline: User payload validation
Given url usermessagesAPI
* request
"""
{
"first_name" : "<first_name>",
"last_name" : "<last_name>",
"transaction_id" : "<transaction_id>,
"user_message" : "<user_message>"
}
"""
When method POST
Then assert responseStatus == 202
Examples:
|first_name|last_name|transaction_id|user_message|
|xyz|xyz|87690|<?xml version=\"1.0\" encoding=\"UTF-8\"?><MsgId>201060024</MsgId><CreDtTm>2020-04- 14T13:45:02</CreDtTm>|
|abc|abc|76565|<?xml version=\"1.0\" encoding=\"UTF-8\"?><MsgId>7858757</MsgId><CreDtTm>2022-04-14T13:45:02</CreDtTm>| */
In the above example, how do I pass random values for MsgId and CreDtTm which are within the XML message
The data within the Examples: is fixed and cannot be changed at run-time. You can however do modifications within the Scenario Outline block. So I think you can achieve what you want. Here is an example:
Feature:
Scenario Outline:
* def rand = java.lang.System.currentTimeMillis()
* xml payload = message
* karate.set('payload', '/root/CreDtTm', rand)
* print payload
Examples:
| message |
| <root><MsgId>201060024</MsgId><CreDtTm></CreDtTm></root> |
There are other ways to modify an XML, for example using replace: https://github.com/karatelabs/karate#replace

Object.keys(data) Js fu not worked when pass Json object as def in Karate 0.9.5.RC5

Js File with following function
function fn(config) {
config.OAuth2 = function (data) {
var keys = Object.keys(data);
return keys;
}
return config;
}
Feature file with following steps
Feature: Sample Feature
Scenario Outline: Sample Scenario
#This is works
* def a = OAuth2({firstName: '<firstName>',lastName: '<lastName>'})
* print a
#This do not work
And def req = {firstName: '<firstName>',lastName: '<lastName>'}
* def b = OAuth2(req)
* print b
Examples:
| firstName | lastName |
| a | a1 |
Giving error at var keys = Object.keys(data);
javascript evaluation failed: OAuth2(req), TypeError: {firstName=a, lastName=a1} is not an Object in <eval>
Please don't use Object.keys() - use karate.keysOf() instead.

Using karate-config parameters in a feature file

The karate header examples do not show how to access config values other than baseUrl. When I switch environments (passing in -Dkarate.env=qual as part of the run command) then baseUrl is set correctly.
The problem is, I want to use other config values as shown here but when I run the test, it fails to access config.ApiKey correctly. Instead I get this error
html report:
file:/C:/bitbucket/karate-checkdigit-api/target/surefire-reports/TEST-features.checkdigitapi.VA.html
Tests run: 250, Failures: 0, Errors: 50, Skipped: 175, Time elapsed: 4.112 sec <<< FAILURE!
* def secretKey = config.apiKey(| XYZ | 2110974841 | 204 | Valid |) Time elapsed: 0.005 sec <<< ERROR!
java.lang.RuntimeException: no variable found with name: config
at com.intuit.karate.Script.getValuebyName(Script.java:323)
at com.intuit.karate.Script.evalJsonPathOnVarByName(Script.java:378)
at com.intuit.karate.Script.eval(Script.java:309)
at com.intuit.karate.Script.eval(Script.java:194)
at com.intuit.karate.Script.assign(Script.java:656)
at com.intuit.karate.Script.assign(Script.java:587)
at com.intuit.karate.StepDefs.def(StepDefs.java:265)
at ✽.* def secretKey = config.apiKey(features/checkdigitapi/XYZ.feature:6)
My .feature file and karate-config.js are below.
XYZ.feature
#regression
Feature: Checkdigit Algorithm API
Background:
* url baseUrl
* def secretKey = config.apiKey
* configure ssl = true
Scenario Outline: Testing XYZ algorithm
* configure headers = { KeyId: secretKey, Accept: 'application/json' }
Given path 'headers'
And param url = baseUrl
And params { customerId: '<custcode>', algoId: '<algo>' }
When method get
Then status <val>
Examples:
| algo | custcode | val | comment |
| XYZ | 2110974841 | 204 | Valid |
| XYZ | 7790011614 | 204 | Valid |
| XYZ | 5580015174 | 204 | Valid |
| XYZ | 2110974840 | 400 | expected check digit 1 |
| XYZ | 211097484 | 400 | not 10 digits |
| XYZ | 211097484x | 400 | not numeric |
karate-config.js
function() {
//set up runtime variables based on environment
//get system property 'karate.env'
var env = karate.env;
if (!env) { env = 'dev'; } // default when karate.env not set
// base config
var config = {
env: env,
baseUrl: 'https://localapi.abc123.example.com/api/v1/validate/customerid',
apiKey: ''
}
//switch environment
if (env == 'dev') {
config.baseUrl = 'https://devapi.abc123.example.com/api/v1/validate/customerid';
config.apiKey = 'fake-1ba403ca8938176f3a62de6d30cfb8e';
}
else if (env == 'qual') { //Pre-production environment settings
config.baseUrl = 'https://qualapi.abc123.example.com/api/v1/validate/customerid';
config.apiKey = 'fake-d5de2eb8c0920537f5488f6535c139f2';
}
karate.log('karate.env =', karate.env);
karate.log('config.baseUrl =', config.baseUrl);
karate.log('config.apiKey =', config.apiKey);
return config;
}
(similar issue here, using a separate headers.js: https://github.com/intuit/karate/issues/94)
Keep in mind that all the keys within the JSON object returned by karate-config.js will be injected as variables, and nothing else. So you will not be able to refer to config, but you will certainly be able to refer to apiKey.
I think if you make this simple change, things will start working:
* def secretKey = apiKey
Also, I think you have a problem in the first line of the scenario, it should be:
* configure headers = { KeyId: '#(secretKey)', Accept: 'application/json' }
FYI my final, correctly working XYZ.feature file looks like this now.
The line Given path 'headers' caused header info to creep into the url so it's removed.
XYZ.feature
#regression
Feature: Checkdigit Algorithm API
Background:
* url baseUrl
* def secretKey = apiKey
* configure ssl = true
Scenario Outline: Testing XYZ algorithm
* configure headers = { KeyId: '#(secretKey)', Accept: 'application/json' }
Given url baseUrl
And params { customerId: '<custcode>', algoId: '<algo>' }
When method get
Then status <val>
Examples:
[...]