Uploading Files with Cypress
Uploading Files with Cypress
Learn how to upload a file using Cypress
The HTML File Picker element is a way to allow users to upload specific files to a website.
For instance, if I wanted to upload a recipe for my photo, I can select that file, and we can see here that we even get a preview.
If I wanted to use Cypress to test out this element, I really have 2 options.
How to Use Cypress File Upload API
The easiest way to test file uploading with Cypress is to use a package on npm called cypress-file-upload. To use it, I would first install it with npm or Yarn, and then I would import it into my commands file.
To start off the test, the first thing I would do would be to get my File Picker input. So, I would use the typical command of cy.get() and pass in my ID of “#photo-upload”.
Then, I’ll have the method available to me of attachFile() where here, I want to specify the location of my image. Particularly, we want to place those files inside of the fixtures directory. So, I’m going to specify my image available at “images/french-toast.jpg”.
If we open Cypress and run our test, we can see that Cypress went through, it selected our input, it uploaded the file, and we can see the preview.
How to Upload Photos Using Cypress File API
Now using the File Upload Plugin is an easy way to do it if you can add a package, but what if you have to use the default Cypress API to upload a file?
The first thing we’re going to do is we’re going to define a fixture. So we’re going to use cy.fixture(). We’re going to specify that as ” images/french-toast.jpg”, and we’re going to specify that .as(‘photo’).
Next, like before, we’re going to use cy.get() to get our input at “#photo-upload”, but this time we’re going to use the then() command, where we’re going to pass in a custom function. To access our file, we want to use the Cypress Blob API.
We’re first going to define a constant of “blob”, and we’re going to set that equal to the Cypress.Blob.base64StringToBlob function, where we’re going to first pass in our photo. We can access this.photo on the this scope. Then we’re going to pass in the image type of “image/jpeg”.
Next, we’re going to use the JavaScript File API to create a new file.
We’ll first specify a new constant of const file, and we’re going to set that equal to new File([blob], where our first parameter is going to be an array where we’re going to include our blob. The next argument is going to be the location of our images. That’s at “images/french-toast.jpg”. Our last argument will be a new object, where we’ll again specify the image type, and we’ll say type: ‘image/jpeg’.
To send this image data, we need to create a new data transfer. So, we’re going to define a new constant called const data. And we’re going to set that equal to a new DataTransfer.
Then on our data object, we’re going to access the items, and we’re going to add a new file — data.items.add(file) — specifically, the new file we created above.
Next, we want to apply this DataTransfer to our input. We’re going to first specify a new argument of input in the function parameter in the cy.get line of code, like this — cy.get(‘#photo-upload’).then(function (input).
Now, because our input is technically an array of nodes, we’re going to specify input[0] grabbing the first item. Then we’re going to set the property of .files equal to data.files where we’re going to access the files of our data transfer.
At this point, our input should have the files associated with it, but we need to trigger a change event. That way, the browser or any APIs that are listening to the element can get notified of that change.
Finally, we’re going to create a new constant called const changeEvent where we’re going to set that equal to a new Event(). As the first argument, we’re going to specify the event name as “change”. For the second argument, we’re going to pass in a new function where we’re going to specify the key of bubbles: true.
With our changeEvent, we want to dispatch this event on our input. So, we’re going to specify input[0], and we’re going to grab the first one. We’re going to use the method dispatchEvent() and we’re going to pass in our “changeEvent”.
Now, if we open back up Cypress and we select our test file, we can see that Cypress first got that photo upload input, and then uploaded the file. But we can’t see the log, similar to what we did with that npm package. But we can see that it still worked with the upload preview.
Summing It Up – How to Test File Uploads with Cypress
To review, if we wanted to use the default Cypress APIs, we were able to create a fixture, where we then created a blob, a new file, and we transferred that data to the input and triggered a new Event.
Alternatively, if we wanted to take the easier route, we were able to install the cypress-file-upload package from npm. Then we were able to simply attachFile from our fixtures.
Resources
- Git Repo – file-picker.spec.js
- Applitools Kitchen – File Picker
- Cypress File Upload Plugin – npm cypress-file-upload
- Yarn JavaScript Package Manager
- Cypress Blob API
- MDN Web Docs – JavaScript File API