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

fix: res.send of cy.intercept doesn't override json-related content types #17401

Merged
merged 6 commits into from
Aug 6, 2021
24 changes: 24 additions & 0 deletions packages/driver/cypress/integration/commands/net_stubbing_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,30 @@ describe('network stubbing', { retries: 2 }, function () {
.wait('@get')
})

// https://github.com/cypress-io/cypress/issues/17084
it('does not overwrite the json-related content-type header', () => {
cy.intercept('/json-content-type', (req) => {
req.on('response', (res) => {
res.send({
statusCode: 500,
headers: {
'content-type': 'application/problem+json',
'access-control-allow-origin': '*',
},
body: {
status: 500,
title: 'Internal Server Error',
},
})
})
})

fetch('/json-content-type')
.then((res) => {
expect(res.headers.get('content-type')).to.eq('application/problem+json')
})
flotwig marked this conversation as resolved.
Show resolved Hide resolved
})

context('body parsing', function () {
[
'application/json',
Expand Down
9 changes: 8 additions & 1 deletion packages/driver/src/cy/net-stubbing/events/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,14 @@ export const onResponse: HandlerFn<CyHttpMessages.IncomingResponse> = async (Cyp
// arguments to res.send() are merged with the existing response
const _staticResponse = _.defaults({}, staticResponse, _.pick(res, STATIC_RESPONSE_KEYS))

_.defaults(_staticResponse.headers, res.headers)
_staticResponse.headers = _.defaults({}, _staticResponse.headers, res.headers)

// https://github.com/cypress-io/cypress/issues/17084
// When a user didn't provide content-type,
// we remove the content-type provided by the server
if (!staticResponse.headers || !staticResponse.headers['content-type']) {
delete _staticResponse.headers['content-type']
}
flotwig marked this conversation as resolved.
Show resolved Hide resolved

sendStaticResponse(requestId, _staticResponse)

Expand Down
14 changes: 13 additions & 1 deletion packages/driver/src/cy/net-stubbing/static-response-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
BackendStaticResponseWithArrayBuffer,
FixtureOpts,
} from '@packages/net-stubbing/lib/types'
import {
caseInsensitiveHas,
} from '@packages/net-stubbing/lib/util'
import $errUtils from '../../cypress/error_utils'

// user-facing StaticResponse only
Expand Down Expand Up @@ -112,7 +115,16 @@ export function getBackendStaticResponse (staticResponse: Readonly<StaticRespons
backendStaticResponse.body = staticResponse.body
} else {
backendStaticResponse.body = JSON.stringify(staticResponse.body)
_.set(backendStaticResponse, 'headers.content-type', 'application/json')

// There are various json-related MIME types. We cannot simply set it as `application/json`.
// @see https://www.iana.org/assignments/media-types/media-types.xhtml
if (
!backendStaticResponse.headers ||
(backendStaticResponse.headers &&
!caseInsensitiveHas(backendStaticResponse.headers, 'content-type'))
) {
_.set(backendStaticResponse, 'headers.content-type', 'application/json')
}
}
}

Expand Down
19 changes: 1 addition & 18 deletions packages/net-stubbing/lib/server/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ThrottleStream from 'throttle'
import MimeTypes from 'mime-types'
import { CypressIncomingRequest } from '@packages/proxy'
import { InterceptedRequest } from './intercepted-request'
import { caseInsensitiveGet, caseInsensitiveHas } from '../util'

// TODO: move this into net-stubbing once cy.route is removed
import { parseContentType } from '@packages/server/lib/controllers/xhrs'
Expand Down Expand Up @@ -79,24 +80,6 @@ function _getFakeClientResponse (opts: {
return clientResponse
}

const caseInsensitiveGet = function (obj, lowercaseProperty) {
for (let key of Object.keys(obj)) {
if (key.toLowerCase() === lowercaseProperty) {
return obj[key]
}
}
}

const caseInsensitiveHas = function (obj, lowercaseProperty) {
for (let key of Object.keys(obj)) {
if (key.toLowerCase() === lowercaseProperty) {
return true
}
}

return false
}

export function setDefaultHeaders (req: CypressIncomingRequest, res: IncomingMessage) {
const setDefaultHeader = (lowercaseHeader: string, defaultValueFn: () => string) => {
if (!caseInsensitiveHas(res.headers, lowercaseHeader)) {
Expand Down
17 changes: 17 additions & 0 deletions packages/net-stubbing/lib/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const caseInsensitiveGet = function (obj, lowercaseProperty) {
for (let key of Object.keys(obj)) {
if (key.toLowerCase() === lowercaseProperty) {
return obj[key]
}
}
}

export const caseInsensitiveHas = function (obj, lowercaseProperty) {
for (let key of Object.keys(obj)) {
if (key.toLowerCase() === lowercaseProperty) {
return true
}
}

return false
}