Uploading a JSON File using API - Cypress.io [shorts]

In this news series called #shorts I'm taking a dig at few small but peculiar problems and their solution.

Hello!

We all know that cypress.io is a really cool automation tool where one can easily automate API and UI part of an web application easily. Cypress has everything working out for its success, as it provides most of the thing out of the box; except for few things which one has to tackle in not so easy fashion.

In this #short we are gonna explore how to tackle a simple JSON File Upload using cypress custom commands.

PROBLEM:

The problem that we're solving is to upload a JSON file passed as a form-data to an API end-point with a multipart/form-data request.

SOLUTION:

We are gonna start with writing a custom cypress command called "uploadFile()" inside /cypress/support/command.js

uploadFile() takes in 2 arguments;
url = the endpoint to where we have to upload a file,
formData = form-data object we have to pass along to the endpoint
/**
 * This Command uploads a file to a given POST endpoint
 * 
 * @param {String} url - full URL of the upload endpoint
 * @param {String} formData - formaData to be passed as body to endpoint
 */
 Cypress.Commands.add("uploadFile", (url, formData) => {
  return cy
    .server()
    .route("POST", url)
    .as("uploadFileRequest")
    .window()
    .then(window => {
      var xhr = new window.XMLHttpRequest();
      xhr.open("POST", url);
      xhr.send(formData);
    })
    .wait("@uploadFileRequest");
});
cy.uploadFile code inside /support/command.js

the above command is implemented using cy.server() (which at the time of writing this post cypress v.7.7.0 is now deprecated and will be moved to a plugin at a later version). In this command, we upload this file using the Javascript window method XMLHttpRequest()

We can reuse this command any number of times we'd like without repeating this code again and again.

Writing the code:

In the following code, we are fetching the user data from user.json present inside fixtures.

Once we have the user data we convert it to a blob using Cypress.blob base64StringToBlob() method (which converts a base64 string to a blob). We then use this created blob to construct a file by creating a new File object using a new File().

After that just create a simple form-data object and pass this newly formed File object into "content" form-data param.

The last thing is just to call cy.uploadFile() and pass the requestURL and form-data. The response to this request is stored in the "@createANewUser" alias.

  cy.fixture('/test/requestPayloads/user.json',"binary")
  .then(data => {
          const fileName = "user.json";
          const blob =   Cypress.Blob.base64StringToBlob(btoa(JSON.stringify(data)), 'application/json');
          const file =  new File([blob], fileName);
          const formData = new FormData();
          formData.set('name', "John");
          formData.set('description', "A new User named John");
          formData.set('id', generateRandomUUID());
          formData.set('citizenship', country.toUpperCase());
          formData.set('content', file);

          cy.uploadFile('/api/v2/user', formData).as('createANewUser');
      });
writing code for creating form-data and passing it to cy.uploadFile()

Note:
btoa(JSON.stringify(data)) is reuired to convert the binary user.json data string to base64 encoding first. Check this link  for more information about base64 encode/decode

That's all folks!!

Kushal Bhalaik

Kushal Bhalaik