msw 2.1.3 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/index.js +1757 -27
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +1751 -23
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/sharedOptions.d.mts +0 -2
- package/lib/core/sharedOptions.d.ts +0 -2
- package/lib/core/utils/handleRequest.js +1 -1
- package/lib/core/utils/handleRequest.js.map +1 -1
- package/lib/core/utils/handleRequest.mjs +1 -1
- package/lib/core/utils/handleRequest.mjs.map +1 -1
- package/lib/core/utils/request/onUnhandledRequest.d.mts +1 -4
- package/lib/core/utils/request/onUnhandledRequest.d.ts +1 -4
- package/lib/core/utils/request/onUnhandledRequest.js +9 -114
- package/lib/core/utils/request/onUnhandledRequest.js.map +1 -1
- package/lib/core/utils/request/onUnhandledRequest.mjs +9 -106
- package/lib/core/utils/request/onUnhandledRequest.mjs.map +1 -1
- package/lib/iife/index.js +10 -213
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/package.json +1 -4
- package/src/core/utils/handleRequest.ts +1 -1
- package/src/core/utils/request/onUnhandledRequest.test.ts +5 -101
- package/src/core/utils/request/onUnhandledRequest.ts +3 -184
|
@@ -26,7 +26,7 @@ async function handleRequest(request, requestId, handlers, options, emitter, han
|
|
|
26
26
|
throw lookupResult.error;
|
|
27
27
|
}
|
|
28
28
|
if (!lookupResult.data) {
|
|
29
|
-
await onUnhandledRequest(request,
|
|
29
|
+
await onUnhandledRequest(request, options.onUnhandledRequest);
|
|
30
30
|
emitter.emit("request:unhandled", { request, requestId });
|
|
31
31
|
emitter.emit("request:end", { request, requestId });
|
|
32
32
|
handleRequestOptions?.onPassthroughResponse?.(request);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/utils/handleRequest.ts"],"sourcesContent":["import { until } from '@open-draft/until'\nimport { Emitter } from 'strict-event-emitter'\nimport { RequestHandler } from '../handlers/RequestHandler'\nimport { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'\nimport { RequiredDeep } from '../typeUtils'\nimport { HandlersExecutionResult, executeHandlers } from './executeHandlers'\nimport { onUnhandledRequest } from './request/onUnhandledRequest'\nimport { readResponseCookies } from './request/readResponseCookies'\n\nexport interface HandleRequestOptions {\n /**\n * `resolutionContext` is not part of the general public api\n * but is exposed to aid in creating extensions like\n * `@mswjs/http-middleware`.\n */\n resolutionContext?: {\n /**\n * A base url to use when resolving relative urls.\n * @note This is primarily used by the `@mswjs/http-middleware`\n * to resolve relative urls in the context of the running server\n */\n baseUrl?: string\n }\n\n /**\n * Transforms a `MockedResponse` instance returned from a handler\n * to a response instance supported by the lower tooling (i.e. interceptors).\n */\n transformResponse?(response: Response): Response\n\n /**\n * Invoked whenever a request is performed as-is.\n */\n onPassthroughResponse?(request: Request): void\n\n /**\n * Invoked when the mocked response is ready to be sent.\n */\n onMockedResponse?(\n response: Response,\n handler: RequiredDeep<HandlersExecutionResult>,\n ): void\n}\n\nexport async function handleRequest(\n request: Request,\n requestId: string,\n handlers: Array<RequestHandler>,\n options: RequiredDeep<SharedOptions>,\n emitter: Emitter<LifeCycleEventsMap>,\n handleRequestOptions?: HandleRequestOptions,\n): Promise<Response | undefined> {\n emitter.emit('request:start', { request, requestId })\n\n // Perform bypassed requests (i.e. issued via \"ctx.fetch\") as-is.\n if (request.headers.get('x-msw-intention') === 'bypass') {\n emitter.emit('request:end', { request, requestId })\n handleRequestOptions?.onPassthroughResponse?.(request)\n return\n }\n\n // Resolve a mocked response from the list of request handlers.\n const lookupResult = await until(() => {\n return executeHandlers({\n request,\n requestId,\n handlers,\n resolutionContext: handleRequestOptions?.resolutionContext,\n })\n })\n\n if (lookupResult.error) {\n // Allow developers to react to unhandled exceptions in request handlers.\n emitter.emit('unhandledException', {\n error: lookupResult.error,\n request,\n requestId,\n })\n throw lookupResult.error\n }\n\n // If the handler lookup returned nothing, no request handler was found\n // matching this request. Report the request as unhandled.\n if (!lookupResult.data) {\n await onUnhandledRequest(request,
|
|
1
|
+
{"version":3,"sources":["../../../src/core/utils/handleRequest.ts"],"sourcesContent":["import { until } from '@open-draft/until'\nimport { Emitter } from 'strict-event-emitter'\nimport { RequestHandler } from '../handlers/RequestHandler'\nimport { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'\nimport { RequiredDeep } from '../typeUtils'\nimport { HandlersExecutionResult, executeHandlers } from './executeHandlers'\nimport { onUnhandledRequest } from './request/onUnhandledRequest'\nimport { readResponseCookies } from './request/readResponseCookies'\n\nexport interface HandleRequestOptions {\n /**\n * `resolutionContext` is not part of the general public api\n * but is exposed to aid in creating extensions like\n * `@mswjs/http-middleware`.\n */\n resolutionContext?: {\n /**\n * A base url to use when resolving relative urls.\n * @note This is primarily used by the `@mswjs/http-middleware`\n * to resolve relative urls in the context of the running server\n */\n baseUrl?: string\n }\n\n /**\n * Transforms a `MockedResponse` instance returned from a handler\n * to a response instance supported by the lower tooling (i.e. interceptors).\n */\n transformResponse?(response: Response): Response\n\n /**\n * Invoked whenever a request is performed as-is.\n */\n onPassthroughResponse?(request: Request): void\n\n /**\n * Invoked when the mocked response is ready to be sent.\n */\n onMockedResponse?(\n response: Response,\n handler: RequiredDeep<HandlersExecutionResult>,\n ): void\n}\n\nexport async function handleRequest(\n request: Request,\n requestId: string,\n handlers: Array<RequestHandler>,\n options: RequiredDeep<SharedOptions>,\n emitter: Emitter<LifeCycleEventsMap>,\n handleRequestOptions?: HandleRequestOptions,\n): Promise<Response | undefined> {\n emitter.emit('request:start', { request, requestId })\n\n // Perform bypassed requests (i.e. issued via \"ctx.fetch\") as-is.\n if (request.headers.get('x-msw-intention') === 'bypass') {\n emitter.emit('request:end', { request, requestId })\n handleRequestOptions?.onPassthroughResponse?.(request)\n return\n }\n\n // Resolve a mocked response from the list of request handlers.\n const lookupResult = await until(() => {\n return executeHandlers({\n request,\n requestId,\n handlers,\n resolutionContext: handleRequestOptions?.resolutionContext,\n })\n })\n\n if (lookupResult.error) {\n // Allow developers to react to unhandled exceptions in request handlers.\n emitter.emit('unhandledException', {\n error: lookupResult.error,\n request,\n requestId,\n })\n throw lookupResult.error\n }\n\n // If the handler lookup returned nothing, no request handler was found\n // matching this request. Report the request as unhandled.\n if (!lookupResult.data) {\n await onUnhandledRequest(request, options.onUnhandledRequest)\n emitter.emit('request:unhandled', { request, requestId })\n emitter.emit('request:end', { request, requestId })\n handleRequestOptions?.onPassthroughResponse?.(request)\n return\n }\n\n const { response } = lookupResult.data\n\n // When the handled request returned no mocked response, warn the developer,\n // as it may be an oversight on their part. Perform the request as-is.\n if (!response) {\n emitter.emit('request:end', { request, requestId })\n handleRequestOptions?.onPassthroughResponse?.(request)\n return\n }\n\n // Perform the request as-is when the developer explicitly returned \"req.passthrough()\".\n // This produces no warning as the request was handled.\n if (\n response.status === 302 &&\n response.headers.get('x-msw-intention') === 'passthrough'\n ) {\n emitter.emit('request:end', { request, requestId })\n handleRequestOptions?.onPassthroughResponse?.(request)\n return\n }\n\n // Store all the received response cookies in the virtual cookie store.\n readResponseCookies(request, response)\n\n emitter.emit('request:match', { request, requestId })\n\n const requiredLookupResult =\n lookupResult.data as RequiredDeep<HandlersExecutionResult>\n\n const transformedResponse =\n handleRequestOptions?.transformResponse?.(response) ||\n (response as any as Response)\n\n handleRequestOptions?.onMockedResponse?.(\n transformedResponse,\n requiredLookupResult,\n )\n\n emitter.emit('request:end', { request, requestId })\n\n return transformedResponse\n}\n"],"mappings":"AAAA,SAAS,aAAa;AAKtB,SAAkC,uBAAuB;AACzD,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AAqCpC,eAAsB,cACpB,SACA,WACA,UACA,SACA,SACA,sBAC+B;AAC/B,UAAQ,KAAK,iBAAiB,EAAE,SAAS,UAAU,CAAC;AAGpD,MAAI,QAAQ,QAAQ,IAAI,iBAAiB,MAAM,UAAU;AACvD,YAAQ,KAAK,eAAe,EAAE,SAAS,UAAU,CAAC;AAClD,0BAAsB,wBAAwB,OAAO;AACrD;AAAA,EACF;AAGA,QAAM,eAAe,MAAM,MAAM,MAAM;AACrC,WAAO,gBAAgB;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,sBAAsB;AAAA,IAC3C,CAAC;AAAA,EACH,CAAC;AAED,MAAI,aAAa,OAAO;AAEtB,YAAQ,KAAK,sBAAsB;AAAA,MACjC,OAAO,aAAa;AAAA,MACpB;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,aAAa;AAAA,EACrB;AAIA,MAAI,CAAC,aAAa,MAAM;AACtB,UAAM,mBAAmB,SAAS,QAAQ,kBAAkB;AAC5D,YAAQ,KAAK,qBAAqB,EAAE,SAAS,UAAU,CAAC;AACxD,YAAQ,KAAK,eAAe,EAAE,SAAS,UAAU,CAAC;AAClD,0BAAsB,wBAAwB,OAAO;AACrD;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,IAAI,aAAa;AAIlC,MAAI,CAAC,UAAU;AACb,YAAQ,KAAK,eAAe,EAAE,SAAS,UAAU,CAAC;AAClD,0BAAsB,wBAAwB,OAAO;AACrD;AAAA,EACF;AAIA,MACE,SAAS,WAAW,OACpB,SAAS,QAAQ,IAAI,iBAAiB,MAAM,eAC5C;AACA,YAAQ,KAAK,eAAe,EAAE,SAAS,UAAU,CAAC;AAClD,0BAAsB,wBAAwB,OAAO;AACrD;AAAA,EACF;AAGA,sBAAoB,SAAS,QAAQ;AAErC,UAAQ,KAAK,iBAAiB,EAAE,SAAS,UAAU,CAAC;AAEpD,QAAM,uBACJ,aAAa;AAEf,QAAM,sBACJ,sBAAsB,oBAAoB,QAAQ,KACjD;AAEH,wBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,EACF;AAEA,UAAQ,KAAK,eAAe,EAAE,SAAS,UAAU,CAAC;AAElD,SAAO;AACT;","names":[]}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { R as RequestHandler } from '../../RequestHandler-MAVTMsma.mjs';
|
|
2
|
-
import '../../typeUtils.mjs';
|
|
3
|
-
|
|
4
1
|
interface UnhandledRequestPrint {
|
|
5
2
|
warning(): void;
|
|
6
3
|
error(): void;
|
|
7
4
|
}
|
|
8
5
|
type UnhandledRequestCallback = (request: Request, print: UnhandledRequestPrint) => void;
|
|
9
6
|
type UnhandledRequestStrategy = 'bypass' | 'warn' | 'error' | UnhandledRequestCallback;
|
|
10
|
-
declare function onUnhandledRequest(request: Request,
|
|
7
|
+
declare function onUnhandledRequest(request: Request, strategy?: UnhandledRequestStrategy): Promise<void>;
|
|
11
8
|
|
|
12
9
|
export { type UnhandledRequestCallback, type UnhandledRequestPrint, type UnhandledRequestStrategy, onUnhandledRequest };
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { R as RequestHandler } from '../../RequestHandler-CwjkprZE.js';
|
|
2
|
-
import '../../typeUtils.js';
|
|
3
|
-
|
|
4
1
|
interface UnhandledRequestPrint {
|
|
5
2
|
warning(): void;
|
|
6
3
|
error(): void;
|
|
7
4
|
}
|
|
8
5
|
type UnhandledRequestCallback = (request: Request, print: UnhandledRequestPrint) => void;
|
|
9
6
|
type UnhandledRequestStrategy = 'bypass' | 'warn' | 'error' | UnhandledRequestCallback;
|
|
10
|
-
declare function onUnhandledRequest(request: Request,
|
|
7
|
+
declare function onUnhandledRequest(request: Request, strategy?: UnhandledRequestStrategy): Promise<void>;
|
|
11
8
|
|
|
12
9
|
export { type UnhandledRequestCallback, type UnhandledRequestPrint, type UnhandledRequestStrategy, onUnhandledRequest };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,129 +15,26 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
var onUnhandledRequest_exports = {};
|
|
30
20
|
__export(onUnhandledRequest_exports, {
|
|
31
21
|
onUnhandledRequest: () => onUnhandledRequest
|
|
32
22
|
});
|
|
33
23
|
module.exports = __toCommonJS(onUnhandledRequest_exports);
|
|
34
|
-
var import_js_levenshtein = __toESM(require("@bundled-es-modules/js-levenshtein"));
|
|
35
|
-
var import_HttpHandler = require("../../handlers/HttpHandler.js");
|
|
36
|
-
var import_GraphQLHandler = require("../../handlers/GraphQLHandler.js");
|
|
37
|
-
var import_parseGraphQLRequest = require("../internal/parseGraphQLRequest.js");
|
|
38
24
|
var import_getPublicUrlFromRequest = require("./getPublicUrlFromRequest.js");
|
|
39
|
-
var import_isStringEqual = require("../internal/isStringEqual.js");
|
|
40
25
|
var import_devUtils = require("../internal/devUtils.js");
|
|
41
|
-
|
|
42
|
-
const MAX_MATCH_SCORE = 3;
|
|
43
|
-
const MAX_SUGGESTION_COUNT = 4;
|
|
44
|
-
const TYPE_MATCH_DELTA = 0.5;
|
|
45
|
-
function groupHandlersByType(handlers) {
|
|
46
|
-
return handlers.reduce(
|
|
47
|
-
(groups, handler) => {
|
|
48
|
-
if (handler instanceof import_HttpHandler.HttpHandler) {
|
|
49
|
-
groups.http.push(handler);
|
|
50
|
-
}
|
|
51
|
-
if (handler instanceof import_GraphQLHandler.GraphQLHandler) {
|
|
52
|
-
groups.graphql.push(handler);
|
|
53
|
-
}
|
|
54
|
-
return groups;
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
http: [],
|
|
58
|
-
graphql: []
|
|
59
|
-
}
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
function getHttpHandlerScore() {
|
|
63
|
-
return (request, handler) => {
|
|
64
|
-
const { path, method } = handler.info;
|
|
65
|
-
if (path instanceof RegExp || method instanceof RegExp) {
|
|
66
|
-
return Infinity;
|
|
67
|
-
}
|
|
68
|
-
const hasSameMethod = (0, import_isStringEqual.isStringEqual)(request.method, method);
|
|
69
|
-
const methodScoreDelta = hasSameMethod ? TYPE_MATCH_DELTA : 0;
|
|
70
|
-
const requestPublicUrl = (0, import_getPublicUrlFromRequest.getPublicUrlFromRequest)(request);
|
|
71
|
-
const score = getStringMatchScore(requestPublicUrl, path);
|
|
72
|
-
return score - methodScoreDelta;
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function getGraphQLHandlerScore(parsedQuery) {
|
|
76
|
-
return (_, handler) => {
|
|
77
|
-
if (typeof parsedQuery.operationName === "undefined") {
|
|
78
|
-
return Infinity;
|
|
79
|
-
}
|
|
80
|
-
const { operationType, operationName } = handler.info;
|
|
81
|
-
if (typeof operationName !== "string") {
|
|
82
|
-
return Infinity;
|
|
83
|
-
}
|
|
84
|
-
const hasSameOperationType = parsedQuery.operationType === operationType;
|
|
85
|
-
const operationTypeScoreDelta = hasSameOperationType ? TYPE_MATCH_DELTA : 0;
|
|
86
|
-
const score = getStringMatchScore(parsedQuery.operationName, operationName);
|
|
87
|
-
return score - operationTypeScoreDelta;
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
function getSuggestedHandler(request, handlers, getScore) {
|
|
91
|
-
const suggestedHandlers = handlers.reduce((suggestions, handler) => {
|
|
92
|
-
const score = getScore(request, handler);
|
|
93
|
-
return suggestions.concat([[score, handler]]);
|
|
94
|
-
}, []).sort(([leftScore], [rightScore]) => leftScore - rightScore).filter(([score]) => score <= MAX_MATCH_SCORE).slice(0, MAX_SUGGESTION_COUNT).map(([, handler]) => handler);
|
|
95
|
-
return suggestedHandlers;
|
|
96
|
-
}
|
|
97
|
-
function getSuggestedHandlersMessage(handlers) {
|
|
98
|
-
if (handlers.length > 1) {
|
|
99
|
-
return `Did you mean to request one of the following resources instead?
|
|
100
|
-
|
|
101
|
-
${handlers.map((handler) => ` \u2022 ${handler.info.header}`).join("\n")}`;
|
|
102
|
-
}
|
|
103
|
-
return `Did you mean to request "${handlers[0].info.header}" instead?`;
|
|
104
|
-
}
|
|
105
|
-
async function onUnhandledRequest(request, handlers, strategy = "warn") {
|
|
106
|
-
const parsedGraphQLQuery = await (0, import_parseGraphQLRequest.parseGraphQLRequest)(request).catch(
|
|
107
|
-
() => null
|
|
108
|
-
);
|
|
26
|
+
async function onUnhandledRequest(request, strategy = "warn") {
|
|
109
27
|
const publicUrl = (0, import_getPublicUrlFromRequest.getPublicUrlFromRequest)(request);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
parsedGraphQLQuery ? getGraphQLHandlerScore(parsedGraphQLQuery) : getHttpHandlerScore()
|
|
117
|
-
);
|
|
118
|
-
return suggestedHandlers.length > 0 ? getSuggestedHandlersMessage(suggestedHandlers) : "";
|
|
119
|
-
}
|
|
120
|
-
function getGraphQLRequestHeader(parsedGraphQLRequest) {
|
|
121
|
-
if (!parsedGraphQLRequest?.operationName) {
|
|
122
|
-
return `anonymous ${parsedGraphQLRequest?.operationType} (${request.method} ${publicUrl})`;
|
|
123
|
-
}
|
|
124
|
-
return `${parsedGraphQLRequest.operationType} ${parsedGraphQLRequest.operationName} (${request.method} ${publicUrl})`;
|
|
125
|
-
}
|
|
126
|
-
function generateUnhandledRequestMessage() {
|
|
127
|
-
const requestHeader = parsedGraphQLQuery ? getGraphQLRequestHeader(parsedGraphQLQuery) : `${request.method} ${publicUrl}`;
|
|
128
|
-
const handlerSuggestion = generateHandlerSuggestion();
|
|
129
|
-
const messageTemplate = [
|
|
130
|
-
`intercepted a request without a matching request handler:`,
|
|
131
|
-
` \u2022 ${requestHeader}`,
|
|
132
|
-
handlerSuggestion,
|
|
133
|
-
`If you still wish to intercept this unhandled request, please create a request handler for it.
|
|
134
|
-
Read more: https://mswjs.io/docs/getting-started/mocks`
|
|
135
|
-
].filter(Boolean);
|
|
136
|
-
return messageTemplate.join("\n\n");
|
|
137
|
-
}
|
|
28
|
+
const unhandledRequestMessage = `intercepted a request without a matching request handler:
|
|
29
|
+
|
|
30
|
+
\u2022 ${request.method} ${publicUrl}
|
|
31
|
+
|
|
32
|
+
If you still wish to intercept this unhandled request, please create a request handler for it.
|
|
33
|
+
Read more: https://mswjs.io/docs/getting-started/mocks`;
|
|
138
34
|
function applyStrategy(strategy2) {
|
|
139
|
-
const message = generateUnhandledRequestMessage();
|
|
140
35
|
switch (strategy2) {
|
|
141
36
|
case "error": {
|
|
142
|
-
import_devUtils.devUtils.error("Error: %s",
|
|
37
|
+
import_devUtils.devUtils.error("Error: %s", unhandledRequestMessage);
|
|
143
38
|
throw new Error(
|
|
144
39
|
import_devUtils.devUtils.formatMessage(
|
|
145
40
|
'Cannot bypass a request when using the "error" strategy for the "onUnhandledRequest" option.'
|
|
@@ -147,7 +42,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks`
|
|
|
147
42
|
);
|
|
148
43
|
}
|
|
149
44
|
case "warn": {
|
|
150
|
-
import_devUtils.devUtils.warn("Warning: %s",
|
|
45
|
+
import_devUtils.devUtils.warn("Warning: %s", unhandledRequestMessage);
|
|
151
46
|
break;
|
|
152
47
|
}
|
|
153
48
|
case "bypass":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import jsLevenshtein from '@bundled-es-modules/js-levenshtein'\nimport { RequestHandler } from '../../handlers/RequestHandler'\nimport { HttpHandler } from '../../handlers/HttpHandler'\nimport { GraphQLHandler } from '../../handlers/GraphQLHandler'\nimport {\n ParsedGraphQLQuery,\n ParsedGraphQLRequest,\n parseGraphQLRequest,\n} from '../internal/parseGraphQLRequest'\nimport { getPublicUrlFromRequest } from './getPublicUrlFromRequest'\nimport { isStringEqual } from '../internal/isStringEqual'\nimport { devUtils } from '../internal/devUtils'\n\nconst getStringMatchScore = jsLevenshtein\n\nconst MAX_MATCH_SCORE = 3\nconst MAX_SUGGESTION_COUNT = 4\nconst TYPE_MATCH_DELTA = 0.5\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\ninterface RequestHandlerGroups {\n http: Array<HttpHandler>\n graphql: Array<GraphQLHandler>\n}\n\nfunction groupHandlersByType(\n handlers: Array<RequestHandler>,\n): RequestHandlerGroups {\n return handlers.reduce<RequestHandlerGroups>(\n (groups, handler) => {\n if (handler instanceof HttpHandler) {\n groups.http.push(handler)\n }\n\n if (handler instanceof GraphQLHandler) {\n groups.graphql.push(handler)\n }\n\n return groups\n },\n {\n http: [],\n graphql: [],\n },\n )\n}\n\ntype RequestHandlerSuggestion = [number, RequestHandler]\n\ntype ScoreGetterFn<RequestHandlerType extends RequestHandler> = (\n request: Request,\n handler: RequestHandlerType,\n) => number\n\nfunction getHttpHandlerScore(): ScoreGetterFn<HttpHandler> {\n return (request, handler) => {\n const { path, method } = handler.info\n\n if (path instanceof RegExp || method instanceof RegExp) {\n return Infinity\n }\n\n const hasSameMethod = isStringEqual(request.method, method)\n\n // Always treat a handler with the same method as a more similar one.\n const methodScoreDelta = hasSameMethod ? TYPE_MATCH_DELTA : 0\n const requestPublicUrl = getPublicUrlFromRequest(request)\n const score = getStringMatchScore(requestPublicUrl, path)\n\n return score - methodScoreDelta\n }\n}\n\nfunction getGraphQLHandlerScore(\n parsedQuery: ParsedGraphQLQuery,\n): ScoreGetterFn<GraphQLHandler> {\n return (_, handler) => {\n if (typeof parsedQuery.operationName === 'undefined') {\n return Infinity\n }\n\n const { operationType, operationName } = handler.info\n\n if (typeof operationName !== 'string') {\n return Infinity\n }\n\n const hasSameOperationType = parsedQuery.operationType === operationType\n // Always treat a handler with the same operation type as a more similar one.\n const operationTypeScoreDelta = hasSameOperationType ? TYPE_MATCH_DELTA : 0\n const score = getStringMatchScore(parsedQuery.operationName, operationName)\n\n return score - operationTypeScoreDelta\n }\n}\n\nfunction getSuggestedHandler(\n request: Request,\n handlers: Array<HttpHandler> | Array<GraphQLHandler>,\n getScore: ScoreGetterFn<HttpHandler> | ScoreGetterFn<GraphQLHandler>,\n): Array<RequestHandler> {\n const suggestedHandlers = (handlers as Array<RequestHandler>)\n .reduce<Array<RequestHandlerSuggestion>>((suggestions, handler) => {\n const score = getScore(request, handler as any)\n return suggestions.concat([[score, handler]])\n }, [])\n .sort(([leftScore], [rightScore]) => leftScore - rightScore)\n .filter(([score]) => score <= MAX_MATCH_SCORE)\n .slice(0, MAX_SUGGESTION_COUNT)\n .map(([, handler]) => handler)\n\n return suggestedHandlers\n}\n\nfunction getSuggestedHandlersMessage(handlers: RequestHandler[]) {\n if (handlers.length > 1) {\n return `\\\nDid you mean to request one of the following resources instead?\n\n${handlers.map((handler) => ` • ${handler.info.header}`).join('\\n')}`\n }\n\n return `Did you mean to request \"${handlers[0].info.header}\" instead?`\n}\n\nexport async function onUnhandledRequest(\n request: Request,\n handlers: Array<RequestHandler>,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const parsedGraphQLQuery = await parseGraphQLRequest(request).catch(\n () => null,\n )\n const publicUrl = getPublicUrlFromRequest(request)\n\n function generateHandlerSuggestion(): string {\n /**\n * @note Ignore exceptions during GraphQL request parsing because at this point\n * we cannot assume the unhandled request is a valid GraphQL request.\n * If the GraphQL parsing fails, just don't treat it as a GraphQL request.\n */\n const handlerGroups = groupHandlersByType(handlers)\n const relevantHandlers = parsedGraphQLQuery\n ? handlerGroups.graphql\n : handlerGroups.http\n\n const suggestedHandlers = getSuggestedHandler(\n request,\n relevantHandlers,\n parsedGraphQLQuery\n ? getGraphQLHandlerScore(parsedGraphQLQuery)\n : getHttpHandlerScore(),\n )\n\n return suggestedHandlers.length > 0\n ? getSuggestedHandlersMessage(suggestedHandlers)\n : ''\n }\n\n function getGraphQLRequestHeader(\n parsedGraphQLRequest: ParsedGraphQLRequest<any>,\n ): string {\n if (!parsedGraphQLRequest?.operationName) {\n return `anonymous ${parsedGraphQLRequest?.operationType} (${request.method} ${publicUrl})`\n }\n\n return `${parsedGraphQLRequest.operationType} ${parsedGraphQLRequest.operationName} (${request.method} ${publicUrl})`\n }\n\n function generateUnhandledRequestMessage(): string {\n const requestHeader = parsedGraphQLQuery\n ? getGraphQLRequestHeader(parsedGraphQLQuery)\n : `${request.method} ${publicUrl}`\n const handlerSuggestion = generateHandlerSuggestion()\n\n const messageTemplate = [\n `intercepted a request without a matching request handler:`,\n ` \\u2022 ${requestHeader}`,\n handlerSuggestion,\n `\\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\nRead more: https://mswjs.io/docs/getting-started/mocks\\\n`,\n ].filter(Boolean)\n return messageTemplate.join('\\n\\n')\n }\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n // Generate handler suggestions only when applying the strategy.\n // This saves bandwidth for scenarios when developers opt-out\n // from the default unhandled request handling strategy.\n const message = generateUnhandledRequestMessage()\n\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', message)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new Error(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', message)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new Error(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":"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","names":["jsLevenshtein","strategy"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import { getPublicUrlFromRequest } from './getPublicUrlFromRequest'\nimport { devUtils } from '../internal/devUtils'\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\nexport async function onUnhandledRequest(\n request: Request,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const publicUrl = getPublicUrlFromRequest(request)\n const unhandledRequestMessage = `intercepted a request without a matching request handler:\\n\\n \\u2022 ${request.method} ${publicUrl}\\n\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/getting-started/mocks`\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', unhandledRequestMessage)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new Error(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', unhandledRequestMessage)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new Error(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAAwC;AACxC,sBAAyB;AAkBzB,eAAsB,mBACpB,SACA,WAAqC,QACtB;AACf,QAAM,gBAAY,wDAAwB,OAAO;AACjD,QAAM,0BAA0B;AAAA;AAAA,WAAyE,QAAQ,MAAM,IAAI,SAAS;AAAA;AAAA;AAAA;AAEpI,WAAS,cAAcA,WAAoC;AACzD,YAAQA,WAAU;AAAA,MAChB,KAAK,SAAS;AAEZ,iCAAS,MAAM,aAAa,uBAAuB;AAGnD,cAAM,IAAI;AAAA,UACR,yBAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,iCAAS,KAAK,eAAe,uBAAuB;AACpD;AAAA,MACF;AAAA,MAEA,KAAK;AACH;AAAA,MAEF;AACE,cAAM,IAAI;AAAA,UACR,yBAAS;AAAA,YACP;AAAA,YACAA;AAAA,UACF;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,YAAY;AAClC,aAAS,SAAS;AAAA,MAChB,SAAS,cAAc,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO,cAAc,KAAK,MAAM,OAAO;AAAA,IACzC,CAAC;AACD;AAAA,EACF;AAEA,gBAAc,QAAQ;AACxB;","names":["strategy"]}
|
|
@@ -1,114 +1,17 @@
|
|
|
1
|
-
import jsLevenshtein from "@bundled-es-modules/js-levenshtein";
|
|
2
|
-
import { HttpHandler } from '../../handlers/HttpHandler.mjs';
|
|
3
|
-
import { GraphQLHandler } from '../../handlers/GraphQLHandler.mjs';
|
|
4
|
-
import {
|
|
5
|
-
parseGraphQLRequest
|
|
6
|
-
} from '../internal/parseGraphQLRequest.mjs';
|
|
7
1
|
import { getPublicUrlFromRequest } from './getPublicUrlFromRequest.mjs';
|
|
8
|
-
import { isStringEqual } from '../internal/isStringEqual.mjs';
|
|
9
2
|
import { devUtils } from '../internal/devUtils.mjs';
|
|
10
|
-
|
|
11
|
-
const MAX_MATCH_SCORE = 3;
|
|
12
|
-
const MAX_SUGGESTION_COUNT = 4;
|
|
13
|
-
const TYPE_MATCH_DELTA = 0.5;
|
|
14
|
-
function groupHandlersByType(handlers) {
|
|
15
|
-
return handlers.reduce(
|
|
16
|
-
(groups, handler) => {
|
|
17
|
-
if (handler instanceof HttpHandler) {
|
|
18
|
-
groups.http.push(handler);
|
|
19
|
-
}
|
|
20
|
-
if (handler instanceof GraphQLHandler) {
|
|
21
|
-
groups.graphql.push(handler);
|
|
22
|
-
}
|
|
23
|
-
return groups;
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
http: [],
|
|
27
|
-
graphql: []
|
|
28
|
-
}
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
function getHttpHandlerScore() {
|
|
32
|
-
return (request, handler) => {
|
|
33
|
-
const { path, method } = handler.info;
|
|
34
|
-
if (path instanceof RegExp || method instanceof RegExp) {
|
|
35
|
-
return Infinity;
|
|
36
|
-
}
|
|
37
|
-
const hasSameMethod = isStringEqual(request.method, method);
|
|
38
|
-
const methodScoreDelta = hasSameMethod ? TYPE_MATCH_DELTA : 0;
|
|
39
|
-
const requestPublicUrl = getPublicUrlFromRequest(request);
|
|
40
|
-
const score = getStringMatchScore(requestPublicUrl, path);
|
|
41
|
-
return score - methodScoreDelta;
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
function getGraphQLHandlerScore(parsedQuery) {
|
|
45
|
-
return (_, handler) => {
|
|
46
|
-
if (typeof parsedQuery.operationName === "undefined") {
|
|
47
|
-
return Infinity;
|
|
48
|
-
}
|
|
49
|
-
const { operationType, operationName } = handler.info;
|
|
50
|
-
if (typeof operationName !== "string") {
|
|
51
|
-
return Infinity;
|
|
52
|
-
}
|
|
53
|
-
const hasSameOperationType = parsedQuery.operationType === operationType;
|
|
54
|
-
const operationTypeScoreDelta = hasSameOperationType ? TYPE_MATCH_DELTA : 0;
|
|
55
|
-
const score = getStringMatchScore(parsedQuery.operationName, operationName);
|
|
56
|
-
return score - operationTypeScoreDelta;
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
function getSuggestedHandler(request, handlers, getScore) {
|
|
60
|
-
const suggestedHandlers = handlers.reduce((suggestions, handler) => {
|
|
61
|
-
const score = getScore(request, handler);
|
|
62
|
-
return suggestions.concat([[score, handler]]);
|
|
63
|
-
}, []).sort(([leftScore], [rightScore]) => leftScore - rightScore).filter(([score]) => score <= MAX_MATCH_SCORE).slice(0, MAX_SUGGESTION_COUNT).map(([, handler]) => handler);
|
|
64
|
-
return suggestedHandlers;
|
|
65
|
-
}
|
|
66
|
-
function getSuggestedHandlersMessage(handlers) {
|
|
67
|
-
if (handlers.length > 1) {
|
|
68
|
-
return `Did you mean to request one of the following resources instead?
|
|
69
|
-
|
|
70
|
-
${handlers.map((handler) => ` \u2022 ${handler.info.header}`).join("\n")}`;
|
|
71
|
-
}
|
|
72
|
-
return `Did you mean to request "${handlers[0].info.header}" instead?`;
|
|
73
|
-
}
|
|
74
|
-
async function onUnhandledRequest(request, handlers, strategy = "warn") {
|
|
75
|
-
const parsedGraphQLQuery = await parseGraphQLRequest(request).catch(
|
|
76
|
-
() => null
|
|
77
|
-
);
|
|
3
|
+
async function onUnhandledRequest(request, strategy = "warn") {
|
|
78
4
|
const publicUrl = getPublicUrlFromRequest(request);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
parsedGraphQLQuery ? getGraphQLHandlerScore(parsedGraphQLQuery) : getHttpHandlerScore()
|
|
86
|
-
);
|
|
87
|
-
return suggestedHandlers.length > 0 ? getSuggestedHandlersMessage(suggestedHandlers) : "";
|
|
88
|
-
}
|
|
89
|
-
function getGraphQLRequestHeader(parsedGraphQLRequest) {
|
|
90
|
-
if (!parsedGraphQLRequest?.operationName) {
|
|
91
|
-
return `anonymous ${parsedGraphQLRequest?.operationType} (${request.method} ${publicUrl})`;
|
|
92
|
-
}
|
|
93
|
-
return `${parsedGraphQLRequest.operationType} ${parsedGraphQLRequest.operationName} (${request.method} ${publicUrl})`;
|
|
94
|
-
}
|
|
95
|
-
function generateUnhandledRequestMessage() {
|
|
96
|
-
const requestHeader = parsedGraphQLQuery ? getGraphQLRequestHeader(parsedGraphQLQuery) : `${request.method} ${publicUrl}`;
|
|
97
|
-
const handlerSuggestion = generateHandlerSuggestion();
|
|
98
|
-
const messageTemplate = [
|
|
99
|
-
`intercepted a request without a matching request handler:`,
|
|
100
|
-
` \u2022 ${requestHeader}`,
|
|
101
|
-
handlerSuggestion,
|
|
102
|
-
`If you still wish to intercept this unhandled request, please create a request handler for it.
|
|
103
|
-
Read more: https://mswjs.io/docs/getting-started/mocks`
|
|
104
|
-
].filter(Boolean);
|
|
105
|
-
return messageTemplate.join("\n\n");
|
|
106
|
-
}
|
|
5
|
+
const unhandledRequestMessage = `intercepted a request without a matching request handler:
|
|
6
|
+
|
|
7
|
+
\u2022 ${request.method} ${publicUrl}
|
|
8
|
+
|
|
9
|
+
If you still wish to intercept this unhandled request, please create a request handler for it.
|
|
10
|
+
Read more: https://mswjs.io/docs/getting-started/mocks`;
|
|
107
11
|
function applyStrategy(strategy2) {
|
|
108
|
-
const message = generateUnhandledRequestMessage();
|
|
109
12
|
switch (strategy2) {
|
|
110
13
|
case "error": {
|
|
111
|
-
devUtils.error("Error: %s",
|
|
14
|
+
devUtils.error("Error: %s", unhandledRequestMessage);
|
|
112
15
|
throw new Error(
|
|
113
16
|
devUtils.formatMessage(
|
|
114
17
|
'Cannot bypass a request when using the "error" strategy for the "onUnhandledRequest" option.'
|
|
@@ -116,7 +19,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks`
|
|
|
116
19
|
);
|
|
117
20
|
}
|
|
118
21
|
case "warn": {
|
|
119
|
-
devUtils.warn("Warning: %s",
|
|
22
|
+
devUtils.warn("Warning: %s", unhandledRequestMessage);
|
|
120
23
|
break;
|
|
121
24
|
}
|
|
122
25
|
case "bypass":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import jsLevenshtein from '@bundled-es-modules/js-levenshtein'\nimport { RequestHandler } from '../../handlers/RequestHandler'\nimport { HttpHandler } from '../../handlers/HttpHandler'\nimport { GraphQLHandler } from '../../handlers/GraphQLHandler'\nimport {\n ParsedGraphQLQuery,\n ParsedGraphQLRequest,\n parseGraphQLRequest,\n} from '../internal/parseGraphQLRequest'\nimport { getPublicUrlFromRequest } from './getPublicUrlFromRequest'\nimport { isStringEqual } from '../internal/isStringEqual'\nimport { devUtils } from '../internal/devUtils'\n\nconst getStringMatchScore = jsLevenshtein\n\nconst MAX_MATCH_SCORE = 3\nconst MAX_SUGGESTION_COUNT = 4\nconst TYPE_MATCH_DELTA = 0.5\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\ninterface RequestHandlerGroups {\n http: Array<HttpHandler>\n graphql: Array<GraphQLHandler>\n}\n\nfunction groupHandlersByType(\n handlers: Array<RequestHandler>,\n): RequestHandlerGroups {\n return handlers.reduce<RequestHandlerGroups>(\n (groups, handler) => {\n if (handler instanceof HttpHandler) {\n groups.http.push(handler)\n }\n\n if (handler instanceof GraphQLHandler) {\n groups.graphql.push(handler)\n }\n\n return groups\n },\n {\n http: [],\n graphql: [],\n },\n )\n}\n\ntype RequestHandlerSuggestion = [number, RequestHandler]\n\ntype ScoreGetterFn<RequestHandlerType extends RequestHandler> = (\n request: Request,\n handler: RequestHandlerType,\n) => number\n\nfunction getHttpHandlerScore(): ScoreGetterFn<HttpHandler> {\n return (request, handler) => {\n const { path, method } = handler.info\n\n if (path instanceof RegExp || method instanceof RegExp) {\n return Infinity\n }\n\n const hasSameMethod = isStringEqual(request.method, method)\n\n // Always treat a handler with the same method as a more similar one.\n const methodScoreDelta = hasSameMethod ? TYPE_MATCH_DELTA : 0\n const requestPublicUrl = getPublicUrlFromRequest(request)\n const score = getStringMatchScore(requestPublicUrl, path)\n\n return score - methodScoreDelta\n }\n}\n\nfunction getGraphQLHandlerScore(\n parsedQuery: ParsedGraphQLQuery,\n): ScoreGetterFn<GraphQLHandler> {\n return (_, handler) => {\n if (typeof parsedQuery.operationName === 'undefined') {\n return Infinity\n }\n\n const { operationType, operationName } = handler.info\n\n if (typeof operationName !== 'string') {\n return Infinity\n }\n\n const hasSameOperationType = parsedQuery.operationType === operationType\n // Always treat a handler with the same operation type as a more similar one.\n const operationTypeScoreDelta = hasSameOperationType ? TYPE_MATCH_DELTA : 0\n const score = getStringMatchScore(parsedQuery.operationName, operationName)\n\n return score - operationTypeScoreDelta\n }\n}\n\nfunction getSuggestedHandler(\n request: Request,\n handlers: Array<HttpHandler> | Array<GraphQLHandler>,\n getScore: ScoreGetterFn<HttpHandler> | ScoreGetterFn<GraphQLHandler>,\n): Array<RequestHandler> {\n const suggestedHandlers = (handlers as Array<RequestHandler>)\n .reduce<Array<RequestHandlerSuggestion>>((suggestions, handler) => {\n const score = getScore(request, handler as any)\n return suggestions.concat([[score, handler]])\n }, [])\n .sort(([leftScore], [rightScore]) => leftScore - rightScore)\n .filter(([score]) => score <= MAX_MATCH_SCORE)\n .slice(0, MAX_SUGGESTION_COUNT)\n .map(([, handler]) => handler)\n\n return suggestedHandlers\n}\n\nfunction getSuggestedHandlersMessage(handlers: RequestHandler[]) {\n if (handlers.length > 1) {\n return `\\\nDid you mean to request one of the following resources instead?\n\n${handlers.map((handler) => ` • ${handler.info.header}`).join('\\n')}`\n }\n\n return `Did you mean to request \"${handlers[0].info.header}\" instead?`\n}\n\nexport async function onUnhandledRequest(\n request: Request,\n handlers: Array<RequestHandler>,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const parsedGraphQLQuery = await parseGraphQLRequest(request).catch(\n () => null,\n )\n const publicUrl = getPublicUrlFromRequest(request)\n\n function generateHandlerSuggestion(): string {\n /**\n * @note Ignore exceptions during GraphQL request parsing because at this point\n * we cannot assume the unhandled request is a valid GraphQL request.\n * If the GraphQL parsing fails, just don't treat it as a GraphQL request.\n */\n const handlerGroups = groupHandlersByType(handlers)\n const relevantHandlers = parsedGraphQLQuery\n ? handlerGroups.graphql\n : handlerGroups.http\n\n const suggestedHandlers = getSuggestedHandler(\n request,\n relevantHandlers,\n parsedGraphQLQuery\n ? getGraphQLHandlerScore(parsedGraphQLQuery)\n : getHttpHandlerScore(),\n )\n\n return suggestedHandlers.length > 0\n ? getSuggestedHandlersMessage(suggestedHandlers)\n : ''\n }\n\n function getGraphQLRequestHeader(\n parsedGraphQLRequest: ParsedGraphQLRequest<any>,\n ): string {\n if (!parsedGraphQLRequest?.operationName) {\n return `anonymous ${parsedGraphQLRequest?.operationType} (${request.method} ${publicUrl})`\n }\n\n return `${parsedGraphQLRequest.operationType} ${parsedGraphQLRequest.operationName} (${request.method} ${publicUrl})`\n }\n\n function generateUnhandledRequestMessage(): string {\n const requestHeader = parsedGraphQLQuery\n ? getGraphQLRequestHeader(parsedGraphQLQuery)\n : `${request.method} ${publicUrl}`\n const handlerSuggestion = generateHandlerSuggestion()\n\n const messageTemplate = [\n `intercepted a request without a matching request handler:`,\n ` \\u2022 ${requestHeader}`,\n handlerSuggestion,\n `\\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\nRead more: https://mswjs.io/docs/getting-started/mocks\\\n`,\n ].filter(Boolean)\n return messageTemplate.join('\\n\\n')\n }\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n // Generate handler suggestions only when applying the strategy.\n // This saves bandwidth for scenarios when developers opt-out\n // from the default unhandled request handling strategy.\n const message = generateUnhandledRequestMessage()\n\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', message)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new Error(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', message)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new Error(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":"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","names":["strategy"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import { getPublicUrlFromRequest } from './getPublicUrlFromRequest'\nimport { devUtils } from '../internal/devUtils'\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\nexport async function onUnhandledRequest(\n request: Request,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const publicUrl = getPublicUrlFromRequest(request)\n const unhandledRequestMessage = `intercepted a request without a matching request handler:\\n\\n \\u2022 ${request.method} ${publicUrl}\\n\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/getting-started/mocks`\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', unhandledRequestMessage)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new Error(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', unhandledRequestMessage)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new Error(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":"AAAA,SAAS,+BAA+B;AACxC,SAAS,gBAAgB;AAkBzB,eAAsB,mBACpB,SACA,WAAqC,QACtB;AACf,QAAM,YAAY,wBAAwB,OAAO;AACjD,QAAM,0BAA0B;AAAA;AAAA,WAAyE,QAAQ,MAAM,IAAI,SAAS;AAAA;AAAA;AAAA;AAEpI,WAAS,cAAcA,WAAoC;AACzD,YAAQA,WAAU;AAAA,MAChB,KAAK,SAAS;AAEZ,iBAAS,MAAM,aAAa,uBAAuB;AAGnD,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,iBAAS,KAAK,eAAe,uBAAuB;AACpD;AAAA,MACF;AAAA,MAEA,KAAK;AACH;AAAA,MAEF;AACE,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,YACP;AAAA,YACAA;AAAA,UACF;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,YAAY;AAClC,aAAS,SAAS;AAAA,MAChB,SAAS,cAAc,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO,cAAc,KAAK,MAAM,OAAO;AAAA,IACzC,CAAC;AACD;AAAA,EACF;AAEA,gBAAc,QAAQ;AACxB;","names":["strategy"]}
|