Yield object instead of string in cy.wait when request content-type is valid JSON Mime type (not only application/json)
See original GitHub issuePossibly a duplicate or related to https://github.com/cypress-io/cypress/issues/14273.
Our back-end services use JSON:API spec (https://jsonapi.org/) which recommends the media type application/vnd.api+json. They deliver valid JSON in the response body, which should be converted to an object by cy.wait
to allow for deep assertions.
Current behavior
If request is intercepted with cy.intercept()
, then cy.wait()
yields a string for the response body (related issue: #14273.)
From this comment: https://github.com/cypress-io/cypress/issues/14273#issuecomment-765625317, I believe this is due to the check in https://github.com/cypress-io/cypress/blob/6ee7a9c27e9ea8b7dceee6bae140ce86d816a5e1/packages/driver/src/cy/net-stubbing/events/utils.ts#L4-L20
Due to our back-end sending content-type: application/vnd.api+json
this check fails, and so the response body is not converted using JSON.parse
.
Desired behavior
I believe that if the response to a request is valid JSON, it should be converted to a JS object regardless of the headers. This approach is taken elsewhere in Cypress, ie: https://github.com/cypress-io/cypress/blob/dae76a8ec0a149d5f4ca4fbe4d15bea1b5f7449d/packages/server/lib/controllers/xhrs.js#L9-L23
Effectively if JSON.parse(text)
succeeds without throwing, we can assume that text
is valid JSON and return the resulting parsed object.
Test code to reproduce
describe('cy.intercept tests', () => {
it('test cy.intercept() with application/json', () => {
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(typeof interception.response.body).to.eq('object');
expect(interception.response.body).to.deep.eq({ foo: 'bar' })
});
});
it('test cy.intercept() with application/vnd.api+json', () => {
// temporary API endpoint at mocky.io that responds with 'content-type: application/vnd.api+json'
cy.intercept('GET', 'https://run.mocky.io/v3/5c528eae-f3c0-4dbe-b9cb-7b12a00320ad').as('jsonApiUrl');
cy.visit('https://example.com');
cy.then((win) => {
Cypress.$.ajax({
url: 'https://run.mocky.io/v3/5c528eae-f3c0-4dbe-b9cb-7b12a00320ad',
method: 'GET',
});
});
cy.wait('@jsonApiUrl')
.should((interception) => {
expect(interception.response.headers['content-type']).to.contain('application/vnd.api+json');
// ❗️ fails
expect(typeof interception.response.body).to.eq('object');
// ❗️ fails
expect(interception.response.body).to.deep.eq({ foo: 'bar' });
});
});
});
Versions
6.3.0
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:6 (3 by maintainers)
Good points. I did some testing and
route
in Cypress 5 and 6 are both consistent in not converting the response body to objects in this scenario, so my suggestion would probably be a breaking change for some.A brief search on iana turned up a few likely JSON-compatible media types:
Most seem to follow the same pattern:
application/SOMETHING+json
application/vnd.SOMETHING+json
Perhaps the check could be expanded to:
Released in
7.0.0
.This comment thread has been locked. If you are still experiencing this issue after upgrading to Cypress v7.0.0, please open a new issue.