Karate DSL - Converting a PNG response to Base64 [duplicate] - api

We're automating our test with karate framework. In one of our features we need to decode a token and get a scope in the response. Everything works well, except this code in js.
function(token) {
return JSON.parse(new Buffer(token.split('.')[1],'base64').toString('ascii')).scope;
}
Error:
Caused by: <eval>:2 ReferenceError: "Buffer" is not defined
Caused by: jdk.nashorn.internal.runtime.ECMAException
In official tutorials it is said that javascript is 'native' to karate, so we don't understand why Buffer is not recognized? What we should do? Thanks for any help

I was able to successfully base64Decode a JWT token payload to JSON using the following code without the need for a Java method:
Background:
* def parseJwt =
"""
function(token) {
var base64Url = token.split('.')[1];
var base64Str = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var Base64 = Java.type('java.util.Base64');
var decoded = Base64.getDecoder().decode(base64Str);
var String = Java.type('java.lang.String')
return new String(decoded)
};
"""
Scenario: JWT Token
Given path 'jwt/authenticate'
And header x-goog-authenticated-user-email = 'email'
And request {}
When method get
Then status 200
* json result = parseJwt(responseHeaders['Set-Cookie'][0])
* match result == {permissions: [1,2,3], iss: "us", exp: "#number", email: "email"}
Note: It does seem to be required to use json rather than def as Karate does better if it parses the string to json itself. Also, you may obtain the token from a header rather than a cookie as in this example if so, just change the responseHeader that you are looking for.

I'm pretty sure that Buffer is advanced / non-standard or NodeJS so it probably is not supported by the JVM JS engine (Nashorn).
Here's my recommendation. For this case, do the work using Java utilities.
For example, look at the Karate basic-auth example in the doc which uses Base64 encoding.
If it is really complex, simply create a Java static function, it will be much easier to test as a side-benefit. Hope this helps !

With respect to the post Karate: Problem with requests using bearer token | Karate is showing "org/apache/commons/codec/binary/Base64" in response instead of HTTP 401
My query was marked duplicate hence posting an answer/solution which we have found in our project.
We did some debugging in karate core about the error. It seemed a dependency was missing.
We added the dependency in the POM.xml
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
Afterwards the problem was resolved and we started getting HTTP 401.
I am not sure it can be added to the karate core.

Related

Karate: Problem with requests using bearer token | Karate is showing "org/apache/commons/codec/binary/Base64" in response instead of HTTP 401 [duplicate]

We're automating our test with karate framework. In one of our features we need to decode a token and get a scope in the response. Everything works well, except this code in js.
function(token) {
return JSON.parse(new Buffer(token.split('.')[1],'base64').toString('ascii')).scope;
}
Error:
Caused by: <eval>:2 ReferenceError: "Buffer" is not defined
Caused by: jdk.nashorn.internal.runtime.ECMAException
In official tutorials it is said that javascript is 'native' to karate, so we don't understand why Buffer is not recognized? What we should do? Thanks for any help
I was able to successfully base64Decode a JWT token payload to JSON using the following code without the need for a Java method:
Background:
* def parseJwt =
"""
function(token) {
var base64Url = token.split('.')[1];
var base64Str = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var Base64 = Java.type('java.util.Base64');
var decoded = Base64.getDecoder().decode(base64Str);
var String = Java.type('java.lang.String')
return new String(decoded)
};
"""
Scenario: JWT Token
Given path 'jwt/authenticate'
And header x-goog-authenticated-user-email = 'email'
And request {}
When method get
Then status 200
* json result = parseJwt(responseHeaders['Set-Cookie'][0])
* match result == {permissions: [1,2,3], iss: "us", exp: "#number", email: "email"}
Note: It does seem to be required to use json rather than def as Karate does better if it parses the string to json itself. Also, you may obtain the token from a header rather than a cookie as in this example if so, just change the responseHeader that you are looking for.
I'm pretty sure that Buffer is advanced / non-standard or NodeJS so it probably is not supported by the JVM JS engine (Nashorn).
Here's my recommendation. For this case, do the work using Java utilities.
For example, look at the Karate basic-auth example in the doc which uses Base64 encoding.
If it is really complex, simply create a Java static function, it will be much easier to test as a side-benefit. Hope this helps !
With respect to the post Karate: Problem with requests using bearer token | Karate is showing "org/apache/commons/codec/binary/Base64" in response instead of HTTP 401
My query was marked duplicate hence posting an answer/solution which we have found in our project.
We did some debugging in karate core about the error. It seemed a dependency was missing.
We added the dependency in the POM.xml
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
Afterwards the problem was resolved and we started getting HTTP 401.
I am not sure it can be added to the karate core.

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.

JWT Bearer token in ABCchrome header

I am using ABCPdf 11 to convert html to pdf, my html page which needs to be converted required JWT token so that needs to be passed to ABCChrome so it can use the JWT token.
I have tried the following but the auth still fails:
doc.HtmlOptions.HttpAdditionalHeaders = $"Authorization: Bearer {accessToken}";
I followed example from here: https://www.websupergoo.com/helppdfnet/default.htm?page=source%2F5-abcpdf%2Fxhtmloptions%2F2-properties%2Fhttpadditionalheaders.htm
From the description in the above URL, I have also tried the below options:
doc.HtmlOptions.NoCookie = true;
doc.HtmlOptions.Media = MediaType.Screen;
After adding HttpAdditionalHeaders and when I get the http status from the pdf library I do get 401 http status code which confirms the
var imageId = doc.AddImageUrl(model.Url);
var status = doc.HtmlOptions.ForChrome.GetHttpStatusCode(imageId);
The status here is 401 - unauthorized
The HttpAdditionalHeaders property is not currently supported by the ABCChrome Engine. The only HtmlOptions supported by ABCChrome are specified here.
There are a few things you could try:
Check whether the target server supports sending the web token via GET request parameters - I guess you've probably done this already :-)
Make the AddImageUrl request URL to an intermediary web server (even a local HttpServer) to a script which can fetch the page for you based on any GET parameters.
If the service you are attempting to access accepts ajax requests you could try using javascript to inject the response into a page using XMLHttpRequest.setRequestHeader(). NB if you use a local file (e.g. file://) for this you may come across some Chromium enforced JavaScript security issues.
I do know that WebSupergoo offer free support for all their licenses, including trial licenses.
Good luck.
Emailed ABCPdf support and unfortunately ABCChrome does not support HttpAdditionalHeaders property so the work around is to download the html ourselves and convert that to PDF, see example below:
var imageId = doc.AddImageHtml(html); // <- html downloaded from auth url
Also don't forget to add paging:
// add all pages to pdf
while (doc.Chainable(imageId))
{
doc.Page = doc.AddPage();
imageId = doc.AddImageToChain(imageId);
}
for (int i = 1; i <= doc.PageCount; i++)
{
doc.PageNumber = i;
doc.Flatten();
}

Cannot JSON.parse serverless event.body

I’ve been working on a simple function with the serverless framework that gets some data in a http POST, does some analysis and sends the results back. I got it working locally on my machine using serverless-offline but when it comes to deploying it I’m getting an error parsing the event.body.
Logging out the event.body it’s a string that looks like this:
----------------------------267253304929569989286258
Content-Disposition: form-data; name="text"
TEST
----------------------------267253304929569989286258--
so it makes sense that the parse is failing but I have no idea why this error it happening.
Any suggestions? I’ve tried a bunch of different things but am completely stumped.
Thanks in advance!
You can't JSON.parse that event.body cause it isn't JSON. It looks like whatever POSTed that data is using a multipart form POST style request rather than sending JSON. How are you invoking the HTTP POST?
I had the same issue and after a lot of debugging noticed 2 important things:
1.When the content type is application/x-www-form-urlencoded you might need to parse the data in a different way:
const qs = require('querystring');
module.exports.run = async event => {
try {
const data = qs.parse(event.body);
console.info('DATA:', data);
} catch(e) {
console.error(e.message);
}
}
2.When the Content-Type of the request is multipart/form-data the parsing will be even more complicated. I will suggest extra dependency to parse it like multiparty or any other of your choice
Thank you #Brian Winant! I am putting the answer here as a screenshot so it's clearer. In Postman, do the following:
AWS Lambda would return event.body as encoded query strings if the content-type is x-www-urlencoded. To have it return a JSON string you can then parse, send JSON data and set content-type as application/json.

how to see actual body sent from restassured

I have created a jax-rs rest api and tested it with rest-assured. All tests are green. Now I am trying to create an html/js front end for it.
My problem is I do not know how my json objects should look like to be accepted by my rest api. Thanks to restassured/jax-rs I never handled request strings. I fill in objects and I get objects, (un)marshaling (json) is invisible.
Is there any way I can see (debug) what strings are created by rest-assured/java and sent over the "wire"?
If you want to log the request body you can do:
given().log().body(). ..
Or if you want to log the response body you can do:
.. .then().log().body(). ..
See documentation on logging for more details.
I'm not a RestAssured used, so I can't answer your question directly, but here are some ideas that may help you out.
I don't know what serializer RestAssured uses under the hood, but Resteasy on Wildfly uses Jackson by default. I would get familiar with this library. For less trivial application, you may need to dig into its APIs directly to get your desired results. Here is it's documentation. For your particular case you can do something as simple as
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(yourObject);
System.out.println(jsonString);
This will print out the POJO in JSON format, based on your getters in the class. This is at the most basic level. If you don't already have Jackson as a dependency, you can add
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.0</version>
</dependency>
A really good friend (tool) to have is cURL. It's a command line tool that allows you to make REST/HTTP (other protocols also) requests. Though for this particular case it wouldn't help, you could send a GET request to one your resources that serves up the same type that you accepted in your POST. That way, you can see the resulting JSON. This may be a little much at this point, but I would definitely look into this tool if you're going to be doing a lot of REST development.
You might also want to check out a Browser tool like [Postman for Chrome]
You should really get familiar with JSON format. Once you get familiar with it, and you start working with JSON framework, you'll notice that at a basic level, they all work similarly.
Java Object == JSON Object ( {} )
Java Collection/Array == JSON Array ( [] )
Java fields/properties == JSON keys
Getters are used for they keys and their values (for serialization)
Setters are used for deserialization
So for example you have this class
public class Person {
String name;
List<Person> friends;
public String getName() { return name; }
public void setName(String name) { return name; }
// Getter and Setter for friends
}
An instance of Person would produce the following JSON
{
"name" : "Peeskillet",
"friends": [
{
"name": "Lebron James"
},
{
"name": "Steph Curry"
}
]
}
It's actually pretty simple once you get the hang of it.
Oh and another thing you can do is add a logging filter on the server side as mentioned here.
As far as working with Javascript, there is a JSON.stringify(javascriptObject) that will serialize your Javacript objects to JSON strings. So generally, you can model your Javascript object like your Java objects.
Hope this helped.
In RestAssured just use this:
String body = resp.asString();
System.out.println(body);
Try this for Request Body
RequestSpecification httpRequest = RestAssured.given().urlEncodingEnabled(true);
..
..
..
System.out.println(" Body ==> "+ httpRequest.log().body());
And for response body:
System.out.println("Res Body ===>"+ response.getBody().prettyPrint());