Skip to content

Commit

Permalink
feat: change cy.intercept override behavior (#14543)
Browse files Browse the repository at this point in the history
  • Loading branch information
flotwig committed Mar 26, 2021
1 parent 491e6e2 commit f6a5d1e
Show file tree
Hide file tree
Showing 30 changed files with 1,327 additions and 513 deletions.
784 changes: 586 additions & 198 deletions packages/driver/cypress/integration/commands/net_stubbing_spec.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/driver/src/cy/commands/querying.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ module.exports = (Commands, Cypress, cy, state) => {

aliasObj = {
alias,
command: state('routes')[request.routeHandlerId].command,
command: state('routes')[request.routeId].command,
}
}

Expand All @@ -199,7 +199,7 @@ module.exports = (Commands, Cypress, cy, state) => {
if (requests.length) {
aliasObj = {
alias: toSelect,
command: state('routes')[requests[0].routeHandlerId].command,
command: state('routes')[requests[0].routeId].command,
}
}
}
Expand Down
48 changes: 37 additions & 11 deletions packages/driver/src/cy/net-stubbing/add-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RouteMatcher,
StaticResponse,
HttpRequestInterceptor,
PLAIN_FIELDS,
STRING_MATCHER_FIELDS,
DICT_STRING_MATCHER_FIELDS,
AnnotatedRouteMatcherOptions,
Expand All @@ -18,6 +19,7 @@ import {
validateStaticResponse,
getBackendStaticResponse,
hasStaticResponseKeys,
hasRouteMatcherKeys,
} from './static-response-utils'
import { registerEvents } from './events'
import $errUtils from '../../cypress/error_utils'
Expand Down Expand Up @@ -67,9 +69,7 @@ function annotateMatcherOptionsTypes (options: RouteMatcherOptions) {
}
})

const noAnnotationRequiredFields: (keyof RouteMatcherOptions)[] = ['https', 'port', 'matchUrlAgainstPath']

_.extend(ret, _.pick(options, noAnnotationRequiredFields))
_.extend(ret, _.pick(options, PLAIN_FIELDS))

return ret
}
Expand Down Expand Up @@ -113,7 +113,7 @@ function validateRouteMatcherOptions (routeMatcher: RouteMatcherOptions): { isVa
}
}

const booleanProps = ['https', 'matchUrlAgainstPath']
const booleanProps = ['https', 'matchUrlAgainstPath', 'middleware']

for (const prop of booleanProps) {
if (_.has(routeMatcher, prop) && !_.isBoolean(routeMatcher[prop])) {
Expand Down Expand Up @@ -209,7 +209,7 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
}

function addRoute (matcher: RouteMatcherOptions, handler?: RouteHandler) {
const handlerId = getUniqueId()
const routeId = getUniqueId()

const alias = cy.getNextAlias()

Expand Down Expand Up @@ -245,8 +245,12 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
routeMatcher.headers = lowercaseFieldNames(routeMatcher.headers)
}

if (routeMatcher.middleware && !hasInterceptor) {
return $errUtils.throwErrByPath('net_stubbing.intercept.invalid_middleware_handler', { args: { handler } })
}

const frame: NetEvent.ToServer.AddRoute = {
handlerId,
routeId,
hasInterceptor,
routeMatcher,
}
Expand All @@ -255,7 +259,7 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
frame.staticResponse = getBackendStaticResponse(staticResponse)
}

state('routes')[handlerId] = {
state('routes')[routeId] = {
log: getNewRouteLog(matcher, !!handler, alias, staticResponse),
options: matcher,
handler,
Expand All @@ -265,16 +269,38 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
}

if (alias) {
state('routes')[handlerId].alias = alias
state('routes')[routeId].alias = alias
}

return emitNetEvent('route:added', frame)
}

function intercept (matcher: RouteMatcher, handler?: RouteHandler | StringMatcher, arg2?: RouteHandler) {
function intercept (matcher: RouteMatcher, handler?: RouteHandler | StringMatcher | RouteMatcherOptions, arg2?: RouteHandler) {
function getMatcherOptions (): RouteMatcherOptions {
if (_.isString(matcher) && hasRouteMatcherKeys(handler)) {
// url, mergeRouteMatcher, handler
// @ts-ignore
if (handler.url) {
return $errUtils.throwErrByPath('net_stubbing.intercept.no_duplicate_url')
}

if (!arg2) {
return $errUtils.throwErrByPath('net_stubbing.intercept.handler_required')
}

const opts = {
url: matcher,
matchUrlAgainstPath: true,
...handler as RouteMatcherOptions,
}

handler = arg2

return opts
}

if (_.isString(matcher) && $utils.isValidHttpMethod(matcher) && isStringMatcher(handler)) {
// method, url, handler
// method, url, handler?
const url = handler as StringMatcher

handler = arg2
Expand All @@ -287,7 +313,7 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
}

if (isStringMatcher(matcher)) {
// url, handler
// url, handler?
return {
matchUrlAgainstPath: true,
url: matcher,
Expand Down
47 changes: 11 additions & 36 deletions packages/driver/src/cy/net-stubbing/events/after-response.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,26 @@
import { get } from 'lodash'
import { CyHttpMessages } from '@packages/net-stubbing/lib/types'
import { errByPath, makeErrFromObj } from '../../../cypress/error_utils'
import { HandlerFn } from '.'
import { parseJsonBody } from './utils'

export const onAfterResponse: HandlerFn<CyHttpMessages.ResponseComplete> = (Cypress, frame, userHandler, { getRequest, getRoute }) => {
const request = getRequest(frame.routeHandlerId, frame.requestId)

const { data } = frame
export const onAfterResponse: HandlerFn<CyHttpMessages.ResponseComplete> = async (Cypress, frame, userHandler, { getRequest, getRoute }) => {
const request = getRequest(frame.subscription.routeId, frame.requestId)

if (!request) {
return frame.data
return null
}

if (data.error) {
let err = makeErrFromObj(data.error)
// does this request have a responseHandler that has not run yet?
const isAwaitingResponse = !!request.responseHandler && ['Received', 'Intercepted'].includes(request.state)
const isTimeoutError = data.error.code && ['ESOCKETTIMEDOUT', 'ETIMEDOUT'].includes(data.error.code)

if (isAwaitingResponse || isTimeoutError) {
const errorName = isTimeoutError ? 'timeout' : 'network_error'

err = errByPath(`net_stubbing.request_error.${errorName}`, {
innerErr: err,
req: request.request,
route: get(getRoute(frame.routeHandlerId), 'options'),
})
}

request.state = 'Errored'
request.error = err

request.log.error(err)

if (isAwaitingResponse) {
// the user is implicitly expecting there to be a successful response from the server, so fail the test
// since a network error has occured
throw err
}

return frame.data
if (request.response && frame.data.finalResBody) {
request.response.body = frame.data.finalResBody
parseJsonBody(request.response)
}

request.state = 'Complete'

request.log.fireChangeEvent()
request.log.end()

return frame.data
// @ts-ignore
userHandler && await userHandler(request.response!)

return null
}
Loading

0 comments on commit f6a5d1e

Please sign in to comment.