How can I set base API? I see double quotes getting added from the first API's response - karate

Given path '/api/metrics/product/ABC'
When method get
* def id = get response
* print id
* def basePathProducts = '/another/api/' + id + '/param'
Given path basePathProducts
When method GET
Then status 200
12:59:28.447 [main] INFO com.intuit.karate.StepDefs - [print] "5ca627bf3edd851238e59c9e" Apr 16, 2019 12:59:28 PM org.glassfish.jersey.logging.LoggingInterceptor log SEVERE: 2 * Sending client request on thread main 2 > GET
http://localhost:8080/API/ANOTHER/API/%225ca627bf3edd851238e59c9e%22/PARAM

I think you are overcomplicating things and you missed that the path syntax is designed for what you commonly need to do.
Don't def basePathProducts and do this, see how the id variable can be easily plugged into a path:
Given path 'another', 'api', id, 'param'

Your post is really hard to comprehend.
Try using
Given url yourURLVariable + 'another/api/'+ id + '/param'
Refer to this for more information : https://stackoverflow.com/a/54477346/10791639
Edit :
There is a problem with your parameter.
* def id = "5ca627bf3edd851238e59c9e"
* print id
Gives :
13:24:19.783 [print] 5ca627bf3edd851238e59c9e
So your variable id is "5ca627bf3edd851238e59c9e" instead of 5ca627bf3edd851238e59c9e

* def newresp = function(id){ return id.slice(1, -1); }
* def id = newresp(response)
I added these to remove the first and last characters from the response which is the double quotes in my case. Thanks for responding guys!

Related

Calling common scenario from another scenario in same feature file where request body is store in json file in karate [duplicate]

This question already has an answer here:
how to dynamically set an value in json read from file in Karate
(1 answer)
Closed 1 year ago.
I am a bit confused and need some clarify on this
Background:
* def successBody = 'util/successRequestBody.json'
#test1 #ignore
Scenario: Verify user
Given url
* def id = id
* def requestBody = read (successBody)
And request requestBody
When method post
Then status 201
#test2
Scenario: First create new user and then delete same user
* def id = '123'
# First call POST user to create a new user
* def postuser = call read('user.feature#test1') {id: id}
Given url
When method delete
Then status 204
I am providing value in request body for creating new user like this in successRequestBody.json
{
"id": "#(id)",
"name": "abc"
}
The above doesn't work. But when I provide like this it works. Please guide how the parameters should be passed in calling a feature from another. I am passing variable name id from test2 while calling test1 but in test1 it is reading id1 not id? Can someone please explain?
Background:
* def successBody = 'util/successRequestBody.json'
#test1 #ignore
Scenario: Verify user
Given url
# I am setting variable name id from test2 but here it is reading id1 not id?
* def id = id1
* def requestBody = read (successBody)
And request requestBody
When method post
Then status 201
#test2
Scenario: First create new user and then delete same user
* def id1 = '123'
# First call POST user to create a new user
* def postuser = call read('user.feature#test1') {id: id1}
Given url
When method delete
Then status 204
The call syntax is wrong, you have to use embedded expressions:
* def postuser = call read('user.feature#test1') { id: '#(id1)' }
Here's a tip. It is not mandatory to pass parameters. Variables in the "caller" will be visible to the "called" feature. This below has the same effect as above.
* def id = id1
* def postuser = call read('user.feature#test1')
Please read the documentation and examples carefully. If still stuck, follow this process: https://github.com/karatelabs/karate/wiki/How-to-Submit-an-Issue

Send a second request nb of times as nb of items returned for first request using Karate

I need to send 2 requests in a Scenario Outline. Ex:
Background:
* url 'someurl'
Scenario Outline:
* path <owner_id>, 'cats'
* method get
* status 200
here I need to get ids of cats from response as {"cats": [{"cat_id": "xx"}, {"cat_id": "yy"}...]}
* path <owner_id>, <cat_id>, 'kittens'
* method get
* status 200
Examples:
|owner_id|
|bill_id |
|kate_id | and so on
Is it possible to send the second request (kittens' retrieving) for each cat_id from the first request and this for each owner_id?
I tried another way:
Background:
* url 'someurl'
Scenario Outline:
* def cats = call read('GetCats.feature')
then store cat_ids as here:
* def catsIds = cats.c[*].id (I get an error "javascript evaluation failed: cats.c[*]id, <eval>:1:6 Expected an operand but found *")
OR
* def catsIds = karate.mapWithKey(cats.c[*].id, 'cat_id')
* path <owner_id>, <cat_id>, 'kittens'
* method get
* status 200
Examples:
|owner_id|
|bill_id |
|kate_id | ...
And here is GetCats.feature
Scenario:
* url 'someurl'
* path 'cats'
* method get
* status 200
* def c = response
I was thinking about karate.repeat but can we use it for this case?
Anything is possible, you can call other features, all data is in scope etc.
You made a mistake here, note the $:
* def catsIds = $cats.c[*].id
Refer: https://github.com/intuit/karate#get

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

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.

How to get id in responseHeaders location?

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 !