Skip to content

Instantly share code, notes, and snippets.

@ZwaarContrast
Last active May 2, 2023 20:31
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ZwaarContrast/00101934954980bcaa4ae70ac9930c60 to your computer and use it in GitHub Desktop.
Save ZwaarContrast/00101934954980bcaa4ae70ac9930c60 to your computer and use it in GitHub Desktop.
Using cypress with react-dropzone to upload a file.
// your react component
import * as React from 'react'
import Dropzone from 'react-dropzone'
// apply your own styling and stuff, should probably also show the files when uploaded
const Upload = () => {
return (<Dropzone data-cy="drag-and-drop">Drag and Drop here</Dropzone>)
}
export default Upload
// cypress test
describe('Test', function() {
it('Should be able upload', function() {
// upload file using drag and drop using a fixtue
cy.fixture('files/file.pdf', 'base64').then(content => {
cy.get('[data-cy=drag-and-drop]').upload(content, 'filename.pdf')
})
// assert succesful upload and continue testing
})
})
// Custom comand to handle uploading a file using react-dropzone
// Should probably be placed somewhere in /support/
Cypress.Commands.add(
'upload',
{
prevSubject: 'element',
},
(subject, file, fileName) => {
// we need access window to create a file below
cy.window().then(window => {
// line below could maybe be refactored to make use of Cypress.Blob.base64StringToBlob, instead of this custom function.
// inspired by @andygock, please refer to https://github.com/cypress-io/cypress/issues/170#issuecomment-389837191
const blob = b64toBlob(file, '', 512)
// Please note that we need to create a file using window.File,
// cypress overwrites File and this is not compatible with our change handlers in React Code
const testFile = new window.File([blob], fileName)
cy.wrap(subject).trigger('drop', {
dataTransfer: { files: [testFile] },
})
})
}
)
// Code stolen from @nrutman here: https://github.com/cypress-io/cypress/issues/170
function b64toBlob(b64Data, contentType = '', sliceSize = 512) {
const byteCharacters = atob(b64Data)
const byteArrays = []
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize)
const byteNumbers = new Array(slice.length)
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
}
const blob = new Blob(byteArrays, { type: contentType })
return blob
}
@donaldpipowitch
Copy link

Thank you!

@jaimefps
Copy link

This was so helpful!

@eranlesser
Copy link

works great , we enhanced the upload (subject, file, fileName) and added a props attribute (subject, file, fileName, props) so we can simulate different file types. for example {type: 'text/csv'}

@hiimoliverwang
Copy link

Not sure if this is a recent requirement, but dataTransfer.types needs to be specified or else dropzone will throw an error because of this https://github.com/react-dropzone/react-dropzone/blob/master/src/utils/index.js#L74

without it, it'll throw Array.prototype.some is called on null or undefined

here's what i put to get it to work

dataTransfer: { files: [testFile], types: ["Files"] },

hopefully my digging through the source code to find the error can prevent someone else from doing the same

@aaronFranssell
Copy link

@hiimoliverwang that just saved my bacon. Thanks!

@mariokandut
Copy link

@hiimoliverwang Big Thanks!

@sepehr500
Copy link

@hiimoliverwang Thanks!

@YacheLee
Copy link

YacheLee commented Jan 18, 2020

It works! Thanks.

@kathybeatz
Copy link

@hiimoliverwang thank you!

@breizhwave
Copy link

amazing stuff. Just one thing when I restrict on image files via js configuration acceptedFiles: 'image/*' , it returns "You can't upload files of this type." whatever the filetype, even for images... any idea ? using your code on cypress 3.4.1 and jquery , not react btw :)

Dropzone.options.waveDropzone = { uploadMultiple: true, // acceptedFiles: 'image/*', parallelUploads: 1, maxFilesize: 0.5, createImageThumbnails:false,

@fabianluna
Copy link

@akinnee
Copy link

akinnee commented Jul 23, 2020

This didn't work for me. I ended up using cypress-file-upload, which triggers a few additional evens before and after drop.

@nathanielongyiitak
Copy link

nathanielongyiitak commented Oct 23, 2020

Is there any updates for this code? cypress-file-upload's attachFile doesn't work for me (with or without submitType: 'drag-n-drop').

Thanks in advance.

@janetlee
Copy link

🙏 @hiimoliverwang.

I just spent 2 days figuring out why my file wouldn't post. If @ZwaarContrast could update, that will save the next person a lot of time. lol

Thank you so much for writing this up. This is the implementation I used because for some reason Cypress.Blob did. not have base64StringToBlob available to it so I installed it and imported it into my commands.js file.

import { base64StringToBlob } from 'blob-util';

Cypress.Commands.add(
  'uploadFile',
  {
    prevSubject: 'element',
  },
  (subject, file, fileName) => {
    cy.window().then(window => {
      const blob = base64StringToBlob(file, 'base64')
      const testFile = new window.File([blob], fileName)
      cy.wrap(subject).trigger('drop', {
        dataTransfer: { files: [testFile], types: ["Files"] }
    })
  })
})

@u119102
Copy link

u119102 commented Apr 26, 2021

If you use cypress-file-upload and end up here like I did, I got it working by using the b64toBlob function from @ZwaarContrast's upload.js file above instead of fileContent.toString()

    cy.fixture(fileName)
      .then(fileContent => {
        cy.get('input[type="file"]').attachFile({
          fileContent: b64toBlob(fileContent),
          fileName,
          mimeType: 'image/jpeg'
        });
      });

Please someone let me know if there is a better way now.

@rluisr
Copy link

rluisr commented Apr 29, 2021

working perfectly! Thanks!

@owezzy
Copy link

owezzy commented May 19, 2021

using cypress v7+,Angular 10 with filepond file upload library:

 cy.fixture('images/SampleJPGImage.jpg', 'base64')
      .then(Cypress.Blob.base64StringToBlob)
      .then((fileContent) => {
        cy.get(ImageUploadSelectors.FILEPOND_INPUT_LABEL).attachFile({
          fileName: 'SampleJPGImage.jpg',
          fileContent,
          mimeType: 'image/jpeg',
        });
      });

@maximbashevoy
Copy link

If you are using cypress-file-upload, the following seems to be sufficient (at least for Excel files) to attach a file and trigger the upload call:

cy.get('[data-cy=dropzone]')
            .attachFile(filePathInFixturesFolder, { subjectType: 'drag-n-drop' })

@vinipachecov
Copy link

Huge thanks to @hiimoliverwang!

@kylejw2
Copy link

kylejw2 commented Jun 28, 2021

Thank you @maximbashevoy 💯

@sanzhardanybayev
Copy link

If you use cypress-file-upload and end up here like I did, I got it working by using the b64toBlob function from @ZwaarContrast's upload.js file above instead of fileContent.toString()

    cy.fixture(fileName)
      .then(fileContent => {
        cy.get('input[type="file"]').attachFile({
          fileContent: b64toBlob(fileContent),
          fileName,
          mimeType: 'image/jpeg'
        });
      });

Please someone let me know if there is a better way now.

Your approach does work! Thanks!

@ex-rajesh-edx
Copy link

Thanks brother.

@sezeresim
Copy link

@maximbashevoy Thank you

@chinnep
Copy link

chinnep commented Oct 5, 2022

Cheers to this thread! Thanks all

@L0Lmaker
Copy link

L0Lmaker commented Mar 27, 2023

cy.get('[data-cy=dropzone]')
            .attachFile(filePathInFixturesFolder, { subjectType: 'drag-n-drop' })

Can confirm this works with CSV files as well. Thanks!

@Nemsae
Copy link

Nemsae commented May 2, 2023

For anyone else running into this problem, I would like to share my solution which is an amalgamation of everything suggested here.

For an image e.g. image/jpeg, I used OP's @ZwaarContrast b64toBlob:

cy.fixture('image_file.jpg')
          .then(fileContent => {
            cy.get('input[type="file"]')
              .attachFile({
                fileContent: b64toBlob(fileContent),
                fileName: 'image_file.jpg',
                mimeType: 'image/jpeg',
              });
          });

For a video file e.g. video/mp4, I used Cypress's Cypress.Blob.binaryStringToBlob to get the blob:

        cy.fixture('video_file.mp4', 'binary')
          .then(Cypress.Blob.binaryStringToBlob)
          .then(blob => {
            cy.get('input[type="file"]').attachFile({
              fileContent: blob,
              fileName: 'video_file.mp4',
              mimeType: 'video/mp4',
              encoding: 'utf8',
            });
          });

For a audio file e.g. .mp3/audio/mpeg, I also used Cypress's Cypress.Blob.binaryStringToBlob:

        cy.fixture('audio_file.mp3', 'binary')
          .then(Cypress.Blob.binaryStringToBlob)
          .then(blob => {
            cy.get('input[type="file"]')
              .attachFile({
                fileContent: blob,
                fileName: 'audio_file.mp3',
                mimeType: 'audio/mpeg',
              });
          });

Lastly, for CSV files, the following worked via drag and drop:

cy.get('.dropzone').attachFile('csv_file.csv', { subjectType: 'drag-n-drop' })

I am using the following package versions:

    "cypress": "^11.2.0",
    "react": "17.0.2",
    "react-dropzone": "^11.3.4",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment