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

feat: change cy.intercept override behavior #14543

Merged
merged 35 commits into from
Mar 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a8f51b2
wip: changes for req.on events, middleware
flotwig Mar 3, 2021
cc32828
fix types
flotwig Mar 4, 2021
06e62d0
Merge remote-tracking branch 'origin/7.0-release' into cy-intercept-o…
flotwig Mar 5, 2021
197af55
expose req.on, rename events
flotwig Mar 5, 2021
4257879
wip: request events work
flotwig Mar 8, 2021
6e70281
wip: call after:response handler
flotwig Mar 8, 2021
22c4c64
stopPropagation
flotwig Mar 11, 2021
2b4e9a0
fix tests
flotwig Mar 11, 2021
e8803a7
Merge remote-tracking branch 'origin/7.0-release' into cy-intercept-o…
flotwig Mar 11, 2021
6db421f
cleanup
flotwig Mar 11, 2021
b274804
routeHandlerId -> routeId, fix types
flotwig Mar 11, 2021
7829f89
types
flotwig Mar 12, 2021
cca8815
fix regression deleting headers
flotwig Mar 12, 2021
2c3dfa5
fix error tests
flotwig Mar 12, 2021
c95c84d
simplify event frame
flotwig Mar 12, 2021
bd73c84
update error tests
flotwig Mar 12, 2021
151054c
add handler chaining tests
flotwig Mar 12, 2021
c52133c
Merge remote-tracking branch 'origin/7.0-release' into cy-intercept-o…
flotwig Mar 12, 2021
421a7fd
Add req.continue to continue a request explicitly
flotwig Mar 22, 2021
7c7b5ca
Remove user-facing `before:request` surface
flotwig Mar 22, 2021
6968655
Add `cy.intercept(url, mergeRouteMatcher, handler)` overload
flotwig Mar 22, 2021
c78fe5a
Rename `after:response` to `response`
flotwig Mar 22, 2021
2753019
Update test now that `headers` is interpreted as a RouteMatcherOption
flotwig Mar 22, 2021
0664022
Break out response errors into `error` event
flotwig Mar 22, 2021
042050c
Differentiate `before:response` and `response`
flotwig Mar 23, 2021
e9496a1
Add res.send fixture test
flotwig Mar 24, 2021
96aa1bb
update runner error tests
flotwig Mar 24, 2021
112c9a1
cleanup
flotwig Mar 24, 2021
fc62a47
Update frontend with resolved fixture body
flotwig Mar 24, 2021
d591bac
fix type
flotwig Mar 24, 2021
7344235
Merge branch '7.0-release' into cy-intercept-overrides
flotwig Mar 24, 2021
762d6eb
Changes from review
flotwig Mar 25, 2021
8b72688
final touch
flotwig Mar 26, 2021
cb9d53d
Merge remote-tracking branch 'origin/7.0-release' into cy-intercept-o…
flotwig Mar 26, 2021
ae33091
appease linter
flotwig Mar 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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