diff --git a/src/core/handlers/GraphQLHandler.ts b/src/core/handlers/GraphQLHandler.ts index 4a405a842..77d9fe302 100644 --- a/src/core/handlers/GraphQLHandler.ts +++ b/src/core/handlers/GraphQLHandler.ts @@ -114,37 +114,40 @@ export class GraphQLHandler extends RequestHandler< this.endpoint = endpoint } - async parse(request: Request) { - return parseGraphQLRequest(request).catch((error) => { + async parse(args: { request: Request }) { + return parseGraphQLRequest(args.request).catch((error) => { console.error(error) return undefined }) } - predicate(request: Request, parsedResult: ParsedGraphQLRequest) { - if (!parsedResult) { + predicate(args: { request: Request; parsedResult: ParsedGraphQLRequest }) { + if (!args.parsedResult) { return false } - if (!parsedResult.operationName && this.info.operationType !== 'all') { - const publicUrl = getPublicUrlFromRequest(request) + if (!args.parsedResult.operationName && this.info.operationType !== 'all') { + const publicUrl = getPublicUrlFromRequest(args.request) devUtils.warn(`\ -Failed to intercept a GraphQL request at "${request.method} ${publicUrl}": anonymous GraphQL operations are not supported. +Failed to intercept a GraphQL request at "${args.request.method} ${publicUrl}": anonymous GraphQL operations are not supported. Consider naming this operation or using "graphql.operation()" request handler to intercept GraphQL requests regardless of their operation name/type. Read more: https://mswjs.io/docs/api/graphql/operation`) return false } - const hasMatchingUrl = matchRequestUrl(new URL(request.url), this.endpoint) + const hasMatchingUrl = matchRequestUrl( + new URL(args.request.url), + this.endpoint, + ) const hasMatchingOperationType = this.info.operationType === 'all' || - parsedResult.operationType === this.info.operationType + args.parsedResult.operationType === this.info.operationType const hasMatchingOperationName = this.info.operationName instanceof RegExp - ? this.info.operationName.test(parsedResult.operationName || '') - : parsedResult.operationName === this.info.operationName + ? this.info.operationName.test(args.parsedResult.operationName || '') + : args.parsedResult.operationName === this.info.operationName return ( hasMatchingUrl.matches && @@ -153,28 +156,28 @@ Consider naming this operation or using "graphql.operation()" request handler to ) } - protected extendInfo( - _request: Request, - parsedResult: ParsedGraphQLRequest, - ) { + protected extendInfo(args: { + request: Request + parsedResult: ParsedGraphQLRequest + }) { return { - query: parsedResult?.query || '', - operationName: parsedResult?.operationName || '', - variables: parsedResult?.variables || {}, + query: args.parsedResult?.query || '', + operationName: args.parsedResult?.operationName || '', + variables: args.parsedResult?.variables || {}, } } - async log( - request: Request, - response: Response, - parsedRequest: ParsedGraphQLRequest, - ) { - const loggedRequest = await serializeRequest(request) - const loggedResponse = await serializeResponse(response) + async log(args: { + request: Request + response: Response + parsedResult: ParsedGraphQLRequest + }) { + const loggedRequest = await serializeRequest(args.request) + const loggedResponse = await serializeResponse(args.response) const statusColor = getStatusCodeColor(loggedResponse.status) - const requestInfo = parsedRequest?.operationName - ? `${parsedRequest?.operationType} ${parsedRequest?.operationName}` - : `anonymous ${parsedRequest?.operationType}` + const requestInfo = args.parsedResult?.operationName + ? `${args.parsedResult?.operationType} ${args.parsedResult?.operationName}` + : `anonymous ${args.parsedResult?.operationType}` console.groupCollapsed( devUtils.formatMessage('%s %s (%c%s%c)'), diff --git a/src/core/handlers/HttpHandler.ts b/src/core/handlers/HttpHandler.ts index cfb3700f9..07bde4b90 100644 --- a/src/core/handlers/HttpHandler.ts +++ b/src/core/handlers/HttpHandler.ts @@ -106,14 +106,17 @@ export class HttpHandler extends RequestHandler< ) } - async parse(request: Request, resolutionContext?: ResponseResolutionContext) { - const url = new URL(request.url) + async parse(args: { + request: Request + resolutionContext?: ResponseResolutionContext + }) { + const url = new URL(args.request.url) const match = matchRequestUrl( url, this.info.path, - resolutionContext?.baseUrl, + args.resolutionContext?.baseUrl, ) - const cookies = getAllRequestCookies(request) + const cookies = getAllRequestCookies(args.request) return { match, @@ -121,9 +124,9 @@ export class HttpHandler extends RequestHandler< } } - predicate(request: Request, parsedResult: HttpRequestParsedResult) { - const hasMatchingMethod = this.matchMethod(request.method) - const hasMatchingUrl = parsedResult.match.matches + predicate(args: { request: Request; parsedResult: HttpRequestParsedResult }) { + const hasMatchingMethod = this.matchMethod(args.request.method) + const hasMatchingUrl = args.parsedResult.match.matches return hasMatchingMethod && hasMatchingUrl } @@ -133,26 +136,26 @@ export class HttpHandler extends RequestHandler< : isStringEqual(this.info.method, actualMethod) } - protected extendInfo( - _request: Request, - parsedResult: HttpRequestParsedResult, - ) { + protected extendInfo(args: { + request: Request + parsedResult: HttpRequestParsedResult + }) { return { - params: parsedResult.match?.params || {}, - cookies: parsedResult.cookies, + params: args.parsedResult.match?.params || {}, + cookies: args.parsedResult.cookies, } } - async log(request: Request, response: Response) { - const publicUrl = getPublicUrlFromRequest(request) - const loggedRequest = await serializeRequest(request) - const loggedResponse = await serializeResponse(response) + async log(args: { request: Request; response: Response }) { + const publicUrl = getPublicUrlFromRequest(args.request) + const loggedRequest = await serializeRequest(args.request) + const loggedResponse = await serializeResponse(args.response) const statusColor = getStatusCodeColor(loggedResponse.status) console.groupCollapsed( devUtils.formatMessage('%s %s %s (%c%s%c)'), getTimestamp(), - request.method, + args.request.method, publicUrl, `color:${statusColor}`, `${loggedResponse.status} ${loggedResponse.statusText}`, diff --git a/src/core/handlers/RequestHandler.ts b/src/core/handlers/RequestHandler.ts index b2216e631..e6a705a0b 100644 --- a/src/core/handlers/RequestHandler.ts +++ b/src/core/handlers/RequestHandler.ts @@ -122,50 +122,55 @@ export abstract class RequestHandler< /** * Determine if the intercepted request should be mocked. */ - abstract predicate( - request: Request, - parsedResult: ParsedResult, - resolutionContext?: ResponseResolutionContext, - ): boolean + abstract predicate(args: { + request: Request + parsedResult: ParsedResult + resolutionContext?: ResponseResolutionContext + }): boolean /** * Print out the successfully handled request. */ - abstract log( - request: Request, - response: Response, - parsedResult: ParsedResult, - ): void + abstract log(args: { + request: Request + response: Response + parsedResult: ParsedResult + }): void /** * Parse the intercepted request to extract additional information from it. * Parsed result is then exposed to other methods of this request handler. */ - async parse( - _request: Request, - _resolutionContext?: ResponseResolutionContext, - ): Promise { + async parse(_args: { + request: Request + resolutionContext?: ResponseResolutionContext + }): Promise { return {} as ParsedResult } /** * Test if this handler matches the given request. */ - public async test( - request: Request, - resolutionContext?: ResponseResolutionContext, - ): Promise { - return this.predicate( - request, - await this.parse(request.clone(), resolutionContext), - resolutionContext, - ) + public async test(args: { + request: Request + resolutionContext?: ResponseResolutionContext + }): Promise { + const parsedResult = await this.parse({ + request: args.request.clone(), + resolutionContext: args.resolutionContext, + }) + + return this.predicate({ + request: args.request, + parsedResult, + resolutionContext: args.resolutionContext, + }) } - protected extendInfo( - _request: Request, - _parsedResult: ParsedResult, - ): ResolverExtras { + protected extendInfo(_args: { + request: Request + parsedResult: ParsedResult + }): ResolverExtras { return {} as ResolverExtras } @@ -173,30 +178,30 @@ export abstract class RequestHandler< * Execute this request handler and produce a mocked response * using the given resolver function. */ - public async run( - request: StrictRequest, - resolutionContext?: ResponseResolutionContext, - ): Promise | null> { + public async run(args: { + request: StrictRequest + resolutionContext?: ResponseResolutionContext + }): Promise | null> { if (this.isUsed && this.options?.once) { return null } - const mainRequestRef = request.clone() + const mainRequestRef = args.request.clone() // Immediately mark the handler as used. // Can't await the resolver to be resolved because it's potentially // asynchronous, and there may be multiple requests hitting this handler. this.isUsed = true - const parsedResult = await this.parse( - mainRequestRef.clone(), - resolutionContext, - ) - const shouldInterceptRequest = this.predicate( - mainRequestRef.clone(), + const parsedResult = await this.parse({ + request: mainRequestRef.clone(), + resolutionContext: args.resolutionContext, + }) + const shouldInterceptRequest = this.predicate({ + request: mainRequestRef.clone(), parsedResult, - resolutionContext, - ) + resolutionContext: args.resolutionContext, + }) if (!shouldInterceptRequest) { return null @@ -206,19 +211,22 @@ export abstract class RequestHandler< // since it can be both an async function and a generator. const executeResolver = this.wrapResolver(this.resolver) - const resolverExtras = this.extendInfo(request, parsedResult) + const resolverExtras = this.extendInfo({ + request: args.request, + parsedResult, + }) const mockedResponse = (await executeResolver({ ...resolverExtras, - request, + request: args.request, })) as Response - const executionResult = this.createExecutionResult( + const executionResult = this.createExecutionResult({ // Pass the cloned request to the result so that logging // and other consumers could read its body once more. - mainRequestRef, + request: mainRequestRef, + response: mockedResponse, parsedResult, - mockedResponse, - ) + }) return executionResult } @@ -272,16 +280,16 @@ export abstract class RequestHandler< } } - private createExecutionResult( - request: Request, - parsedResult: ParsedResult, - response?: Response, - ): RequestHandlerExecutionResult { + private createExecutionResult(args: { + request: Request + parsedResult: ParsedResult + response?: Response + }): RequestHandlerExecutionResult { return { handler: this, - parsedResult, - request, - response, + request: args.request, + response: args.response, + parsedResult: args.parsedResult, } } } diff --git a/src/core/utils/getResponse.ts b/src/core/utils/getResponse.ts index 2644ebf28..0d53e5942 100644 --- a/src/core/utils/getResponse.ts +++ b/src/core/utils/getResponse.ts @@ -25,7 +25,7 @@ export const getResponse = async >( let result: RequestHandlerExecutionResult | null = null for (const handler of handlers) { - result = await handler.run(request, resolutionContext) + result = await handler.run({ request, resolutionContext }) // If the handler produces some result for this request, // it automatically becomes matching.