Ask a Question

Performing post request with content-type multipart/form-data (for binary file)

TestKeks
Occasional Contributor

Performing post request with content-type multipart/form-data (for binary file)

Hi,

 

in a script test, I would like to use the send method to send a binary file, namely a desktop screenshot, formatted in the content type "multipart/form-data". According to the JavaScript code example for the CreatePostRequest Method I wrote down the following:

 

 

function httpPostRequest()

{

  var address = "https://example.com/receiver";

 

  // Define the request body FormData-Object

  var requestBody = new FormData(Sys.Desktop.Picture());

 

  // Create the aqHttpRequest object

  var aqHttpRequest = aqHttp.CreatePostRequest(address, "", "");

 

  // Specify the Content-Type header value

  aqHttpRequest.SetHeader("Content-Type", "multipart/form-data");

 

  // Send the request, create the aqHttpResponse object

  var aqHttpResponse = aqHttpRequest.Send(requestBody);

 

  // Check the response:

  Log.Message(aqHttpResponse.StatusCode); // A status code

  Log.Message(aqHttpResponse.Text); // A body

}

 

But the JavaScript object FormData, which is to be generated in this code, is apparently not supported by TestComplete. The error "ReferenceError: FormData is not defined" appears. Or what am I doing wrong?

 

Is there any other way? Or do I have to build my own function to format the binary code according to the standard (see here)?

 

Thanks in advance for any hint and best regards

13 REPLIES 13
AlexKaras
Champion Level 3

Hi,

 

a) I am not sure that FormData is "JavaScript object" but not something provided by the browser (https://developer.mozilla.org/en-US/docs/Web/API/FormData);

b) I am not sure that

var requestBody = new FormData(Sys.Desktop.Picture());

will work. According to the samples, you should first save .Desktop.Picture() to the file and use something like

formData.append('image', <FullFileName>);

then;

c) If you don't need to use different files every time (and I am pretty sure that you don't), you may capture request that sends some small file using Fiddler or the tool like it and use captured data for the form content.

Regards,
  /Alex [Community Champion]
____
[Community Champions] are not employed by SmartBear Software but
are just volunteers who have some experience with the tools by SmartBear Software
and a desire to help others. Posts made by [Community Champions]
may differ from the official policies of SmartBear Software and should be treated
as the own private opinion of their authors and under no circumstances as an
official answer from SmartBear Software.
The [Community Champion] signature is assigned on quarterly basis and is used with permission by SmartBear Software.
https://community.smartbear.com/t5/Community-Champions/About-the-Community-Champions-Program/gpm-p/252662
================================
TestKeks
Occasional Contributor

Hi AlexKaras,

 

regarding a) and b) you may be right in principle.

 

But either way, since the FormData object is not supported by TestComplete, the method formData.append() cannot work either. Because even if I try to initiate the FormData object empty ...

 

var requestBody = new FormData();

 

... I get the same error.

 

I did not quite understand what you mean by c). Maybe I should have mentioned that I need the routine for some web tests that have to run on CrossBrowserTesting devices. I wanted to avoid opening another browser tab for such actions in parallel to the tested web application. And of course, I can't access desktop applications on these devices at all - if that's necessary for such additional tools. Otherwise could you please outline the use of Fiddler in this context a little closer?

 

Thank you and best regards

Hi,

 

> since the FormData object is not supported by TestComplete

Depending on the scripting language of your test project, you may look for some third-party library/component that will provide such functionality and use it. However, there may be problems with deploying required components to the CrossBrowserTesting environment.

 

> could you please outline the use of Fiddler in this context a little closer?

The suggestion is based on the assumption that you don't need to send some specific file in your test but it is acceptable if the same file is sent every time.

If this assumption is correct, then you may use Fiddler or any other request-capturing tool to capture the request that sends some small (for performance considerations) file. The captured request will provide you with the already properly encoded body part. So you may store it in some file or as a constant string in test code and use in the test.

Regards,
  /Alex [Community Champion]
____
[Community Champions] are not employed by SmartBear Software but
are just volunteers who have some experience with the tools by SmartBear Software
and a desire to help others. Posts made by [Community Champions]
may differ from the official policies of SmartBear Software and should be treated
as the own private opinion of their authors and under no circumstances as an
official answer from SmartBear Software.
The [Community Champion] signature is assigned on quarterly basis and is used with permission by SmartBear Software.
https://community.smartbear.com/t5/Community-Champions/About-the-Community-Champions-Program/gpm-p/252662
================================
TestKeks
Occasional Contributor

Hi,

 

> Depending on the scripting language of your test project, you may look for some third-party library/component that will provide such functionality and use it. However, there may be problems with deploying required components to the CrossBrowserTesting environment.

 

That's exactly my problem. Smiley Happy

Fiddler will then also be excluded as an option.

 

That's why, in the meantime, I have taken a closer look at the syntax required for the multipart/form-data content type in order to assemble the string for myself, that has to be transmitted.

 

But therefore I also need an approach to read the byte code of the binary graphic file and append it to my output variable. I assumed that the second code example at https://support.smartbear.com/testcomplete/docs/reference/program-objects/aqbinaryfile/index.html could help me with this:

 

function ReadByteFromFile()
{
  var Path = "C:\\MyFiles\\Desktop.jpg";

  // Opens the specified file for reading
  var myFile = aqFile.OpenBinaryFile(Path, aqFile.faRead);
  Log.Message("File by bytes:");

  // Reads bytes from the file and posts them to the test log 
  while(! myFile.IsEndOfFile())
  {
    s = myFile.ReadByte();
    Log.Message(s);
  }

  // Closes the file
  myFile.Close();
}

Unfortunately, however, this does not result in the byte code but in a purely numerical chain (I suspect ASCII code?).

 

But how can I access the unaltered byte code, which I need? I do not find any further details on this in the TestComplete documentation.

 

Many thanks and best regards

HKosova
SmartBear Alumni (Retired)

Hi TestKeks,

 

File upload using multipart requests is tricky because the request body needs to be formatted with extra info - boundaries, Content-Disposition header, etc., as shown here.

 

aqHttp does not have a built-in method to format multipart requests. You will need to either format the request body manually (add the boundaries, Content-... headers, etc. yourself), or use some external tool or library to send the request.

 

Do you have curl? If yes, you could just shell out to curl:

var url = "http://httpbin.org/post";
var fileName = "C:\\my_image.png";
var fieldName = "file"; // The name of the form field whose value is the file contents.
// Check with the admins of the targer server or its docs
// to learn what field name to use.

var command = aqString.Format("curl \"%s\" -F \"%s=@%s\"", url, fieldName, fileName);
// TC 12.0+ WshShell.Run(command, 0, true);
// TC <= 11.x
// Sys.OleObject("WScript.Shell").Run(command, 0, true);
// TODO: check response status and content if needed

 

Alternatively, if you have .NET Framework 4.5+, you can use its HttpClient and MultipartFormDataContent classes as shown in the following example. You need to add the System.Net.Http assembly to Tools > Current Project Properties > CLR Bridge to use this code.

var url = "http://httpbin.org/post";
var fileName = "C:\\my_image.png";
var fieldName = "file"; // The name of the form field whose value is the file contents.
// Check with the admins of the targer server or its docs
// to learn what field name to use.
// Read file contents as a byte array
var fileData = dotNET.System_IO.File.ReadAllBytes(fileName);

// Configure multipart request
var httpClient = dotNET.System_Net_Http.HttpClient.zctor();
var formData = dotNET.System_Net_Http.MultipartFormDataContent.zctor();
formData.Add_3(dotNET.System_Net_Http.ByteArrayContent.zctor(fileData),
fieldName,
aqFileSystem.GetFileName(fileName));

// Send the request and check the response
var response = httpClient.PostAsync(url, formData).Result;
if (response.IsSuccessStatusCode)
{
Log.Message("success!")
}
Log.Message("Status: " + response.StatusCode.value__); // e.g. 200 or 400
Log.Message("Response contents - see Additional Info", response.Content.ReadAsStringAsync().Result);

Helen Kosova
SmartBear Documentation Team Lead
________________________
Did my reply answer your question? Give Kudos or Accept it as a Solution to help others. ⬇️⬇️⬇️
TestKeks
Occasional Contributor

Hi Helen,

 

thanks for your reply. Our messages have crossed.

 
As I wrote above, only those approaches that I can use for TestComplete tests on CrossBrowserTesting are useful to me. That's why I have already started to create the required multipart/form-data format myself (of course including the required headers and boundaries etc.). Outside of TestComplete, I have already succeeded in doing so. I now only need the correct method to integrate the binary image data into my post message.

Thank you and best regards
TestKeks
Occasional Contributor

3rd attempt (why was my answer to Alex' last post deleted twice?):

 

Hi,

 

> Depending on the scripting language of your test project, you may look for some third-party library/component that will provide such functionality and use it. However, there may be problems with deploying required components to the CrossBrowserTesting environment.

 

That's exactly my problem. 🙂
Fiddler will then also be excluded as an option.

 

That's why, in the meantime, I have taken a closer look at the syntax required for the multipart/form-data content type in order to assemble the string for myself, that has to be transmitted.

 

But therefore I also need an approach to read the byte code of the binary graphic file and append it to my output variable. I assumed that the second code example at https://support.smartbear.com/testcomplete/docs/reference/program-objects/aqbinaryfile/index.html could help me with this:

 

function ReadByteFromFile()
{
  var Path = "C:\\MyFiles\\Desktop.jpg";

  // Opens the specified file for reading
  var myFile = aqFile.OpenBinaryFile(Path, aqFile.faRead);
  Log.Message("File by bytes:");

  // Reads bytes from the file and posts them to the test log 
  while(! myFile.IsEndOfFile())
  {
    s = myFile.ReadByte();
    Log.Message(s);
  }

  // Closes the file
  myFile.Close();
}

Unfortunately, however, this does not result in the byte code but in a purely numerical chain (I suspect ASCII code?).

 

But how can I access the unaltered byte code, which I need? I do not find any further details on this in the TestComplete documentation.

 

Many thanks and best regards

Hi,

 

Once again in order to double-check:

Do you *really* need to send *different* files from your test? Won't sending of the same file work?

Regards,
  /Alex [Community Champion]
____
[Community Champions] are not employed by SmartBear Software but
are just volunteers who have some experience with the tools by SmartBear Software
and a desire to help others. Posts made by [Community Champions]
may differ from the official policies of SmartBear Software and should be treated
as the own private opinion of their authors and under no circumstances as an
official answer from SmartBear Software.
The [Community Champion] signature is assigned on quarterly basis and is used with permission by SmartBear Software.
https://community.smartbear.com/t5/Community-Champions/About-the-Community-Champions-Program/gpm-p/252662
================================
TestKeks
Occasional Contributor

Hi Alex,

 

I apologize for not having explicitly stated that yet. The answer is: Yes, I would like to send a screenshot directly from the respective CrossBrowserTesting machine in certain situations, for example (but not only) in case of an error during testing. And I don't want to have to wait until the log data has finally landed on the local computer after completing all assigned test runs on all the CBT machines concerned (which can take several hours).

 

Thanks + best regards

cancel
Showing results for 
Search instead for 
Did you mean: