Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload File with Cypress.io via Request

Given this simple form

<form action="/upload_file" method="POST" enctype="multipart/form-data" id="upload_file_form">
    <input type="file" name="file" required>
    <input type="text" placeholder="Select file" disabled>
    <input type="submit" value="upload">
</form>

Since native events are not supported by cypress.io (can't select a file), I have to use a post-request.

The request structure in cypress.io looks like

cy.request({
    method: 'POST',
    url: '/some/url',
    form: true,
    body: { ... },
    headers:{ ... }
})

I would like to know how I could send a simple *.txt

Any suggestions appreciated!

like image 863
Felix PK Avatar asked Nov 28 '17 14:11

Felix PK


2 Answers

Will leave this here in case it helps somebody https://github.com/javieraviles/cypress-upload-file-post-form

Second scenario (send_form_data_with_file_in_post_request_spec.js):

I want to build up the FormData myself( new FormData(), formData.append/formData.set ) and send it directly with a POST request to the backend or submit the form with the FormData I have created. For this case, the transmitted data must be in the same format as the form's submit(), which type is set to "multipart/form-data". Having a look at the MDN web docs to see how you can build a FormData: Using FormData Objects, and knowing that at this very moment (Cypress 2.1.0) cy.request doesn't support FormData (multipart/form-data) so we will need a XMLHttpRequest, the test can be performed as follows. Include the following code in your "commands.js" file within the cypress support folder, so the command cy.form_request() can be used from any test:
// Performs an XMLHttpRequest instead of a cy.request (able to send data as 
// FormData - multipart/form-data)
Cypress.Commands.add('form_request', (method, url, formData, done) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
        done(xhr);
    };
    xhr.onerror = function () {
        done(xhr);
    };
    xhr.send(formData);
})

Then, in case you want to send the same form as before (form containing an excel file and other plain inputs) but build it by yourself and send it directly to the server, the test would be something like this:

describe('Testing the API', function () {

    it('Receives valid FormData and proccesses the information correctly', 
        function () {

    /*
    The reason why this test may look a bit tricky is because the backend endpoint is expecting the 
    submission of a web Form (multipart/form-data), not just data within a POST. The "cy.request()" 
    command doesn't support sending a web Form as a body in a POST request, so the test uses a support 
    command that has been created to perform a genuine XMLHttpRequest where a web Form can be placed.
    */

    //Declarations
    const fileName = 'your_excel_file.xlsx';
    const method = 'POST';
    const url = 'http://localhost:3000/api/excel_form';
    const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
    const inputContent2 = 'input_content2';
    const expectedAnswer = '{"msg":"X elements from the excel where successfully imported"}';

    // Get file from fixtures as binary
    cy.fixture(fileName, 'binary').then( (excelBin) => {

        // File in binary format gets converted to blob so it can be sent as Form data
        Cypress.Blob.binaryStringToBlob(excelBin, fileType).then((blob) => {

            // Build up the form
            const formData = new FormData();
            formData.set('file', blob, fileName); //adding a file to the form
            formData.set('input2', inputContent2); //adding a plain input to the form
            .
            .
            .
            // Perform the request
            cy.form_request(method, url, formData, function (response) {
                expect(response.status).to.eq(200);
                expect(expectedAnswer).to.eq(response.response);
            });

        })

    })

})

})

like image 194
Javier Aviles Avatar answered Oct 30 '22 07:10

Javier Aviles


I just needed from Cypress context to upload a file somewhere (to mock something out before the browser does request it).

The following is working just fine in my case:

cy.fixture('something.svg').then((file) => {
  cy.request({
    url: 'http://mock/uploads/some-id',
    method: 'put',
    body: file,
  });
});
like image 23
maxime1992 Avatar answered Oct 30 '22 07:10

maxime1992