How to test file inputs with Cypress?
How can I write an e2e test of flow that requires interaction with the file Input DOM element?
If it's a text input I can interact with it (check value, set value) etc as its a DOM component. But If I have a File Input element, I am guessing that the interaction is limited till I can open the dialog to select a File. I can't move forward and select the file I want to upload as the dialog would be native and not some browser element.
So how would I test that a user can correctly upload a file from my site? I am using Cypress to write my e2e tests.
it('Testing picture uploading', () => {
cy.fixture('testPicture.png').then(fileContent => {
cy.get('input[type="file"]').attachFile({
fileContent: fileContent.toString(),
fileName: 'testPicture.png',
mimeType: 'image/png'
});
});
});
Use cypress file upload package: https://www.npmjs.com/package/cypress-file-upload
Note: testPicture.png must be in fixture folder of cypress
For me the easier way to do this is using this cypress file upload package
Install it:
npm install --save-dev cypress-file-upload
Then add this line to your project's cypress/support/commands.js
:
import 'cypress-file-upload';
Now you can do:
const fixtureFile = 'photo.png';
cy.get('[data-cy="file-input"]').attachFile(fixtureFile);
photo.png
must be in cypress/fixtures/
For more examples checkout the Usage section on README of the package.
With this approach/hack you can actually make it: https://github.com/javieraviles/cypress-upload-file-post-form
It is based on different answers from the aformentioned thread https://github.com/cypress-io/cypress/issues/170
First scenario (upload_file_to_form_spec.js):
I want to test a UI where a file has to be selected/uploaded before submitting the form. Include the following code in your "commands.js" file within the cypress support folder, so the command cy.upload_file() can be used from any test:
Cypress.Commands.add('upload_file', (fileName, fileType, selector) => {
cy.get(selector).then(subject => {
cy.fixture(fileName, 'hex').then((fileHex) => {
const fileBytes = hexStringToByte(fileHex);
const testFile = new File([fileBytes], fileName, {
type: fileType
});
const dataTransfer = new DataTransfer()
const el = subject[0]
dataTransfer.items.add(testFile)
el.files = dataTransfer.files
})
})
})
// UTILS
function hexStringToByte(str) {
if (!str) {
return new Uint8Array();
}
var a = [];
for (var i = 0, len = str.length; i < len; i += 2) {
a.push(parseInt(str.substr(i, 2), 16));
}
return new Uint8Array(a);
}
Then, in case you want to upload an excel file, fill in other inputs and submit the form, the test would be something like this:
describe('Testing the excel form', function () {
it ('Uploading the right file imports data from the excel successfully', function() {
const testUrl = 'http://localhost:3000/excel_form';
const fileName = 'your_file_name.xlsx';
const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
const fileInput = 'input[type=file]';
cy.visit(testUrl);
cy.upload_file(fileName, fileType, fileInput);
cy.get('#other_form_input2').type('input_content2');
.
.
.
cy.get('button').contains('Submit').click();
cy.get('.result-dialog').should('contain', 'X elements from the excel where successfully imported');
})
})