简体   繁体   中英

Send uploaded file to backend in Cypress

I am using Cypress to use my application and encounter a problem by sending an uploaded file to the backend. It sends an empty FormData .

I am using the code found here https://github.com/cypress-io/cypress/issues/170 to handle file upload which is:

 return cy.get('input[type=file]').then(subject => {
    return cy
        .fixture('blueprint.xlsx', 'base64')
        .then(Cypress.Blob.base64StringToBlob)
        .then(blob => {
            const el = <HTMLInputElement>subject[0]
            if (el != null) {
                const testFile = new File([blob], 'blueprint.xlsx')
                const dataTransfer = new DataTransfer()
                dataTransfer.items.add(testFile)
                el.files = dataTransfer.files
            }
            return subject
        })
}) 

When I debug the API call, the file is set, it is in the fixtures folder and everything seems fine but the call doesn't have any formdata (which should be the file) and ends in a 400 Bad request error.

Why is the formdata empty? Is this a Cypress problem? Is there a way to send my fixture file to the backend?

Your code seems to run ok on the ng-file-upload demo page .

I also tested with an 'xlsx' file, no problem found.

describe('Angular file upload Demo', () => {

  /*
    To run these tests, add a file 'logo.png' to /cypress/fixtures
  */

  it('uploads the fixture file', () => {
    cy.visit('https://angular-file-upload.appspot.com/')
    cy.get('[name=userName]').type('myLogo')

    cy.get('[name=file]').then(subject => {
      return cy.fixture('logo.png', 'base64')
        .then(Cypress.Blob.base64StringToBlob)
        .then(blob => {
          console.log('blob', blob)
          const el = subject[0]
          if (el != null) {
            const testFile = new File([blob], 'logo.png')
            const dataTransfer = new DataTransfer()
            dataTransfer.items.add(testFile)
            el.files = dataTransfer.files
          }
          return subject          
        })
    })

    cy.contains('button', 'Submit').click()

    cy.contains('.progress', '100%')
    cy.contains('body', 'Upload Successful')
  })

  Cypress.Commands.add('uploadFile', { prevSubject: 'element' }, (subject, fileName) => {
    console.log('subject', subject)
    return cy.fixture(fileName, 'base64')
      .then(Cypress.Blob.base64StringToBlob)
      .then(blob => {
        console.log('blob', blob)
        const el = subject[0]
        if (el != null) {
          const testFile = new File([blob], fileName)
          const dataTransfer = new DataTransfer()
          dataTransfer.items.add(testFile)
          el.files = dataTransfer.files
        }
        return subject          
      })
    }
  )

  it('uploads the file via custom command', () => {
    cy.visit('https://angular-file-upload.appspot.com/')
    cy.get('[name=userName]').type('myLogo')

    cy.get('[name=file]').uploadFile('logo.png')

    cy.contains('button', 'Submit').click()

    cy.contains('.progress', '100%')
    cy.contains('body', 'Upload Successful')
  })

})

I use "cypress": "3.3.1"

The following codes work for me,

const fixturePath = 'test.png';
const mimeType = 'application/png';
const filename = 'test.png';

cy.getTestElement('testUploadFrontID')
  .get('input[type=file')
  .eq(0)
  .then(subject => {
    cy.fixture(fixturePath, 'base64').then(front => {
      Cypress.Blob.base64StringToBlob(front, mimeType).then(function(blob) {
        var testfile = new File([blob], filename, { type: mimeType });
        var dataTransfer = new DataTransfer();
        var fileInput = subject[0];

        dataTransfer.items.add(testfile);
        fileInput.files = dataTransfer.files;

        cy.wrap(subject).trigger('change', { force: true });
      });
    });
  });

getTestElement is a command added by myself,

Cypress.Commands.add(`getTestElement`, selector =>
cy.get(`[data-testid="${selector}"]`)
);

after many hours of trying, i figured out a workaround to make ng-file-upload works.

At least my problem was about the File that was not passed as an instance of Blob, i guess.

I've used the same snippet as Jonas one on cypress side.

The workaround is to add a check into the upload function that manages changes in select and drop directives.

function upload() {
    if (!Upload.isFile(file)) {
      file = new File([file], file.name, { type: file.type })
    }

    Upload.upload({
        url: "/api/upload",
        data: {
          file: file
        }
    })
    .then(/* ... */)
    /* ... */
}

This is just a workaround and i don't really like it.

I don't know why this happens, it happens for me only when i test it using cypress, so i don't like to add that in my production code.

Could someone please help me understanding why this happens?

Does anyone know why the file instance passed into the upload function seems to be a File instance but then it's not?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM