-
-
Save ZwaarContrast/00101934954980bcaa4ae70ac9930c60 to your computer and use it in GitHub Desktop.
// 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 | |
} |
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
@hiimoliverwang that just saved my bacon. Thanks!
@hiimoliverwang Big Thanks!
@hiimoliverwang Thanks!
It works! Thanks.
@hiimoliverwang thank you!
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,
@hiimoliverwang thanks
This didn't work for me. I ended up using cypress-file-upload
, which triggers a few additional evens before and after drop
.
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.
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"] }
})
})
})
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.
working perfectly! Thanks!
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',
});
});
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' })
Huge thanks to @hiimoliverwang!
Thank you @maximbashevoy 💯
If you use
cypress-file-upload
and end up here like I did, I got it working by using theb64toBlob
function from @ZwaarContrast's upload.js file above instead offileContent.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!
Thanks brother.
@maximbashevoy Thank you
Cheers to this thread! Thanks all
cy.get('[data-cy=dropzone]') .attachFile(filePathInFixturesFolder, { subjectType: 'drag-n-drop' })
Can confirm this works with CSV files as well. Thanks!
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",
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'}