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

fix: properly detect cy.intercept(url, routeMatcher, handler) overload #16167

Merged
merged 3 commits into from
Apr 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ describe('network stubbing', { retries: { runMode: 2, openMode: 0 } }, function
cy.wait('@create')
})

// @see https://github.com/cypress-io/cypress/issues/16117
it('can statically stub a url response with headers', () => {
cy.intercept('/url', { headers: { foo: 'bar' }, body: 'something' })
})

// TODO: implement warning in cy.intercept if appropriate
// https://github.com/cypress-io/cypress/issues/2372
it.skip('warns if a percent-encoded URL is used', function () {
Expand Down
7 changes: 5 additions & 2 deletions packages/driver/src/cy/net-stubbing/add-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ import {
validateStaticResponse,
getBackendStaticResponse,
hasStaticResponseKeys,
hasRouteMatcherKeys,
} from './static-response-utils'
import { registerEvents } from './events'
import $errUtils from '../../cypress/error_utils'
import $utils from '../../cypress/utils'

const lowercaseFieldNames = (headers: { [fieldName: string]: any }) => _.mapKeys(headers, (v, k) => _.toLower(k))

export function hasOnlyRouteMatcherKeys (obj: any) {
return !_.isEmpty(obj) && !_.isArray(obj) && _.isEmpty(_.omit(obj, _.concat(PLAIN_FIELDS, STRING_MATCHER_FIELDS, DICT_STRING_MATCHER_FIELDS)))
Copy link
Contributor

Choose a reason for hiding this comment

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

will this be truthy if obj is a function?

Copy link
Contributor Author

@flotwig flotwig Apr 23, 2021

Choose a reason for hiding this comment

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

like this?

cy.intercept('/url', () => {})
cy.intercept('/url', function () {})

nope, see net_stubbing_spec for examples of such usage

}

/**
* Get all STRING_MATCHER_FIELDS paths plus any extra fields the user has added within
* DICT_STRING_MATCHER_FIELDS objects
Expand Down Expand Up @@ -280,7 +283,7 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,

function intercept (matcher: RouteMatcher, handler?: RouteHandler | StringMatcher | RouteMatcherOptions, arg2?: RouteHandler) {
function getMatcherOptions (): RouteMatcherOptions {
if (_.isString(matcher) && hasRouteMatcherKeys(handler)) {
if (_.isString(matcher) && hasOnlyRouteMatcherKeys(handler)) {
// url, mergeRouteMatcher, handler
// @ts-ignore
if (handler.url) {
Expand Down
37 changes: 18 additions & 19 deletions packages/driver/src/cy/net-stubbing/events/before-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,24 +94,6 @@ export const onBeforeRequest: HandlerFn<CyHttpMessages.IncomingRequest> = (Cypre
requestWaited: false,
responseWaited: false,
subscriptions: [],
on (eventName, handler) {
if (!validEvents.includes(eventName)) {
return $errUtils.throwErrByPath('net_stubbing.request_handling.unknown_event', {
args: {
validEvents,
eventName,
},
})
}

if (!_.isFunction(handler)) {
return $errUtils.throwErrByPath('net_stubbing.request_handling.event_needs_handler')
}

subscribe(eventName, handler)

return request
},
}
}

Expand All @@ -122,7 +104,24 @@ export const onBeforeRequest: HandlerFn<CyHttpMessages.IncomingRequest> = (Cypre

const userReq: CyHttpMessages.IncomingHttpRequest = {
...req,
on: request.on,
on (eventName, handler) {
if (!validEvents.includes(eventName)) {
return $errUtils.throwErrByPath('net_stubbing.request_handling.unknown_event', {
args: {
validEvents,
eventName,
},
})
}

if (!_.isFunction(handler)) {
return $errUtils.throwErrByPath('net_stubbing.request_handling.event_needs_handler')
}

subscribe(eventName, handler)

return userReq
},
continue (responseHandler?) {
if (resolved) {
return $errUtils.throwErrByPath('net_stubbing.request_handling.completion_called_after_resolved', { args: { cmd: 'continue' } })
Expand Down
7 changes: 0 additions & 7 deletions packages/driver/src/cy/net-stubbing/static-response-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import {
StaticResponse,
BackendStaticResponse,
FixtureOpts,
PLAIN_FIELDS,
STRING_MATCHER_FIELDS,
DICT_STRING_MATCHER_FIELDS,
} from '@packages/net-stubbing/lib/types'
import $errUtils from '../../cypress/error_utils'

Expand Down Expand Up @@ -125,7 +122,3 @@ export function getBackendStaticResponse (staticResponse: Readonly<StaticRespons
export function hasStaticResponseKeys (obj: any) {
return !_.isArray(obj) && (_.intersection(_.keys(obj), STATIC_RESPONSE_KEYS).length || _.isEmpty(obj))
}

export function hasRouteMatcherKeys (obj: any) {
return _.intersection(_.keys(obj), _.concat(PLAIN_FIELDS, STRING_MATCHER_FIELDS, DICT_STRING_MATCHER_FIELDS)).length
}
18 changes: 9 additions & 9 deletions packages/net-stubbing/lib/external-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export namespace CyHttpMessages {
*/
statusMessage: string
/**
* Kilobits per second to send 'body'.
* Kilobytes per second to send 'body'.
*/
throttleKbps?: number
/**
Expand Down Expand Up @@ -152,7 +152,7 @@ export namespace CyHttpMessages {
alias?: string
}

export interface IncomingHttpRequest extends IncomingRequest, InterceptionEvents {
export interface IncomingHttpRequest extends IncomingRequest, RequestEvents {
/**
* Destroy the request and respond with a network error.
*/
Expand Down Expand Up @@ -237,31 +237,31 @@ export interface Subscription {
skip?: boolean
}

interface InterceptionEvents {
interface RequestEvents {
/**
* Emitted before `response` and before any `req.continue` handlers.
* Modifications to `res` will be applied to the incoming response.
* If a promise is returned from `cb`, it will be awaited before processing other event handlers.
*/
on(eventName: 'before:response', cb: HttpResponseInterceptor): Interception
on(eventName: 'before:response', cb: HttpResponseInterceptor): this
/**
* Emitted after `before:response` and after any `req.continue` handlers - before the response is sent to the browser.
* Modifications to `res` will be applied to the incoming response.
* If a promise is returned from `cb`, it will be awaited before processing other event handlers.
*/
on(eventName: 'response', cb: HttpResponseInterceptor): Interception
on(eventName: 'response', cb: HttpResponseInterceptor): this
/**
* Emitted once the response to a request has finished sending to the browser.
* Modifications to `res` have no impact.
* If a promise is returned from `cb`, it will be awaited before processing other event handlers.
*/
on(eventName: 'after:response', cb: (res: CyHttpMessages.IncomingResponse) => void | Promise<void>): Interception
on(eventName: 'after:response', cb: (res: CyHttpMessages.IncomingResponse) => void | Promise<void>): this
}

/**
* Request/response cycle.
*/
export interface Interception extends InterceptionEvents {
export interface Interception {
id: string
routeId: string
/* @internal */
Expand Down Expand Up @@ -342,7 +342,7 @@ export interface RouteMatcherOptionsGeneric<S> {
*/
method?: S
/**
* If `true`, this will pass the request on to the next `RouteMatcher` after the request handler completes.
* If `true`, this handler will be called before any non-`middleware` handlers, in the order it was defined.
* Can only be used with a dynamic request handler.
* @default false
*/
Expand Down Expand Up @@ -413,7 +413,7 @@ export interface GenericStaticResponse<Fixture, Body> {
*/
forceNetworkError?: boolean
/**
* Kilobits per second to send 'body'.
* Kilobytes per second to send 'body'.
*/
throttleKbps?: number
/**
Expand Down