Setting HTTP Body during runtime

Hi

Can anyone please provide a solution as to how to set HTTP Body on the fly, i.e during the test case execution.
I am getting the response text as below.

{“jsonrpc”:“2.0”,“id”:0,“error”:{“code”:400,“message”:“required Field: jsonrpc”,“data”:{}},“fcFlingVersion”:“0.8.5”}

Which is because it is not taking the HTTP body which I provided externally.
Thanks.

Screenshot (35).png

Vidyasagar Sakaray

There is a known issue, see:

so you may have to manually edit the .rs files and add the ‘text’ tag.

This should be fixed in 5.8.3 (I haven’t checked yet) so try first to upgrade katalon to the latest version

Hi Ibus

I looked into the .rs file in the object repo, and it has the text text already present in it, but still it is showing the same message when I try to print the response.

I am passing http header for Authorization from the code.
Here is my code.

‘Get token’

token = ‘some token …’

‘Scope to a project’

RequestObject ScopeToProject = findTestObject(‘Request2’)

‘Create new ArrayList’

ArrayList HTTPHeader = new ArrayList()

‘Send token in HTTP header’

HTTPHeader.add(new TestObjectProperty(‘X-Auth-Token’, ConditionType.EQUALS, token))

//HTTPHeader.add(new TestObjectProperty(‘Authorization’, ConditionType.EQUALS, "Bearer " + token))

‘Set that token’

ScopeToProject.setHttpHeaderProperties(HTTPHeader)

‘Get response text’

response = WS.sendRequest(ScopeToProject)

responseText = response.getResponseText()

println(’\nResponse text : ’ + responseText)

Could anyone suggest where is the mistake and come up with a solution?

Thanks.

Just a guess, but I think the way you do it, it will create a new instance of the Request2 … which may not have the body properties set.

Try to set it also programmatically …

or set the Header too into the Object and just use it into the test case.

You can use also object variables to pass values from the test case to the test object (token etc)

This method usually works for me.

Ibus said:

Just a guess, but I think the way you do it, it will create a new instance of the Request2 … which may not have the body properties set.

Try to set it also programmatically …

or set the Header too into the Object and just use it into the test case.

You can use also object variables to pass values from the test case to the test object (token etc)

This method usually works for me.

You may be right. It might be because i am creating a new instance of the Request2.
And so, I have to set the http body also programatically. But that’s what was my question, to which I didn’t get any solution.
If you have an idea, could you explain how can I set the http body programatically?

Thanks.

 setHttpBody(String httpBody)

This should do the job, see the API doc:

https://api-docs.katalon.com/studio/v4.6.0.2/api/com/kms/katalon/core/testobject/RequestObject.html#setHttpBody(java.lang.String)

You have to pass the Json as a string.

Option two:

Use the RestRequestObjectBuilder:

so you no longer need to define the object into the repository

just use

withTextBodyContent(String text, String charset)

instead of

withUrlEncodedBodyContent(List<UrlEncodedBodyParameter> parameters, String charset)

Option 3 (the way i use more often) - using a generic test object, parametrized:

and into the test-case I have something like this (I am passing the json body from an external file to keep the script cleaner)

'Given'
WS.comment("Setup")
reqUrl = "http://your/url/here"
reqBody = new File('./path/to/json/file').text
myToken = 'Bearer blah Blah'
request = findTestObject('POSTRequest.ContentJSON(url,body,token)', [ ('url') : reqUrl, ('body') : reqBody, ('token') : myToken ])

'When'
WS.comment("Sending POST request: ${request.getRestUrl()}")
WS.comment("With body: ${request.getHttpBody()}")
response = WS.sendRequest(request)

'Then'
WS.comment("Check response status")
WS.verifyResponseStatusCode(response, 201)

req_body.png

req_header.png

3 Likes

Ibus said:

Option 3 (the way i use more often) - using a generic test object, parametrized:

and into the test-case I have something like this (I am passing the json body from an external file to keep the script cleaner)

'Given'
WS.comment("Setup")
reqUrl = "http://your/url/here"
reqBody = new File('./path/to/json/file').text
myToken = 'Bearer blah Blah'
request = findTestObject('POSTRequest.ContentJSON(url,body,token)', [ ('url') : reqUrl, ('body') : reqBody, ('token') : myToken ])

‘When’


WS.comment(“Sending POST request: ${request.getRestUrl()}”)


WS.comment(“With body: ${request.getHttpBody()}”)


response = WS.sendRequest(request)


‘Then’


WS.comment(“Check response status”)


WS.verifyResponseStatusCode(response, 201)


  
  

  

Tried this one, and its working fine.
Credits to you Ibus, You are awesome!!

Thanks and regards,
Vidyasagar

@Ibus
I am having issues with the following code lines. Any thoughts, please ?
Appreciate your help.

‘When’
WS.comment(“Sending POST request: ${request.getRestUrl()}”)
WS.comment(“With body: ${request.getHttpBody()}”)
response = WS.sendRequest(request)

2019-02-06 18:20:46.240 ERRORe[0;39m e[36mc.k.katalon.core.main.TestCaseExecutor
comment(Sending POST request: $request.getRestUrl()) FAILED.
Reason:
java.lang.NullPointerException: Cannot invoke method getRestUrl() on null object
at Launch Campaign.run(Launch Campaign:25)
at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:328)
at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:319)
at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:298)
at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:290)
at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:224)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:106)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:97)
at com.kms.katalon.core.main.TestCaseMain$runTestCase$0.call(Unknown Source)
at TempTestCase1549506040032.run(TempTestCase1549506040032.groovy:22)

@spullabhotla - if you are using my sample code, make sure the above line is right. looks like the findTestObject method did not found the request object so the variable is null

in my example, POSTRequest.ContentJSON(url,body,token) is the exact name of the object i made in object repository

@Ibus
Here is my code (fully followed your way of approach because it is way easier than the confused TestObjectProperty approach). what could be the wrong with my code, I am new - please help.

‘Given’
WS.comment(“Setup”)
requestUrl = myUrl
requestBody = new File(‘C:\Users\external\some.json’).text
adminToken = token

request = findTestObject(‘LaunchCampaign.ContentJSON(url,body,token)’, [ (‘url’) : requestUrl, (‘body’) : requestBody, (‘token’) : adminToken ])

‘When’
WS.comment(“Sending POST request: ${request.getRestUrl()}”)
WS.comment(“With body: ${request.getHttpBody()}”)
response = WS.sendRequest(request)

‘Then’
WS.comment(“Check response status”)
WS.verifyResponseStatusCode(response, 200)

My object report is as below -

image

looks like your object is in a sub-folder named ‘external (SendGrid)’.
therefore, provide the full path to the object in the findTestObject method, relative to the repository, e.g:

'external (SendGrid)/LaunchCampaign.ContentJSON(url,body,token)'

Thank you very much - It worked very well.
I got to know now the subfolders matter the most.
We certainly need your help and expertise for newbies.

@Ibus
How can we parameterize the field of JSON from the file for data driven testing ?
I have tried creating variables in the test case and reference of the variable in the JSON file.
It did not work because the request is not correct.
Any thoughts and ideas, please ?

for code line -
comment(With body: $request.getHttpBody())

Sent as -
With body: {"_id": ["${id}"], “to”: ["${email}"], “launch”: true}

So, I did not built it correctly.

to parametreize certain keys / values in the JSON body I am using Groovy Template engine, see:
http://docs.groovy-lang.org/docs/next/html/documentation/template-engines.html

aka I have a template with the parametrized JSON, and I am building a string from it and pass to the request object as a single variable

Other approach is to build a map with the needed structure and produce the JSON using JsonOutput, see:

http://groovy-lang.org/json.html

@Ibus
Your suggestion is great and I have tried it the following way as you have suggested.

We have an array (thousands) of values for “to” field in the json given below. I tried it but couldn’t achieve the results. When I execute the test, the n’th string of the “to” field is executed. Also, the response is throwing the errors though I get the 200K success status code.

Any thoughts, please ?

‘Given’
WS.comment(“Setup”)
requestUrl = url
adminToken = token

def text = ‘’’{"_id": “someString1”, “to”: “${to}”, “launch”: true}’’’
def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)

def binding = [
to : “someSting2”
to : “someSting3”,
-------
-------
to : “someStingn”]

String response = template.make(binding)

request = findTestObject(‘Object Repository/external (SendGrid)/LaunchCampaign.ContentJSON(url,body,token)’, [ (‘url’) : requestUrl, (‘body’) : template, (‘token’) : adminToken ])

‘When’
WS.comment(“Sending POST request: ${request.getRestUrl()}”)
WS.comment(“With body: ${request.getHttpBody()}”)
response = WS.sendRequest(request)
println (response)

‘Then’
WS.comment(“Check response status”)
WS.verifyResponseStatusCode(response, 200)

Response Error :-
groovy.lang.MissingMethodException: No signature of method: static com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords.verifyResponseStatusCode() is applicable for argument types: (java.lang.String, java.lang.Integer) values: [200 101 bytes, 200]
Possible solutions: verifyResponseStatusCode(com.kms.katalon.core.testobject.ResponseObject, int), verifyResponseStatusCode(com.kms.katalon.core.testobject.ResponseObject, int, com.kms.katalon.core.model.FailureHandling)

Is this the intended final JSON you want to achieve?
Or an array with thousand objects, one for each “to” field?

I think 1st … so in this case, don’t do one binding for each value, but for a single one:

def binding = [
to : some_variable
]

declare the some_variable in the test-case variable tab.
Build a data file with the needed values for the “to” field
Make a test suite and add the testcase to your suite
Bind the data file to the test-case in the suite.

When you execute the suite, the test-case will run once for each value provided in the data file.

If 2nd (you want to build an array of objects) kindly post what is the intended structure for the final JSON and i can sketch some code, using a map and pushing elements into it.

The binding of variable for the test is working. It worked exactly how it was suggested.

def text = ‘’’{"_id": “somString1”, “to”: “${to}”, “launch”: true}’’’
def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)

def binding = [
to : someVariable1] (someVariable1 is defined in the test case variables tab)
String response = template.make(binding)

But it is failing for two variables in the binding :

def text = ‘’’{"_id": “${id}”, “to”: “${to}”, “launch”: true}’’’
def binding = [
id : someVariable1,
to : someVariable2] (Both the variables are added in the variables section.)