How to export response into a file or validate the tag value with the help of Karate Framework - selenium

I'm using the following feature file and it generates the response. How can we store the response into an XML file instead of showing the console?
Feature File:
Feature: Test soap end point
Background:
* url 'sample url'
Scenario: SmokeTest
Given request read('getMbrWksMembershipDetails.xml')
When soap action 'test url'
Then status 200
And print response
EDITED: The response I'm getting like this.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getMbrWksMembershipDetailsResponse xmlns:ns1="xxxxxxxxxx">
<ns4:WksMembershipSummaryResponse xmlns:ns2="xxxxxxxx" xmlns:ns3="xxxxxxxxxx" xmlns:ns4="xxxxxxxxxx">
<ns2:customerSummary>
<ns2:address>
<ns2:city>SOUTH CHESTERFIELD</ns2:city>
<ns2:country>USA</ns2:country>
<ns2:isoCountryCode>US</ns2:isoCountryCode>
<ns2:line1>9998, N. MICHIGAN ROAD.</ns2:line1>
<ns2:postalCode>23834</ns2:postalCode>
<ns2:state>VA</ns2:state>
</ns2:address>
<ns2:allowPasswordChange>true</ns2:allowPasswordChange>
<ns2:arpMember>false</ns2:arpMember>
<ns2:brandCode>ABC</ns2:brandCode>
<ns2:brandId>1</ns2:brandId>
<ns2:companyCode>ABC</ns2:companyCode>
<ns2:eliteMemberRewardStatus>false</ns2:eliteMemberRewardStatus>.....
Question:
How can I validate the tag values from this response?
Thanks,

First a question - why do you want to do this ? Karate is a testing framework, and besides being able to run assertions on responses, you can easily re-use responses (or some data from a response) in the next request. There is no need to ever save anything to a file.
And if you follow the instructions in the Karate documentation on logging you will also see responses logged to the file target/karate.log.
When you use the JUnit runner, you will see all responses in an HTML report.
Same case with the parallel runner.
Anyway, even after all this if you really really want to save responses to a file, use Java interop and write your own utility to save to a file, it will be a just a few lines of code. It is not built-in to Karate because of the above reasons.
EDIT: well, after all the typing above, turns out you just want to know how to validate (assert / match) the response ? Great, that is the whole selling point of Karate.
I assume you have read the Karate documentation. Also refer this example: soap.xml and this one for more ideas: xml.feature
Anyway here are some hints based on your XML sample to get you started. You can paste the below into a Scenario: and run this without needing to make HTTP requests and that way test and get comfortable with match:
* def response =
"""
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getMbrWksMembershipDetailsResponse xmlns:ns1="xxxxxxxxxx">
<ns4:WksMembershipSummaryResponse xmlns:ns2="xxxxxxxx" xmlns:ns3="xxxxxxxxxx" xmlns:ns4="xxxxxxxxxx">
<ns2:customerSummary>
<ns2:address>
<ns2:city>SOUTH CHESTERFIELD</ns2:city>
<ns2:country>USA</ns2:country>
<ns2:isoCountryCode>US</ns2:isoCountryCode>
<ns2:line1>9998, N. MICHIGAN ROAD.</ns2:line1>
<ns2:postalCode>23834</ns2:postalCode>
<ns2:state>VA</ns2:state>
</ns2:address>
</ns2:customerSummary>
</ns4:WksMembershipSummaryResponse>
</ns1:getMbrWksMembershipDetailsResponse>
</soap:Body>
</soap:Envelope>
"""
* match //address/city == 'SOUTH CHESTERFIELD'
* match //customerSummary/address ==
"""
<ns2:address>
<ns2:city>SOUTH CHESTERFIELD</ns2:city>
<ns2:country>USA</ns2:country>
<ns2:isoCountryCode>US</ns2:isoCountryCode>
<ns2:line1>9998, N. MICHIGAN ROAD.</ns2:line1>
<ns2:postalCode>23834</ns2:postalCode>
<ns2:state>VA</ns2:state>
</ns2:address>
"""

Related

Is anyone using Karate for Salesforce API testing? [duplicate]

Karate has been super helpful to validate our rest apis which gives json response. Now we have apis which gives us response in avro format. May also need to send the payload in avro format. How can i test the rest endpoints which gives response in AVRO format using karate? Is there any easy way I can tweak and get it done. Thanks!
Here's my suggestion, and in my opinion this will work very well.
Write a simple Java utility, maybe a static method that can take JSON and convert it to AVRO and vice versa.
Now you can define all your request data as JSON - but just before you make the request to the server, convert it to AVRO. I am not sure if the server call is HTTP or not. If it is HTTP - then you know what to do in Karate, just send binary as the request body etc.
Else you may not even use the Karate HTTP DSL like method, request etc. You have to write one more Java helper that will take your JSON (or AVRO) and make the call to the server (specific for your project) and return the response, converted back to JSON. For example:
* def Utils = Java.type('com.myco.avro.Utils')
* def json = { hello: 'world' }
* def req = Utils.toAvro(json)
* def res = Utils.send(req)
# you can combine this with the above
* def response = Utils.fromAvro(res)
* match response == { success: true }
Yes, you might be using Karate mostly for matching, reporting, environments etc. Which is still valuable ! Many people don't realize that HTTP is just 10% of what Karate can do for you.

How to pass multiple json records using data driven approach in Karate DSL?

We have gone through the Karate documentation where we can compare the exact JSON object as a response (which contains multiple data records) but how can we pass and read the JSON in a single scenario?
Below is my sample.JSON and I want to read this in the request payload.
[{"name":"John","salary":"10000","age":"25"},
{"name":"Maria","salary":"20000","age":"27"}]
I have tried the JSON structure in the above format, however, I am getting below exception. Kindly help me in this.
status code was: 400, expected: 200, response time: 4315
Kindly suggest how to read and pass it in request payload of single scenario.
Thank you.
Status code 400 means you have made some other mistake with the request. Karate is working fine, it is just an HTTP client, maybe the request was not in the "shape" the server was expecting. Talk to the server-side team if you can or check the documentation of the API.
Here is a simple example that works, paste it and try:
* def body = [{"name":"John","salary":"10000","age":"25"}, {"name":"Maria","salary":"20000","age":"27"}]
* url 'https://httpbin.org/post'
* request body
* method post
* status 200
EDIT: for looping, please read the documentation.
The below example is just one way of doing it - please identify what best you are comfortable with: https://github.com/intuit/karate#data-driven-tests
Feature:
Background:
* def data = [{"name":"John","salary":"10000","age":"25"}, {"name":"Maria","salary":"20000","age":"27"}]
Scenario Outline:
* url 'https://httpbin.org/post'
* request __row
* method post
* status 200
Examples:
| data |

Declare Global variables in background of feature-karate Soap API

I am using karate for SOAP API services. How can I declare a global variable ?? as you can see in below feature file? after print response I have variable name def ourSession = /Envelope/Body/LoginReturn I am using this variable (ourSession) in next scenario but it's failing ? but it's not global.
So how can I declare "ourSession" as a global variable ?? so I can use into other scenarios?
Any help will be highly appreciated. Please have a look of my feature file below;
#
Feature:
SOAP calls to the following service:
Background:
* url baseUrl
* def configSS = Java.type('practice.utilities.Shellscripts')
##################################### LOG IN #########################################################
#DataAcquisition
Scenario: login
Given request
"""
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsh="http://www.informatica.com/wsh">
<soapenv:Header/>
<soapenv:Body>
<wsh:Login>
<RepositoryDomainName>Domain_Aqr_Dev_Powercenter</RepositoryDomainName>
<RepositoryName>Powercenter_Repository_Service</RepositoryName>
<UserName>#(AM_USERNAME)</UserName>
<Password>#(AM_PASSWORD)</Password>
<UserNameSpace/>
</wsh:Login>
</soapenv:Body>
</soapenv:Envelope>
"""
When soap action '/login'
Then assert responseStatus == 200
And print 'response: ', response
* def ourSession = /Envelope/Body/LoginReturn
* print ourSession
Do not create a new scenario for the subsequent call. A single scenario can have multiple requests.
i am using this variable (ourSession) in next scenario
You can't. There are many answers in Stack Overflow addressing this question, please find them and read them.
And please read the docs: https://github.com/intuit/karate#script-structure
To quote:
if you are expecting a variable in the Background to be modified by one Scenario so that later ones can see the updated value - that is not how you should think of them, and you should combine your 'flow' into one scenario.
There are many ways to "re-use" in Karate such as call. So you should be able to figure out how to do what you want.
Now if you really want a "global" variable, please use callonce that is most likely what you are looking for:

How can I get WebMock to match a body containing specific XML data using hash_including?

I have a Ruby (2.6.5) on Rails (5.2.3) application which is already successfully using Savon (2.12) to interact with FlightAware's FlightXML 2 API via SOAP/WSDL. However, I'm running into an issue while attempting to write Minitest tests for this functionality, using WebMock (3.7.6) to stub out the API requests.
My application (via Savon) makes a request including an XML body like the following example:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:FlightXML2="http://flightxml.flightaware.com/soap/FlightXML2" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<FlightXML2:AirportInfoRequest>
<FlightXML2:airportCode>KDFW</FlightXML2:airportCode>
</FlightXML2:AirportInfoRequest>
</env:Body>
</env:Envelope>
I would like to use a with statement so that the stub only responds to a request having a specific airport code in the element. For example, if I'm looking for "KDFW", then a request containing <FlightXML2:airportCode>KDFW</FlightXML2:airportCode> should match, but a request containing <FlightXML2:airportCode>CYYZ</FlightXML2:airportCode> should not.
Right now, I have it working by including the XML tag in a regular expression:
icao_code = "KDFW"
response_body = "[the response I want]"
WebMock.stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op").
with(body: /<FlightXML2:airportCode>#{icao_code}<\/FlightXML2:airportCode>/).
to_return(status: 200, body: response_body)
This feels like a kludge, especially when the documentation for WebMock mentions that I can use hash_including to match XML tags. No matter what I try, though, I get the typical WebMock unregistered request error, indicating that I don't match the request. Here are the with statements that I've tried so far:
with(body: hash_including({airport_code: icao_code})
with(body: hash_including({"airportCode": icao_code})
with(body: hash_including({"FlightXML2:airportCode": icao_code})
How can I match a specific XML element without having to resort to putting the XML tag in a regular expression?
Match the request against a block:
stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op")
.with do |request|
# do something
end.to_return(status: 200, body: response_body)
The block code could look something like:
request_xml = Nokogiri::XML(request.body)
request_xml.xpath("//FlightXML2:airportCode").any? do |node|
node.content == icao_code
end
This approach has an additional advantage in that you can insert a debugger into the above code block and figure out why your test case isn't working. You can see Webmock docs here.

how to send payload and header parameters in a gherkin step

new to cucumber.
I want to test rest api using cucumber jvm.
suppose , I have the following scenario
scenario:
* POST at "http://localhost:8080/x" with payload:
"""
<user>
<name>abc</name>
</user>
"""
with header:
|param1|value|
|param2|value|
But it is not working.
if I break the step into 2, one that gives payload and other that gives header,
I have to hold the first step (because it would be missing header) and do the actual post operation with the second step.
what are my options ?
thanks
There was a feature request for supporting both tables and docstrings, but it was closed because of the amount of work to support it in all cucumber implementations, not just the one for the jvm.
So the workaround would be to split this into multiple steps, collecting all data, and sending it at the end:
Scenario: Create a user
Given the following payload:
"""
<user><name>abc</name></user>
"""
And the following headers:
| param | value |
When the request is sent as "POST" to "http://example.com/users"
Then the user is created
I think this also helps with readability of the scenario, and both payload and headers would be optional, which might be useful for other (simpler) requests.