From a92b0c17d812282e1a6f74b2f404e36ab6e37b92 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 5 Aug 2021 20:33:29 -0400 Subject: [PATCH] fix: `res.send` of `cy.intercept` doesn't override json-related content types (#17401) Co-authored-by: Kukhyeon Heo --- .../integration/commands/net_stubbing_spec.ts | 25 +++++++++++++++++++ .../src/cy/net-stubbing/events/response.ts | 12 ++++++++- .../cy/net-stubbing/static-response-utils.ts | 14 ++++++++++- packages/net-stubbing/lib/server/util.ts | 19 +------------- packages/net-stubbing/lib/util.ts | 17 +++++++++++++ 5 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 packages/net-stubbing/lib/util.ts diff --git a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts index 4210c22deba2..ee03bb722502 100644 --- a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts +++ b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts @@ -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', diff --git a/packages/driver/src/cy/net-stubbing/events/response.ts b/packages/driver/src/cy/net-stubbing/events/response.ts index 8220899d3c38..846799848257 100644 --- a/packages/driver/src/cy/net-stubbing/events/response.ts +++ b/packages/driver/src/cy/net-stubbing/events/response.ts @@ -77,7 +77,17 @@ export const onResponse: HandlerFn = 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) diff --git a/packages/driver/src/cy/net-stubbing/static-response-utils.ts b/packages/driver/src/cy/net-stubbing/static-response-utils.ts index 3e67fab322d7..7e5961e7af45 100644 --- a/packages/driver/src/cy/net-stubbing/static-response-utils.ts +++ b/packages/driver/src/cy/net-stubbing/static-response-utils.ts @@ -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 @@ -112,7 +115,16 @@ export function getBackendStaticResponse (staticResponse: Readonly string) => { if (!caseInsensitiveHas(res.headers, lowercaseHeader)) { diff --git a/packages/net-stubbing/lib/util.ts b/packages/net-stubbing/lib/util.ts new file mode 100644 index 000000000000..e922fcc8c120 --- /dev/null +++ b/packages/net-stubbing/lib/util.ts @@ -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 +}