I am trying automate testing using Karate.
I have a XML payload.
I have a static XML payload which I am readying from a file and I want to call my service in loop.
For each call I would like to replace value for a tag name dynamically.
How would I achieve this?
e.g.
Below is my Main Feature which calls my common feature in loop
Feature: Loop Call
Background:
* def common = call read('classpath:CommonFeatures.feature')
Scenario:
* table table
| payload_file | field_tag | field_value |
| 'HappyPath.xml' | 'car_fuel' | 'Gas' |
| 'HappyPath.xml' | 'car_color'| 'Red' |
* def response = call read('classpath:Car.feature') table
Car.feature
Feature: Common
Scenario:
* print payload_file
* print field_tag
* print field_value
* xml payload = read('classpath:/payload/'+payload_file)
* print payload
* set payload/$field_tag = field_value
This is where I have issue setting the field_tag value.
I have other option to do this like writing a small java script method to replace the tag value or a small java class which use DOMParser or SAXParser to perform the same.
However I would like to know if there is any karate in build way to perform the same.
Also while using java script method to replace the tag value if I am using var parser = new DOMParser(); and it seems DOMParser is not available to use. Is there a way to make this available?
I think if you go through this sample, it will answer all your questions:
https://github.com/intuit/karate/blob/master/karate-junit4/src/test/java/com/intuit/karate/junit4/xml/xml.feature
For example this is how you can substitute values, as well replace a whole chunk of XML (which can include tags) using the set keyword:
Scenario: set xml chunks using xpath
* def req = read('envelope1.xml')
* def phone = '123456'
* def search =
"""
<acc:getAccountByPhoneNumber>
<acc:phoneNumber>#(phone)</acc:phoneNumber>
</acc:getAccountByPhoneNumber>
"""
* set req /Envelope/Body = search
* match req ==
"""
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:acc="http://foo/bar">
<soapenv:Header />
<soapenv:Body>
<acc:getAccountByPhoneNumber>
<acc:phoneNumber>123456</acc:phoneNumber>
</acc:getAccountByPhoneNumber>
</soapenv:Body>
</soapenv:Envelope>
"""
And please don't think of using DOMParser etc, you will be able to do anything you need via Karate syntax.
Thanks to Peter for all help and the examples.
I feel this is the best way to achieve this.
Wrote a small javascript function
"""
* def replaceTag =
"""
function(x){
karate.setXml('temp', x.payload);
karate.pretty(karate.get('temp'));
if (x.field_tag) karate.set('temp', x.field_tag, x.field_value);
return karate.get('temp');
}
"""
and calling the same from Car.feature like below and I get the dynamically replaced payload.
Feature: Common
Scenario:
* print payload_file
* print field_tag
* print field_value
* xml payload = read('classpath:/payload/'+payload_file)
* print payload
* def args = { payload: #(payload), field_tag: #(field_tag), field_value: #
(field_value)}
* print args
* xml payload = call common.replaceTag args
Note: I had to upgrade Karate 0.7.0 version in order to use karate.setXml method.
Related
Is it possible to use Scenario Outline as in this mode (which is really great!!):
Scenario Outline:
* print 'hello <name>'
Examples:
| (read('cats.json')) |
but with a json or a list in Background? Ex:
Background:
* json temp = cats_ids (ids that I get from an external job as here [111,222,333...])
or
* def temp = cats_ids
Scenario Outline:
* path id from temp
* method get
...
Examples:
| temp |
Yes, please look at karate.mapWithKey() explained here: https://github.com/intuit/karate#json-transforms
* def temp = karate.mapWithKey(cats_ids, 'id')
Scenario Outline:
* print id
This question already has an answer here:
How to use a variable in JsonPath filter
(1 answer)
Closed 2 years ago.
I have a feature file to retrieve the data from csv file for the given parameter. In order to do it, I need to use a variable in the JsonPath expression to retrieve data for given parameter. I tried may ways, but using variable in jsonPath is not working. I'm using 0.9.4 version
I tried the below ways:
* def userId = get[0] testData[?(#.UserType=='${userType}')].UserId
* def userId = get[0] testData[?(#.UserType==userType)].UserId
* def userId = get[0] testData[?(#.UserType=='#(userType)')].UserId(I suppose this can only be used in json/xml)
Below hard coded value works fine:
* def userId = get[0] testData[?(#.UserType=='SuperAdmin')].UserId
Called feature:
Feature: Utility to extract the various types of data from excel datasource
Background:
* def DataUtility = Java.type('com.org.utils.DataUtility')
* def dataUtils = new DataUtility()
* def testData = read('classpath:testdata/TestData.csv')
Scenario: Retrieve userId for a given user type
* def userId = get[0] testData[?(#.UserType=='${userType}')].UserId
Calling feature:
* table params
| userType |
| 'SuperAdmin' |
* def extractedData = call read('DataExtractor.feature') params
* def userID = extractedData[0].userId
I have tried using variables in Json Path.
Example:
String elementPath = "$.[" + i + "].item.value";
In this statement, i is a loop variable. After this pass it to the read api of DocumentContext.
It has worked perfectly fine for me.
I am using JsonPath & DocumentContext from jayway to achieve this.
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
I have to verify an XML fragment obtained from a function, but matches fails also when should.
To explain my needs, i have to test a web service that in response sends a soap message containing into the body an xml fragment encoded in base64. In my karate test i decode that fragment with a function and verify it with a fuzzy match, but every match fails also when good.
I made a test where the XML 'A' is explicity defined and the XML 'B' is obtained from a function where A == B. Then i define a XML 'C' that should match both, but instead matches only the one explicity defined.
Feature:
Background:
* def buildXml =
"""
function(param){
return '<root><hello>world</hello><foo>bar</foo></root>';
}
"""
Scenario:
* def a = <root><hello>world</hello><foo>bar</foo></root>
* def b = buildXml()
* def c =
"""
<root>
<hello>world</hello>
<foo>#ignore</foo>
</root>
"""
* match a == b
* match a == c
* match b == c
Last match fails, but should pass.
Just one small change, and you are good:
* xml b = buildXml()
Reason: https://github.com/intuit/karate#type-conversion
I want to run examples for n times , n is the length of data of getHotelid.
Feature: match rates from ds api to pricing api.
Background:
* url ''
Scenario Outline: Calling production assert feature file.
* def DbNew = Java.type('DbNew')
* def dq = new DbNew()
* def activeHotels = <ds_hotel_id>
* def hotel_id = call read('StringConverter.js') { activeHotels:'#(activeHotels)'}
* print hotel_id
Examples:
|dq.getHotelid()|
This is look a like Karate - Not able to run dynamic scenario outline in a loop
Your Examples should be as below,
Examples:
|dq.getHotelid()|
please read this documentation : Karate dynamic scenario
For my POST request, in responseHeaders I get 1 < location: /users/123
I would like to print only the id > 123.
When I do * print responseHeaders['location'][0] in my feature file, I get users/123. How I can get only the id?
This is not really a Karate question is it :P
Try this:
* def location = responseHeaders['location'][0]
* def userId = location.substring(location.lastIndexOf('/') + 1)
* print userId
That's right, all the power of JavaScript (or even Java via Java interop) is available to you in Karate !