Skip to content

Commit

Permalink
fix: res.send of cy.intercept doesn't override json-related conte…
Browse files Browse the repository at this point in the history
…nt types (#17401)

Co-authored-by: Kukhyeon Heo <sainthkh@naver.com>
  • Loading branch information
flotwig and sainthkh authored Aug 6, 2021
1 parent 171791b commit a92b0c1
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 20 deletions.
25 changes: 25 additions & 0 deletions packages/driver/cypress/integration/commands/net_stubbing_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,31 @@ 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',
},
})
})
})
.then(() => {
return fetch('/json-content-type')
.then((res) => {
expect(res.headers.get('content-type')).to.eq('application/problem+json')
})
})
})

context('body parsing', function () {
[
'application/json',
Expand Down
12 changes: 11 additions & 1 deletion packages/driver/src/cy/net-stubbing/events/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,17 @@ 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,
// and they provided body as an object,
// we remove the content-type provided by the server
if (!staticResponse.headers || !staticResponse.headers['content-type']) {
if (typeof _staticResponse.body === 'object') {
delete _staticResponse.headers['content-type']
}
}

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 * as $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
}

4 comments on commit a92b0c1

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a92b0c1 Aug 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/8.2.1/circle-develop-a92b0c17d812282e1a6f74b2f404e36ab6e37b92/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a92b0c1 Aug 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 ia32 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/8.2.1/appveyor-develop-a92b0c17d812282e1a6f74b2f404e36ab6e37b92/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a92b0c1 Aug 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/8.2.1/appveyor-develop-a92b0c17d812282e1a6f74b2f404e36ab6e37b92/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a92b0c1 Aug 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/8.2.1/circle-develop-a92b0c17d812282e1a6f74b2f404e36ab6e37b92/cypress.tgz

Please sign in to comment.