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

Kushal Bhalaik
Geek Culture
Published in
3 min readJul 9, 2021

--

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 the API and UI part of a web application easily. Cypress has everything working out for its success, as it provides most of the things out of the box; except for few things which one has to tackle is not an easy way.

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

Sample API code for creating a user and retrieving it using Cypress Aliases:

/**
* 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");
});

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.

writing code for creating form-data and passing it to cy.uploadFile()

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');
});

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

EDIT [2022]:

In the above article, we did the uploading of JSON file using now deprecated cy.server() and cy.route() commands; though they will keep working as a plugin in Cypress in the future until we will keep seeing a deprecation message in cypress console.

So there is an alternate implementation of cy.uploadFile() command:

/**
* 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.request({
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json'
},
body: formData
}).as('uploadFileRequest')

})

Now it can happen that sometimes the response that we get from this comment is not in plain JSON i.e it may contain Buffer object.

So we can Sanitize this using the below code:
converting Javascript ArrayBuffer to JSON object

cy.get('@uploadFileRequest').then(async (res) => {

//convert res.body ArrayBuffer to JSON object
var jsonResponse = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(res.body)))
return jsonResponse;
});

That’s all folks!!

Originally posted at https:kushalbhalaik.xyz/blog

--

--