Skip to content

Instantly share code, notes, and snippets.

@ZwaarContrast
Last active May 2, 2023 20:31
Show Gist options
  • 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
}
@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