UNPKG

msw

Version:

Seamless REST/GraphQL API mocking library for browser and Node.js.

203 lines (202 loc) 8.48 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var GraphQLHandler_exports = {}; __export(GraphQLHandler_exports, { GraphQLHandler: () => GraphQLHandler, isDocumentNode: () => isDocumentNode }); module.exports = __toCommonJS(GraphQLHandler_exports); var import_graphql = require("graphql"); var import_RequestHandler = require("./RequestHandler"); var import_getTimestamp = require("../utils/logging/getTimestamp"); var import_getStatusCodeColor = require("../utils/logging/getStatusCodeColor"); var import_serializeRequest = require("../utils/logging/serializeRequest"); var import_serializeResponse = require("../utils/logging/serializeResponse"); var import_matchRequestUrl = require("../utils/matching/matchRequestUrl"); var import_parseGraphQLRequest = require("../utils/internal/parseGraphQLRequest"); var import_toPublicUrl = require("../utils/request/toPublicUrl"); var import_devUtils = require("../utils/internal/devUtils"); var import_getRequestCookies = require("../utils/request/getRequestCookies"); var import_outvariant = require("outvariant"); function isDocumentNode(value) { if (value == null) { return false; } return typeof value === "object" && "kind" in value && "definitions" in value; } function isDocumentTypeDecoration(value) { return value instanceof String; } class GraphQLHandler extends import_RequestHandler.RequestHandler { endpoint; static parsedRequestCache = /* @__PURE__ */ new WeakMap(); static #parseOperationName(predicate, operationType) { const getOperationName = (node) => { (0, import_outvariant.invariant)( node.operationType === operationType, 'Failed to create a GraphQL handler: provided a DocumentNode with a mismatched operation type (expected "%s" but got "%s").', operationType, node.operationType ); (0, import_outvariant.invariant)( node.operationName, "Failed to create a GraphQL handler: provided a DocumentNode without operation name" ); return node.operationName; }; if (isDocumentNode(predicate)) { return getOperationName((0, import_parseGraphQLRequest.parseDocumentNode)(predicate)); } if (isDocumentTypeDecoration(predicate)) { const documentNode = (0, import_graphql.parse)(predicate.toString()); (0, import_outvariant.invariant)( isDocumentNode(documentNode), "Failed to create a GraphQL handler: given TypedDocumentString (%s) does not produce a valid DocumentNode", predicate ); return getOperationName((0, import_parseGraphQLRequest.parseDocumentNode)(documentNode)); } return predicate; } constructor(operationType, predicate, endpoint, resolver, options) { const operationName = GraphQLHandler.#parseOperationName( predicate, operationType ); const displayOperationName = typeof operationName === "function" ? "[custom predicate]" : operationName; const header = operationType === "all" ? `${operationType} (origin: ${endpoint.toString()})` : `${operationType}${displayOperationName ? ` ${displayOperationName}` : ""} (origin: ${endpoint.toString()})`; super({ info: { header, operationType, operationName: GraphQLHandler.#parseOperationName( predicate, operationType ) }, resolver, options }); this.endpoint = endpoint; } /** * Parses the request body, once per request, cached across all * GraphQL handlers. This is done to avoid multiple parsing of the * request body, which each requires a clone of the request. */ async parseGraphQLRequestOrGetFromCache(request) { if (!GraphQLHandler.parsedRequestCache.has(request)) { GraphQLHandler.parsedRequestCache.set( request, await (0, import_parseGraphQLRequest.parseGraphQLRequest)(request).catch((error) => { console.error(error); return void 0; }) ); } return GraphQLHandler.parsedRequestCache.get(request); } async parse(args) { const match = (0, import_matchRequestUrl.matchRequestUrl)(new URL(args.request.url), this.endpoint); const cookies = (0, import_getRequestCookies.getAllRequestCookies)(args.request); if (!match.matches) { return { match, cookies }; } const parsedResult = await this.parseGraphQLRequestOrGetFromCache( args.request ); if (typeof parsedResult === "undefined") { return { match, cookies }; } return { match, cookies, query: parsedResult.query, operationType: parsedResult.operationType, operationName: parsedResult.operationName, variables: parsedResult.variables }; } async predicate(args) { if (args.parsedResult.operationType === void 0) { return false; } if (!args.parsedResult.operationName && this.info.operationType !== "all") { const publicUrl = (0, import_toPublicUrl.toPublicUrl)(args.request.url); import_devUtils.devUtils.warn(`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/#graphqloperationresolver`); return false; } const hasMatchingOperationType = this.info.operationType === "all" || args.parsedResult.operationType === this.info.operationType; const hasMatchingOperationName = await this.matchOperationName({ request: args.request, parsedResult: args.parsedResult }); return args.parsedResult.match.matches && hasMatchingOperationType && hasMatchingOperationName; } async matchOperationName(args) { if (typeof this.info.operationName === "function") { const customPredicateResult = await this.info.operationName({ request: args.request, ...this.extendResolverArgs({ request: args.request, parsedResult: args.parsedResult }) }); return typeof customPredicateResult === "boolean" ? customPredicateResult : customPredicateResult.matches; } if (this.info.operationName instanceof RegExp) { return this.info.operationName.test(args.parsedResult.operationName || ""); } return args.parsedResult.operationName === this.info.operationName; } extendResolverArgs(args) { return { query: args.parsedResult.query || "", operationType: args.parsedResult.operationType, operationName: args.parsedResult.operationName || "", variables: args.parsedResult.variables || {}, cookies: args.parsedResult.cookies }; } async log(args) { const loggedRequest = await (0, import_serializeRequest.serializeRequest)(args.request); const loggedResponse = await (0, import_serializeResponse.serializeResponse)(args.response); const statusColor = (0, import_getStatusCodeColor.getStatusCodeColor)(loggedResponse.status); const requestInfo = args.parsedResult.operationName ? `${args.parsedResult.operationType} ${args.parsedResult.operationName}` : `anonymous ${args.parsedResult.operationType}`; console.groupCollapsed( import_devUtils.devUtils.formatMessage( `${(0, import_getTimestamp.getTimestamp)()} ${requestInfo} (%c${loggedResponse.status} ${loggedResponse.statusText}%c)` ), `color:${statusColor}`, "color:inherit" ); console.log("Request:", loggedRequest); console.log("Handler:", this); console.log("Response:", loggedResponse); console.groupEnd(); } } //# sourceMappingURL=GraphQLHandler.js.map