Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cy.intercept() breaks uploaded image #9359

Closed
AlexCSR opened this issue Nov 27, 2020 · 10 comments · Fixed by #14235
Closed

cy.intercept() breaks uploaded image #9359

AlexCSR opened this issue Nov 27, 2020 · 10 comments · Fixed by #14235

Comments

@AlexCSR
Copy link

AlexCSR commented Nov 27, 2020

Current behavior

When using cy.intercept(), an image uploaded has incorrect size and doesn't recognized as image. It's almost 2x more in size than original image.

Desired behavior

An image uploaded should be the same as the original image.

Test code to reproduce

Please clone and try: https://github.com/AlexCSR/cypress-intercept-buffer-bug

Versions

Cypress: 6.0.0


This issue looks similar to #9166 and only faced with cy.route2() / cy.intercept(), but not with cy.route().

@jennifer-shehane
Copy link
Member

I am able to recreate the issue from the repo provided.

@bahmutov
Copy link
Contributor

bahmutov commented Dec 3, 2020

Tried Cypress v6.0.1 and the latest develop branch, still breaks

Even breaks when simply spying using cy.intercept

it.only('spy only', () => {
  cy.intercept('PUT', 'http://localhost:3000/upload'); // only spy on the upload

  cy.visit('http://localhost:3000/');
  cy.get('input').attachFile('image.jpeg');
  cy.get('button').click();
  cy.get('span').should(function ($span) {
    expect($span).to.have.text('SUCCESS')
  });
})

The command log shows

Screen Shot 2020-12-03 at 2 41 34 PM

Note: the image upload code

var formData = new FormData();
formData.append('image', input.files[0]);
axios.put('http://localhost:3000/upload', formData)

@nickpalmer
Copy link

I just discovered this is ALSO an issue with blob downloads as I was attempting to test a PDF download by parsing the intercepted body, but the PDF parser pukes.

It turns out the intercepted body has way more bytes than the actual API provided, so the bug exists in intercept on both send and receive.

@nickpalmer
Copy link

I suspect the toString() is incorrect here:

request.req.body = frame.req.body = reqBody.toString()

@pedrojpj
Copy link

Same issue here and continues in version 6.1.0.

Any progress on fixing it? This prevents the use of intercept in requests with formData.

@Threnos
Copy link

Threnos commented Dec 16, 2020

Me and colleague just spent 2 hours on figuring out why file download request was failing not even getting to back-end. It was cy.intercept that broke request somewhere in the middle (or, maybe, the very moment it was detected).

@maxbause
Copy link
Contributor

Hey everyone 👋,
I run into the same problem this week, and I found a possible solution/hack.

⚠️ Disclaimer: I'm new to cypress source code that's why I have only assumptions and no proof for some statements. if I have assumed something wrong, please correct me.

The problem

As @nickpalmer mentioned, the issue lies in:

request.req.body = frame.req.body = reqBody.toString()

The parameter reqBody is the original request body represented by a Buffer. If this buffer gets encoded with .toString() it will be encoded to utf8, since it is the default encoding.

That results in a change of the actual byte length of the request body.

  request.req.pipe(network_1.concatStream(function (reqBody) {
       request.req.body = frame.req.body = reqBody.toString() 
       console.log("Original content length: ", request.req.headers["content-length"], " Bytes")
       console.log("Binary content length: ", reqBody.byteLength, " Bytes")
       console.log("UTF-8 content length: ", Buffer.byteLength(reqBody.toString(), 'utf8'), " Bytes")
       cb();
  }));
Original content length: 18135  Bytes
Binary content length: 18135  Bytes
UTF-8 content length: 29223  Bytes

Now the content-length header is no longer correct, thus resulting in an error on the backend. You might get something like [ExceptionsHandler] Unexpected end of multipart data. (NestJS in my case).

A possible solution

After some manual testing I came across this working solution:

  request.req.pipe(network_1.concatStream(function (reqBody) {
      request.req.body = frame.req.body || reqBody.byteLength ? reqBody : undefined
      cb();
  }));

It is key to omit toString() because trying to encode into a different encoding may work but can/will result in broken files attached to the multipart/form-data form.

Can anyone give me feedback on this solution? I would be more than willing to make a pull request for it.

Cheers,
Max

@flotwig
Copy link
Contributor

flotwig commented Dec 17, 2020

@maxbause it sounds like you're on the right track, feel free to open a PR and I can help if you run into any issues

@cypress-bot cypress-bot bot added stage: work in progress and removed stage: needs investigating Someone from Cypress needs to look at this labels Dec 18, 2020
@cypress-bot cypress-bot bot added stage: needs review The PR code is done & tested, needs review and removed stage: work in progress labels Dec 28, 2020
@cypress-bot cypress-bot bot added stage: pending release and removed stage: needs review The PR code is done & tested, needs review labels Dec 29, 2020
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Dec 29, 2020

The code for this is done in cypress-io/cypress#14235, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jan 4, 2021

Released in 6.2.1.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v6.2.1, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators Jan 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
9 participants