UNPKG

@revoloo/cypress6

Version:

Cypress.io end to end testing tool

124 lines (93 loc) 3.46 kB
import _ from 'lodash' import { concatStream, httpUtils } from '@packages/network' import Debug from 'debug' import { Readable, PassThrough } from 'stream' import { ResponseMiddleware, } from '@packages/proxy' import { NetStubbingState, } from './types' import { CyHttpMessages, NetEventFrames, SERIALIZABLE_RES_PROPS, } from '../types' import { emit, sendStaticResponse, setResponseFromFixture, getBodyStream, } from './util' const debug = Debug('cypress:net-stubbing:server:intercept-response') export const InterceptResponse: ResponseMiddleware = function () { const backendRequest = this.netStubbingState.requests[this.req.requestId] debug('InterceptResponse %o', { req: _.pick(this.req, 'url'), backendRequest }) if (!backendRequest) { // original request was not intercepted, nothing to do return this.next() } backendRequest.incomingRes = this.incomingRes backendRequest.onResponse = (incomingRes, resStream) => { this.incomingRes = incomingRes backendRequest.continueResponse!(resStream) } backendRequest.continueResponse = (newResStream?: Readable) => { if (newResStream) { this.incomingResStream = newResStream.on('error', this.onError) } this.next() } const frame: NetEventFrames.HttpResponseReceived = { routeHandlerId: backendRequest.route.handlerId!, requestId: backendRequest.requestId, res: _.extend(_.pick(this.incomingRes, SERIALIZABLE_RES_PROPS), { url: this.req.proxiedUrl, }) as CyHttpMessages.IncomingResponse, } const res = frame.res as CyHttpMessages.IncomingResponse const emitReceived = () => { emit(this.socket, 'http:response:received', frame) } this.makeResStreamPlainText() new Promise((resolve) => { if (httpUtils.responseMustHaveEmptyBody(this.req, this.incomingRes)) { resolve('') } else { this.incomingResStream.pipe(concatStream((resBody) => { resolve(resBody) })) } }) .then((body) => { const pt = this.incomingResStream = new PassThrough() pt.end(body) res.body = String(body) emitReceived() if (!backendRequest.waitForResponseContinue) { this.next() } // this may get set back to `true` by another route backendRequest.waitForResponseContinue = false }) } export async function onResponseContinue (state: NetStubbingState, frame: NetEventFrames.HttpResponseContinue) { const backendRequest = state.requests[frame.requestId] if (typeof backendRequest === 'undefined') { return } const { res } = backendRequest debug('_onResponseContinue %o', { backendRequest: _.omit(backendRequest, 'res.body'), frame: _.omit(frame, 'res.body') }) const throttleKbps = _.get(frame, 'staticResponse.throttleKbps') || frame.throttleKbps const delay = _.get(frame, 'staticResponse.delay') || frame.delay if (frame.staticResponse) { // replacing response with a staticResponse await setResponseFromFixture(backendRequest.route.getFixture, frame.staticResponse) const staticResponse = _.chain(frame.staticResponse).clone().assign({ delay, throttleKbps }).value() return sendStaticResponse(backendRequest, staticResponse) } // merge the changed response attributes with our response and continue _.assign(res, _.pick(frame.res, SERIALIZABLE_RES_PROPS)) const bodyStream = getBodyStream(res.body, { throttleKbps, delay }) return backendRequest.continueResponse!(bodyStream) }