Use variables in json path expressions [duplicate] - karate

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;

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

Can I run example in scenario outline for n times?

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

Passing a parameter to a sql query using pyodbc failing

I have read dozens of similar posts and tried everything but I still get an error message when trying to pass a parameter to a simple query using pyodbc. Apologies if there is an answer to this elsewhere but I cannot find it
I have a very simple table:
select * from Test
yields
a
b
c
This works fine:
import pyodbc
import pandas
connection = pyodbc.connect('DSN=HyperCube SYSTEST',autocommit=True)
result = pandas.read_sql("""select * from Test where value = 'a'""",connection,params=None)
print(result)
result:
value
0 a
However if I try to do the where clause with a parameter it fails
result = pandas.read_sql("""select * from Test where value = ?""",connection,params='a')
yields
Error: ('01S02', '[01S02] Unknown column/parameter value (9001) (SQLPrepare)')
I also tried this
cursor = connection.cursor()
cursor.execute("""select * from Test where value = ?""",['a'])
pyodbcResults = cursor.fetchall()
and still received the same error
Does anyone know what is going on? Could it be an issue with the database I am querying?
PS. I looked at the following post and the syntax there in the first part of answer 9 where dates are passed by strings looks identical to what I am doing
pyodbc the sql contains 0 parameter markers but 1 parameters were supplied' 'hy000'
Thanks
pandas.read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None)[https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_sql.html]ΒΆ
params : list, tuple or dict, optional, default: None
example:
cursor.execute("select * from Test where value = %s",['a'])
or Named arguments example:
result = pandas.read_sql(('select * from Test where value = %(par)s'),
db,params={"par":'p'})
in pyodbc write parms directly after sql parameter:
cursor.execute(sql, *parameters)
for example:
onepar = 'a'
cursor.execute("select * from Test where value = ?", onepar)
cursor.execute("select a from tbl where b=? and c=?", x, y)

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 !