Karate: Multipart file : read works but passing content in value fails - karate

I have a endpoint with a multipart request which takes two files as part of the request parameter.
I tried with the below snippet with read and it worked, but my use case is to take content from a file and pass it to the value parameter.
Can I pass the content as a file?
The working code if my I try to read the file from directory is
Working feature::
Scenario:
* configure headers = {'Content-Type' : 'multipart/form-data', 'Authorization': 'Bearer sgahshshshs'}
Given url "http://filecompare.com/compare"
And multipart file oldfile = { read: './oldfile.json', filename: 'oldfile.json'}
And multipart file newfile = { read: './newfile.json', filename: newfile.json'}
When method post
Then status 200
Not working feature::
Scenario:
Given url "http://download-oldfile/oldfile"
When method get
* def oldfile = response
Given url "http://download-newfile/newfile"
When method get
* def newfile = response
* configure headers = {'Content-Type' : 'multipart/form-data', 'Authorization': 'Bearer sgahshshshs'}
Given url "http://filecompare.com/compare"
And multipart file oldfile = { value: '#(oldfile)', filename: 'oldfile.json'}
And multipart file newfile = { value: '#(newfile)', filename: newfile.json'}
When method post
Then status 200
The contents are printed correctly but api returns error when I use value
Please let me know if I am missing something as part of running with the value keyword in multipart file.
Thank you

Can't think of anything other than try to convert the value to a string:
* string oldfile = response
If still stuck, follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue

Had the same issue, resolved without needing to save to file by defining a variable holding the JSON object and using set to manipulate its value.
In your case this would look like:
* def temp = {value: '', filename: 'oldfile.json'}
* set temp.value = oldFile
#[...]
And multipart file oldFile = temp

Related

Karate - Trouble passing correct headers for authorization

I am have some problems passing in the correct headers for my graphql endpoints
The use case in Postman:
call requestToken endpoint to obtain sessionToken value
requestToken response contains Key Value " and Token Value.
For subsequent calls, I set postman headers as:
Key = X_SESSION_TOKEN Value = Token Value
The user case in Karate
1st feature 'requestToken.feature' successfully calls and stores key + tokenValue
2nd feature successfully defines and prints the token value
here is my 2nd request:
Feature: version
Background:
* url 'http://api-dev.markq.com:5000/'
* def myFeature = call read('requestToken.feature')
* def authToken = myFeature.sessionToken
* configure headers = { 'X_SESSION_TOKEN': authToken , 'Content-Type': 'application/json' }
Scenario: get version
Given path 'query'
Given text query =
"""
query {
version
}
"""
And request { query: '#(query)' }
When method POST
Then status 200
And print authToken
And print response
I am not sure I send the headers right. Its coming back 200, but I keep getting a error 'token malformed' in the response message
Any suggestions? New at this, thanks!
Honestly this is hard to answer, a LOT depends on the specific server.
EDIT: most likely it is this change needed, explained here: https://github.com/intuit/karate#embedded-expressions
* configure headers = { 'X_SESSION_TOKEN': '#(authToken)' , 'Content-Type': 'application/json' }
2 things from experience:
should it be X-SESSION-TOKEN
add an Accept: 'application/json' header
And try to hardcode the headers before attempting call etc.
Here is an example that works for me:
* url 'https://graphqlzero.almansi.me/api'
* text query =
"""
{
user(id: 1) {
posts {
data {
id
title
}
}
}
}
"""
* request { query: '#(query)' }
* method post
* status 200

Multipart file does not take the variable for the file name

I am trying to use the multipart file with the file as a variable, my feature looks like below
Feature: Test feature
Background:
* def JavaUtil = Java.type('com.intuit.karate.demo.util.JavaUtil')
* def file = JavaUtil.createBatchFile("1003");
# Scenario: test one
# * print " this is the first test: "
* url appUrl + '/api/partner/v1/bulk/'
* print 'file :', file
Given path 'jobs', jobId, 'batches'
And multipart file newBatchInfo = { read: file}
When method post
Then status 200
When the code executes the file has the right value but the multipart file does not accept the file variable which has the absolute path.
Is this the right usage? If there are some docs around this, can someone point me. Thanks.
This is my output
There is a file: prefix, which you can use in cases like this, where you generate a file. I recommend you generate files into target when using Maven for e.g.
Refer docs: https://github.com/intuit/karate#reading-files
Also note that you should use embedded expressions:
* def file = 'file:' + JavaUtil.createBatchFile("1003")
# ...
* And multipart file newBatchInfo = { read: '#(file)' }

Sending a SOAP request with a file attachment [duplicate]

I have an endpoint who consumes Json with 2 attributes, like
{id='12344', data=byte_array}
so I've wrote a test
Feature: submitted request
Scenario: submitted request
* def convertToBytes =
"""
function(arg) {
var StreamUtils = Java.type('my.utils.StreamUtils');
// it reads stream and convert it to a byte array
return StreamUtils.getBytes(arg);
}
"""
Given url 'http://my-server/post'
And def image = convertToBytes(read('classpath:images/image_1.jpg'));
And request {id:1, data: "#(image)"}
When method POST
Then status 200
However is got an exception form karate without much details
ERROR com.intuit.karate - http request failed: [B cannot be cast to [Ljava.lang.Object;
Any hits how to submit byte arrays as a part of Json with karate?
I don't think you can do that. Either the whole request should be binary (byte-array) or you do a multi-part request, where binary is Base64 encoded. As far as I know you can't put binary inside JSON. There is something called Binary JSON though.
EDIT: after assuming that the byte[] has to be Base64 encoded:
Background:
* url demoBaseUrl
* def Base64 = Java.type('java.util.Base64')
Scenario: json with byte-array
Given path 'echo', 'binary'
And def encoded = Base64.encoder.encodeToString('hello'.bytes);
And request { message: 'hello', data: '#(encoded)' }
When method post
Then status 200
And def expected = Base64.encoder.encodeToString('world'.bytes);
And match response == { message: 'world', data: '#(expected)' }
I just added this test to the Karate demos, and it is working fine. Here is the commit.

as for 'replace' usage, does it support to replace the placeholder with value in place (I mean "over-write"))?

I need to upload a file to the server side, however, before doing that I need to replace a placeholder in the file with a dynamic value. does it support to get the placeholder replaced in place dynamically?
I noticed that I can replace the placeholder with ease using the 'replace' keyword. The following is my script:
Given path 'common/upload'
And multipart fields read('classpath:mainFlow/labresultUpload.json')
* def filename = 'PKU.A22backup'
* def someString = read('PKU.A22backup')
* print someString
* replace someString
|token|value|
|labsampleid|'123456'|
* print someString
* multipart file file = { read: "#(filename)", filename: "#(filename)"}
When method post
Then status 200
* def result = response[0].result
However, I need to replace the placeholder in place (here, I mean over-write) dynamically and then upload the file to the server side.
You have the option to supply a value instead of the file-name: https://github.com/intuit/karate#multipart-file
* multipart file file = { value: "#(someString)", filename: "#(filename)" }

How to send a byte array as a part of Json with karate framework

I have an endpoint who consumes Json with 2 attributes, like
{id='12344', data=byte_array}
so I've wrote a test
Feature: submitted request
Scenario: submitted request
* def convertToBytes =
"""
function(arg) {
var StreamUtils = Java.type('my.utils.StreamUtils');
// it reads stream and convert it to a byte array
return StreamUtils.getBytes(arg);
}
"""
Given url 'http://my-server/post'
And def image = convertToBytes(read('classpath:images/image_1.jpg'));
And request {id:1, data: "#(image)"}
When method POST
Then status 200
However is got an exception form karate without much details
ERROR com.intuit.karate - http request failed: [B cannot be cast to [Ljava.lang.Object;
Any hits how to submit byte arrays as a part of Json with karate?
I don't think you can do that. Either the whole request should be binary (byte-array) or you do a multi-part request, where binary is Base64 encoded. As far as I know you can't put binary inside JSON. There is something called Binary JSON though.
EDIT: after assuming that the byte[] has to be Base64 encoded:
Background:
* url demoBaseUrl
* def Base64 = Java.type('java.util.Base64')
Scenario: json with byte-array
Given path 'echo', 'binary'
And def encoded = Base64.encoder.encodeToString('hello'.bytes);
And request { message: 'hello', data: '#(encoded)' }
When method post
Then status 200
And def expected = Base64.encoder.encodeToString('world'.bytes);
And match response == { message: 'world', data: '#(expected)' }
I just added this test to the Karate demos, and it is working fine. Here is the commit.