Karate : Dynamic text value in xml file - karate

I want to provide dynamic values in the XML
test.xml:
<name>
<first>#(first)</first>
<last>#(last)</last>
<version>this is the #(version) in the file</version>
</name>
I have a .csv file:
first,last,version
abc,pqr,1
lma,qwe,2
Feature file:
call the csv and xml file
For first and last variable it works but for version it doesn't take version value

Yes, changing the tag name (or key name in JSON) is an advanced operation which "embedded expressions" cannot be used for. I think you should just use XPath. You should also take some time to read the examples linked from the documentation.
Here is just one way to do it, there are many more:
Scenario Outline:
* def payload =
"""
<name>
<first>#(_first)</first>
<last>#(_last)</last>
</name>
"""
* set payload /name/version = _version
* match payload == <name><first>foo</first><last>bar</last><version>1</version></name>
Examples:
| _first | _last | _version |
| foo | bar | 1 |

Related

How to pass response variable in path through examples table in karate

I am trying to pass a variable value in URL path which is further stored in examples table.
Unfortunately, it gives me error.
Can any one please help.
Background:
* def challengeID = res.challengeID
* def version = '2'
Given url dispatch And path '/api/fire/v' + version + '/sms/otp/' + <challengeID>
And param code = <code>
And header Content-Type = 'application/json'
When method GET Then status 400
Examples:
| challengeID | code |
| #(challengeID) | 2121211 |
| 3434343434343 | 111111 |
Sorry, the Examples: table cannot be dynamic. This is standard "Cucumber" behavior. Use table instead: https://github.com/intuit/karate#table
But I think you are over-complicating things. You should just do this:
And path 'api/fire/v' + version + '/sms/otp', res.challengeID

Karate API-building dynamic request XML from csv file and I don't want tag to be created in request if resp tag value is blank in csv

I am trying to build xml from csv file and wanted to remove the xml tags from request if the respective tag value is blank in the csv. I have 2 feature files, 1 xml and 1 csv file.
Below is my code.
'''
request.xml:
<ROUTE>
<Name>
<FirstName></FirstName>
<LastName></LastName>
</Name>
</ROUTE>
getQuoteTest.feature:
#tag
Feature: Get Quote Test
Scenario Outline:
* call read('classpath:getQuote.feature') {'FirstName':"<FirstName>",'LastName':"<LastName>"}
Examples:
| read('classpath:TestData.csv') |
CSV file:
FirstName LastName
Matt Chat
(blank) John
Shane Bond
Andrew (blank)
getQuote.feature
#ignore
Feature: Get Quote
Background:
Scenario:
* xml req = read('classpath:request.xml')
* set req/ROUTE/Name/FirstName = FirstName
* set req/ROUTE/Name/LastName = LastName
Given request req
When method POST
Then status 200
And print response
'''
When FirstName is blank, I don't want <FirstName></FirstName> tags to be present in my request xml. It would be great if I can get the exact code.
Thanks in advance !
A self contained code which you can run and then customize for your needs:
Feature: Conditional Example
Background:
Scenario Outline:
* def req =
"""
<ROUTE>
<Name>
<FirstName><FN></FirstName>
<LastName><LN></LastName>
</Name>
</ROUTE>
"""
* xml req2 = req
* if (req2.ROUTE.Name.LastName == null) karate.remove("req2","//LastName")
* if (req2.ROUTE.Name.FirstName == null) karate.remove("req2","//FirstName")
* print req2
Examples:
| FN | LN |
| Matt | Chat |
| | John |
| Shane | Bond |
| Andrew | |

Refer defined variable in Scenario outline example [duplicate]

This question already has answers here:
Can we parameterize the request file name to the Read method in Karate?
(2 answers)
Closed 1 year ago.
Feature: Test Type
Background:
* url host
* def name = 'test_name'
* def label = name
Scenario Outline: Test 2
Given url homeLinks.groupTypesUrl
And headers { tenant: #(tenantId), Authorization: #(authToken) }
* def name = <name>
* def description = <description>
* def label = <label>
* json data = read('path/to/file/create_group_type_request.json')
And request data
When method POST
Then status 400
Examples:
| name | label | description |
| '\u0000' | 'label' | 'description' |
| #(name) | '\u0000'| 'description' |
I need to refer global name defined inside examples map. How to get that reference?
Getting Javascript evalution error when I tried to like above piece of code.
Yes, Examples do not support JS eval and variables. Use the table form and loop over it with a call to a second feature: https://github.com/intuit/karate#calling-other-feature-files
Or you can try to use a dynamic Scenario Outline by initializing the table in the background: https://github.com/intuit/karate#dynamic-scenario-outline

How to deserialize json payload passed to other feature file which accept multiple arguments

I am sending multiple arguments to .feature file one of the argument is request json payload generated by using karate table. How to iterate through request payload so that post request will get one payload at a time.
Scenario: post booking
* table payload
| firstname | lastname | totalprice | depositpaid |
| 'foo' | 'IN' | 10 | true |
| 'bar' | 'out' | 20 | true |
#date will calculate using js function in background and baseURL is configured in karate.config.js file
* set payload[*].bookingdates = { checkin: '#(date())', checkout: '#(date())' }
* def result = call read('createrecord.feature') {PayLoad: #(payload) , URL: #(baseURL)}
######################################
createrecord.feature file will have
#ignore
Feature: To create data
Background:
* header Accept = 'application/json'
Scenario:
Given url __arg.URL
And path 'booking'
And request __arg.PayLoad
When method post
Then status 200
Here in createrecord.feature file how I can iterate through passed payload so that single payload will be passed to post request.
The simple rule you are missing is that if the argument to call is a JSON array (of JSON objects) it will iterate automatically.
Read the docs carefully please: https://github.com/intuit/karate#data-driven-features
So make this change:
* def result = call read('createrecord.feature') payload
And baseURL will be available in createrecord.feature so you don't need to worry about passing it.
Note that this may not work: * set payload[*].bookingdates refer this answer: https://stackoverflow.com/a/54928848/143475

Dynamically set a XML tag value while building payload

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.