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.wait yields string instead of object as intercepted request body #14273

Closed
tlpbu opened this issue Dec 22, 2020 · 12 comments
Closed

cy.wait yields string instead of object as intercepted request body #14273

tlpbu opened this issue Dec 22, 2020 · 12 comments
Labels
topic: cy.intercept() type: unexpected behavior User expected result, but got another

Comments

@tlpbu
Copy link

tlpbu commented Dec 22, 2020

cy.wait() yields object containing string instead of object as intercepted request/response body if cy.intercept() is used preventing deep equal assertions.

Current behavior

If request is stubbed with cy.route(), then cy.wait() yields object in request and response body as expected (if json is used).

Desired behavior

Yield object to simplify assertions

Test code to reproduce

I cannot provide full test due to info security but generic code involved is as:

      cy.route('POST', '/api/data, {}).as('storeDataRequest'); // passes with cy.route stubbing
      cy.intercept('POST', '/api/data', {}).as('storeDataRequest'); // fails with cy.intercept stubbing

      cy.contains('button', 'PUBLISH').click()
        .wait('@storeDataRequest')
        .should(interception => {
          expect(interception.request.body).to.deep.eq(
            { name: 'XYZ',
              date: `${dayjs().format('YYYY-MM-DD')}`,
              collectNew: false,
              productName: 'example.com',
              content: [{ locale: 'en', text: '<p>Text html</p>' }] }
          );
        });

Versions

Cypress 6.20

@jarretmoses
Copy link

jarretmoses commented Dec 22, 2020

Im having a similar-ish issue myself. It seems the actual api response is just missing and the body field is an empty string. The setup above is essentially identical to mine without adding adding the 3rd arg as an empty object. It does not actually happen 100% of the time. I've noticed when the response code is 304 Not Modified the body will not show my data but when it is 200 the data appears as expected.

@jarretmoses
Copy link

This may actually be a different issue...I've opened a new one

@tlpbu
Copy link
Author

tlpbu commented Dec 24, 2020

@jarretmoses you issue is something else. from description sounds like the one described here https://glebbahmutov.com/blog/cypress-intercept-problems/#cached-response with solution.

I have response and request body content it is just that it is string if stubbing done with cy.intercept() but was always an object with cy.route() previously and IMO it was more convenient for assertions.

@jennifer-shehane
Copy link
Member

@tlpbu This is actually only an issue with the request.body, not the response.body.

Reproducible example

it('test cy.route()', () => {
  cy.server()
  cy.route('POST', '/users', { foo: 'bar' }).as('postUrl')
  cy.visit('https://example.com')
  cy.window().then((win) => {
    const xhr = new win.XMLHttpRequest()
    xhr.open('POST', '/users')
    xhr.send({ name: 'XYZ' })
  })
  cy.wait('@postUrl')
    .should(xhr => {
      expect(xhr.request.body).to.deep.eq({ name: 'XYZ' })
      expect(xhr.response.body).to.deep.eq({ foo: 'bar'  })
    })
})

it('test cy.intercept()', () => {
  cy.intercept('POST', '/users', { foo: 'bar' }).as('postUrl')
  cy.visit('https://example.com')
  cy.window().then((win) => {
    const xhr = new win.XMLHttpRequest()
    xhr.open('POST', '/users')
    xhr.send({ name: 'XYZ' })
  })
  cy.wait('@postUrl')
  .should(interception => {
    expect(interception.response.body).to.deep.eq({ foo: 'bar' })
    // ❗️ fails because request.body is a string
    expect(interception.request.body).to.deep.eq({ name: 'XYZ' }
    )
  })
})

Screen Shot 2020-12-29 at 9 10 52 AM

@jennifer-shehane jennifer-shehane changed the title cy.wait yields string instead of object as intercepted request/response body if cy.intercept() is used cy.wait yields string instead of object as intercepted request body Dec 29, 2020
@jennifer-shehane jennifer-shehane added the type: unexpected behavior User expected result, but got another label Dec 29, 2020
@cypress-bot cypress-bot bot added the stage: needs investigating Someone from Cypress needs to look at this label Dec 29, 2020
@cypress-bot cypress-bot bot added stage: ready for work The issue is reproducible and in scope and removed stage: needs investigating Someone from Cypress needs to look at this labels Jan 20, 2021
@flotwig
Copy link
Contributor

flotwig commented Jan 22, 2021

@jennifer-shehane this still fails in 6.3.0, but I think the repro is wrong, the body of the XHR is not being stringified as you expect:
image

If I update the repro to properly send a JSON request body, it passes in 6.3.0:

    it('test cy.intercept()', () => {
      cy.intercept('POST', '/users', { foo: 'bar' }).as('postUrl')
      cy.visit('https://example.com')
      cy.then((win) => {
        Cypress.$.ajax({
          url: '/users',
          method: 'POST',
          contentType: 'application/json',
          data: JSON.stringify({ name: 'XYZ' }),
        })
      })

      cy.wait('@postUrl')
      .should((interception) => {
        expect(interception.response.body).to.deep.eq({ foo: 'bar' })
        // ❗️ fails because request.body is a string
        expect(interception.request.body).to.deep.eq({ name: 'XYZ' })
      })
    })

@tlpbu are you POSTing application/json type data or some other type of body? Only JSON bodies are automatically parsed in req.body and res.body, currently, but more could be added.

@tlpbu
Copy link
Author

tlpbu commented Jan 23, 2021

@flotwig Yes, it is JSON in request body.

@aethr
Copy link

aethr commented Jan 27, 2021

We're seeing a similar issue when we use cy.intercept and want to make changes to the intercepted response and then deliver it using res.send:

  cy.intercept('POST', '/users', (req) => {
    // ... a bunch of logic here
    req.reply((res) => {
      // send an object
      res.send({ name: 'XYZ' });
    });
  }).as('postUrl')

  cy.wait('@postUrl')
    .should((interception) => {
      // ❗️ fails because response.body is a string
      expect(interception.response.body).to.deep.eq({ name: 'XYZ' })
    })

@sybrendotinga
Copy link

sybrendotinga commented Feb 9, 2021

I have the same issue with the response.body.

This works with .route:

cy.route('GET', '**/projects/*/calculation').as('projectCalculation')
cy.wait('@projectCalculation').its('response.body').should('contain.keys', ['projectId', 'name'])

But this fails with .intercept:

cy.intercept('GET', '**/projects/*/calculation').as('projectCalculation')
cy.wait('@projectCalculation').its('response.body').should('contain.keys', ['projectId', 'name']) // etc.

I also tried this:

cy.wait('@projectCalculation').then(request => {
  console.log(typeof request.response.body) // Yields String, the whole body is not JSON, but a String
})

image

@flotwig
Copy link
Contributor

flotwig commented Feb 9, 2021

@flotwig Yes, it is JSON in request body.

Are you sending content-type application/json? That is what matters.

If you are using another content-type, see #14763

@flotwig
Copy link
Contributor

flotwig commented Feb 9, 2021

@sybrendotinga The response type from your server is incorrect. It is text/html, but should be application/json.

@sybrendotinga
Copy link

@sybrendotinga The response type from your server is incorrect. It is text/html, but should be application/json.

Life safer! This was my problem.

@flotwig
Copy link
Contributor

flotwig commented Mar 24, 2021

Closing since there should not be any issues with this with the current release of Cypress as long as Content-Type is correct - see: #14273 (comment)

If you're still experiencing this issue with a JSON content-type in the latest version of Cypress, please open a new issue.

@flotwig flotwig closed this as completed Mar 24, 2021
@cypress-io cypress-io locked as resolved and limited conversation to collaborators Mar 24, 2021
@jennifer-shehane jennifer-shehane removed the stage: ready for work The issue is reproducible and in scope label May 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
topic: cy.intercept() type: unexpected behavior User expected result, but got another
Projects
None yet
Development

No branches or pull requests

6 participants