karate doesn't match xml obtained from function - karate

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

Related

Karate - Matching 2 JSON objects for values but applying regex to one element of objects

I have 2 json as follows:
a: [{"code":"00","name":"A","iconUrl":"https:env1.test.png"}, {"code":"01","name":"B"}]
b: [{"iconUrl":"https:env2.test.png", "code":"00","name":"A"}, {"code":"01","name":"B"}]
I want to compare the 2 json objects. I tried match contains only.
My test is failing due to mismatch of env1 and env2 in iconUrl. By any chance is there a way out to resolve it by applying regex for iconUrl and not affecting the validation for code and number?
There are many possible ways, here is one:
* def first = [{"code":"00","name":"A","iconUrl":"https:env1.test.png"}, {"code":"01","name":"B"}]
* def second = [{"iconUrl":"https:env2.test.png", "code":"00","name":"A"}, {"code":"01","name":"B"}]
* second[0].iconUrl = '#string'
* match first == second

Removing quotes from param values in karate request

Scenario: I get response from a karate request which is in the form as below:
idValues = ["123:ABCD-F", "345:CFGB-F", "678:DERF-F"]
I then need to make a further request in a scenario where the values from array above is passed in karate's request * param as below:
Given path 'users','details'
* param = 123:ABCD-F, 345:CFGB-F, 678:DERF-F
When method get
Then status 200
Issue: I need to send this list of ids as comma separated values without the " quotes to the param keyword. If the values are passed to params with quotes, karate further encloses the ids within quotes (which is the correct behaviour i think) and because of this i do not get the expected response.
Wanted to know if there is a way to:
1. Take the values out of the array, remove the quotes from start and end.
2. Pass these as comma separated values to `param' keyword (as shown in the example above).
Thanks
2 suggestions.
karate.forEach() can do any kind of conversion you want. Here is an example. If you find this too ugly, use Java (search the docs for Java Interop):
* def idValues = ["123:ABCD-F", "345:CFGB-F", "678:DERF-F"]
* def fun = function(x, i){ var s = karate.get('temp'); if (i) x = ',' + x; karate.set('temp', s + x) }
* def temp = ''
* karate.forEach(idValues, fun)
* print temp
param will always encode, and as you said - it is the right behavior. So use url and manually concatenate the path you need. Refer this answer for more:
https://stackoverflow.com/a/55357704/143475

Karate expression to check if value exists in array

Here is my sample feature file:
Feature: Karate expression to check if status within array of status.
Scenario: Test
* def status = "ACTIVE"
* def possibleStatus = ["ACTIVE", "INACTIVE"]
* match status contains possibleStatus ?
Is there a way to check if status is either ACTIVE or INACTIVE using karate expression ?
NOTE: It can definitely be achieved by writing custome JS function.
This is an easy one.
* def status = "ACTIVE"
* def possibleStatus = ["ACTIVE", "INACTIVE"]
* match possibleStatus contains status
Any questions :)

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.

Certain expressions to validate json don't work

I am trying to print the following:
* print response.requests[?(#.friendlyId == '#(ORID)')]
where ORID is:
* def temp2 = response.teams[?(#.name == '<Name>')].requestedResources[0].resourceRequestFriendlyId
* def ORID = temp2[0]
The expression is giving value as null where as if i use JSON evaluator, I am getting the correct json.
Only JavaScript is supported on the right-hand-side of the print keyword. And JsonPath is not supported.
I will update the documentation to make this clear.