msw 2.0.12 → 2.0.14
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.d.mts +104 -0
- package/lib/browser/index.d.ts +1 -1
- package/lib/browser/index.js +1 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/index.mjs +1 -0
- package/lib/browser/index.mjs.map +1 -0
- package/lib/core/{GraphQLHandler-da09c680.d.ts → GraphQLHandler-JB4bsrLF.d.ts} +4 -2
- package/lib/core/GraphQLHandler-mT-MmgeB.d.mts +99 -0
- package/lib/core/HttpResponse.d.mts +2 -0
- package/lib/core/HttpResponse.d.ts +1 -1
- package/lib/core/HttpResponse.js +1 -0
- package/lib/core/HttpResponse.js.map +1 -0
- package/lib/core/HttpResponse.mjs +1 -0
- package/lib/core/HttpResponse.mjs.map +1 -0
- package/lib/core/RequestHandler-YiqamK0M.d.mts +179 -0
- package/lib/core/{RequestHandler-25f9cfd1.d.ts → RequestHandler-rmY-HeFN.d.ts} +4 -4
- package/lib/core/SetupApi.d.mts +26 -0
- package/lib/core/SetupApi.d.ts +1 -1
- package/lib/core/SetupApi.js +1 -0
- package/lib/core/SetupApi.js.map +1 -0
- package/lib/core/SetupApi.mjs +1 -0
- package/lib/core/SetupApi.mjs.map +1 -0
- package/lib/core/bypass.d.mts +16 -0
- package/lib/core/bypass.d.ts +1 -1
- package/lib/core/bypass.js +1 -0
- package/lib/core/bypass.js.map +1 -0
- package/lib/core/bypass.mjs +1 -0
- package/lib/core/bypass.mjs.map +1 -0
- package/lib/core/delay.d.mts +18 -0
- package/lib/core/delay.d.ts +1 -1
- package/lib/core/delay.js +1 -0
- package/lib/core/delay.js.map +1 -0
- package/lib/core/delay.mjs +1 -0
- package/lib/core/delay.mjs.map +1 -0
- package/lib/core/graphql.d.mts +111 -0
- package/lib/core/graphql.d.ts +11 -9
- package/lib/core/graphql.js +1 -0
- package/lib/core/graphql.js.map +1 -0
- package/lib/core/graphql.mjs +1 -0
- package/lib/core/graphql.mjs.map +1 -0
- package/lib/core/handlers/GraphQLHandler.d.mts +5 -0
- package/lib/core/handlers/GraphQLHandler.d.ts +2 -2
- package/lib/core/handlers/GraphQLHandler.js +8 -6
- package/lib/core/handlers/GraphQLHandler.js.map +1 -0
- package/lib/core/handlers/GraphQLHandler.mjs +8 -6
- package/lib/core/handlers/GraphQLHandler.mjs.map +1 -0
- package/lib/core/handlers/HttpHandler.d.mts +62 -0
- package/lib/core/handlers/HttpHandler.d.ts +2 -2
- package/lib/core/handlers/HttpHandler.js +1 -0
- package/lib/core/handlers/HttpHandler.js.map +1 -0
- package/lib/core/handlers/HttpHandler.mjs +1 -0
- package/lib/core/handlers/HttpHandler.mjs.map +1 -0
- package/lib/core/handlers/RequestHandler.d.mts +2 -0
- package/lib/core/handlers/RequestHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.js +3 -2
- package/lib/core/handlers/RequestHandler.js.map +1 -0
- package/lib/core/handlers/RequestHandler.mjs +3 -2
- package/lib/core/handlers/RequestHandler.mjs.map +1 -0
- package/lib/core/http.d.mts +28 -0
- package/lib/core/http.d.ts +13 -11
- package/lib/core/http.js +1 -0
- package/lib/core/http.js.map +1 -0
- package/lib/core/http.mjs +1 -0
- package/lib/core/http.mjs.map +1 -0
- package/lib/core/index.d.mts +18 -0
- package/lib/core/index.d.ts +4 -4
- package/lib/core/index.js +1 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/index.mjs +1 -0
- package/lib/core/index.mjs.map +1 -0
- package/lib/core/passthrough.d.mts +17 -0
- package/lib/core/passthrough.js +1 -0
- package/lib/core/passthrough.js.map +1 -0
- package/lib/core/passthrough.mjs +1 -0
- package/lib/core/passthrough.mjs.map +1 -0
- package/lib/core/sharedOptions.d.mts +66 -0
- package/lib/core/sharedOptions.d.ts +2 -2
- package/lib/core/sharedOptions.js +1 -0
- package/lib/core/sharedOptions.js.map +1 -0
- package/lib/core/sharedOptions.mjs +1 -0
- package/lib/core/sharedOptions.mjs.map +1 -0
- package/lib/core/typeUtils.d.mts +7 -0
- package/lib/core/typeUtils.d.ts +1 -1
- package/lib/core/typeUtils.js +1 -0
- package/lib/core/typeUtils.js.map +1 -0
- package/lib/core/typeUtils.mjs +1 -0
- package/lib/core/typeUtils.mjs.map +1 -0
- package/lib/core/utils/HttpResponse/decorators.d.mts +12 -0
- package/lib/core/utils/HttpResponse/decorators.d.ts +2 -2
- package/lib/core/utils/HttpResponse/decorators.js +1 -0
- package/lib/core/utils/HttpResponse/decorators.js.map +1 -0
- package/lib/core/utils/HttpResponse/decorators.mjs +1 -0
- package/lib/core/utils/HttpResponse/decorators.mjs.map +1 -0
- package/lib/core/utils/getResponse.d.mts +2 -0
- package/lib/core/utils/getResponse.d.ts +1 -1
- package/lib/core/utils/getResponse.js +1 -0
- package/lib/core/utils/getResponse.js.map +1 -0
- package/lib/core/utils/getResponse.mjs +1 -0
- package/lib/core/utils/getResponse.mjs.map +1 -0
- package/lib/core/utils/handleRequest.d.mts +37 -0
- package/lib/core/utils/handleRequest.d.ts +2 -2
- package/lib/core/utils/handleRequest.js +1 -0
- package/lib/core/utils/handleRequest.js.map +1 -0
- package/lib/core/utils/handleRequest.mjs +1 -0
- package/lib/core/utils/handleRequest.mjs.map +1 -0
- package/lib/core/utils/internal/Disposable.d.mts +7 -0
- package/lib/core/utils/internal/Disposable.d.ts +1 -1
- package/lib/core/utils/internal/Disposable.js +1 -0
- package/lib/core/utils/internal/Disposable.js.map +1 -0
- package/lib/core/utils/internal/Disposable.mjs +1 -0
- package/lib/core/utils/internal/Disposable.mjs.map +1 -0
- package/lib/core/utils/internal/checkGlobals.d.mts +3 -0
- package/lib/core/utils/internal/checkGlobals.js +1 -0
- package/lib/core/utils/internal/checkGlobals.js.map +1 -0
- package/lib/core/utils/internal/checkGlobals.mjs +1 -0
- package/lib/core/utils/internal/checkGlobals.mjs.map +1 -0
- package/lib/core/utils/internal/devUtils.d.mts +19 -0
- package/lib/core/utils/internal/devUtils.js +1 -0
- package/lib/core/utils/internal/devUtils.js.map +1 -0
- package/lib/core/utils/internal/devUtils.mjs +1 -0
- package/lib/core/utils/internal/devUtils.mjs.map +1 -0
- package/lib/core/utils/internal/getCallFrame.d.mts +6 -0
- package/lib/core/utils/internal/getCallFrame.js +1 -0
- package/lib/core/utils/internal/getCallFrame.js.map +1 -0
- package/lib/core/utils/internal/getCallFrame.mjs +1 -0
- package/lib/core/utils/internal/getCallFrame.mjs.map +1 -0
- package/lib/core/utils/internal/isIterable.d.mts +6 -0
- package/lib/core/utils/internal/isIterable.js +1 -0
- package/lib/core/utils/internal/isIterable.js.map +1 -0
- package/lib/core/utils/internal/isIterable.mjs +1 -0
- package/lib/core/utils/internal/isIterable.mjs.map +1 -0
- package/lib/core/utils/internal/isObject.d.mts +6 -0
- package/lib/core/utils/internal/isObject.js +1 -0
- package/lib/core/utils/internal/isObject.js.map +1 -0
- package/lib/core/utils/internal/isObject.mjs +1 -0
- package/lib/core/utils/internal/isObject.mjs.map +1 -0
- package/lib/core/utils/internal/isStringEqual.d.mts +6 -0
- package/lib/core/utils/internal/isStringEqual.js +1 -0
- package/lib/core/utils/internal/isStringEqual.js.map +1 -0
- package/lib/core/utils/internal/isStringEqual.mjs +1 -0
- package/lib/core/utils/internal/isStringEqual.mjs.map +1 -0
- package/lib/core/utils/internal/jsonParse.d.mts +7 -0
- package/lib/core/utils/internal/jsonParse.js +1 -0
- package/lib/core/utils/internal/jsonParse.js.map +1 -0
- package/lib/core/utils/internal/jsonParse.mjs +1 -0
- package/lib/core/utils/internal/jsonParse.mjs.map +1 -0
- package/lib/core/utils/internal/mergeRight.d.mts +7 -0
- package/lib/core/utils/internal/mergeRight.js +1 -0
- package/lib/core/utils/internal/mergeRight.js.map +1 -0
- package/lib/core/utils/internal/mergeRight.mjs +1 -0
- package/lib/core/utils/internal/mergeRight.mjs.map +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +5 -0
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +2 -2
- package/lib/core/utils/internal/parseGraphQLRequest.js +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.js.map +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.mjs +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.mjs.map +1 -0
- package/lib/core/utils/internal/parseMultipartData.d.mts +10 -0
- package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
- package/lib/core/utils/internal/parseMultipartData.js +1 -0
- package/lib/core/utils/internal/parseMultipartData.js.map +1 -0
- package/lib/core/utils/internal/parseMultipartData.mjs +1 -0
- package/lib/core/utils/internal/parseMultipartData.mjs.map +1 -0
- package/lib/core/utils/internal/pipeEvents.d.mts +8 -0
- package/lib/core/utils/internal/pipeEvents.js +1 -0
- package/lib/core/utils/internal/pipeEvents.js.map +1 -0
- package/lib/core/utils/internal/pipeEvents.mjs +1 -0
- package/lib/core/utils/internal/pipeEvents.mjs.map +1 -0
- package/lib/core/utils/internal/requestHandlerUtils.d.mts +8 -0
- package/lib/core/utils/internal/requestHandlerUtils.d.ts +1 -1
- package/lib/core/utils/internal/requestHandlerUtils.js +1 -0
- package/lib/core/utils/internal/requestHandlerUtils.js.map +1 -0
- package/lib/core/utils/internal/requestHandlerUtils.mjs +1 -0
- package/lib/core/utils/internal/requestHandlerUtils.mjs.map +1 -0
- package/lib/core/utils/internal/toReadonlyArray.d.mts +6 -0
- package/lib/core/utils/internal/toReadonlyArray.js +1 -0
- package/lib/core/utils/internal/toReadonlyArray.js.map +1 -0
- package/lib/core/utils/internal/toReadonlyArray.mjs +1 -0
- package/lib/core/utils/internal/toReadonlyArray.mjs.map +1 -0
- package/lib/core/utils/internal/tryCatch.d.mts +3 -0
- package/lib/core/utils/internal/tryCatch.js +1 -0
- package/lib/core/utils/internal/tryCatch.js.map +1 -0
- package/lib/core/utils/internal/tryCatch.mjs +1 -0
- package/lib/core/utils/internal/tryCatch.mjs.map +1 -0
- package/lib/core/utils/internal/uuidv4.d.mts +3 -0
- package/lib/core/utils/internal/uuidv4.js +1 -0
- package/lib/core/utils/internal/uuidv4.js.map +1 -0
- package/lib/core/utils/internal/uuidv4.mjs +1 -0
- package/lib/core/utils/internal/uuidv4.mjs.map +1 -0
- package/lib/core/utils/logging/getStatusCodeColor.d.mts +11 -0
- package/lib/core/utils/logging/getStatusCodeColor.js +1 -0
- package/lib/core/utils/logging/getStatusCodeColor.js.map +1 -0
- package/lib/core/utils/logging/getStatusCodeColor.mjs +1 -0
- package/lib/core/utils/logging/getStatusCodeColor.mjs.map +1 -0
- package/lib/core/utils/logging/getTimestamp.d.mts +6 -0
- package/lib/core/utils/logging/getTimestamp.js +1 -0
- package/lib/core/utils/logging/getTimestamp.js.map +1 -0
- package/lib/core/utils/logging/getTimestamp.mjs +1 -0
- package/lib/core/utils/logging/getTimestamp.mjs.map +1 -0
- package/lib/core/utils/logging/serializeRequest.d.mts +12 -0
- package/lib/core/utils/logging/serializeRequest.d.ts +1 -1
- package/lib/core/utils/logging/serializeRequest.js +1 -0
- package/lib/core/utils/logging/serializeRequest.js.map +1 -0
- package/lib/core/utils/logging/serializeRequest.mjs +1 -0
- package/lib/core/utils/logging/serializeRequest.mjs.map +1 -0
- package/lib/core/utils/logging/serializeResponse.d.mts +9 -0
- package/lib/core/utils/logging/serializeResponse.d.ts +1 -1
- package/lib/core/utils/logging/serializeResponse.js +1 -0
- package/lib/core/utils/logging/serializeResponse.js.map +1 -0
- package/lib/core/utils/logging/serializeResponse.mjs +1 -0
- package/lib/core/utils/logging/serializeResponse.mjs.map +1 -0
- package/lib/core/utils/matching/matchRequestUrl.d.mts +19 -0
- package/lib/core/utils/matching/matchRequestUrl.d.ts +1 -1
- package/lib/core/utils/matching/matchRequestUrl.js +1 -0
- package/lib/core/utils/matching/matchRequestUrl.js.map +1 -0
- package/lib/core/utils/matching/matchRequestUrl.mjs +1 -0
- package/lib/core/utils/matching/matchRequestUrl.mjs.map +1 -0
- package/lib/core/utils/matching/normalizePath.d.mts +12 -0
- package/lib/core/utils/matching/normalizePath.js +1 -0
- package/lib/core/utils/matching/normalizePath.js.map +1 -0
- package/lib/core/utils/matching/normalizePath.mjs +1 -0
- package/lib/core/utils/matching/normalizePath.mjs.map +1 -0
- package/lib/core/utils/request/getPublicUrlFromRequest.d.mts +7 -0
- package/lib/core/utils/request/getPublicUrlFromRequest.js +1 -0
- package/lib/core/utils/request/getPublicUrlFromRequest.js.map +1 -0
- package/lib/core/utils/request/getPublicUrlFromRequest.mjs +1 -0
- package/lib/core/utils/request/getPublicUrlFromRequest.mjs.map +1 -0
- package/lib/core/utils/request/getRequestCookies.d.mts +8 -0
- package/lib/core/utils/request/getRequestCookies.js +1 -0
- package/lib/core/utils/request/getRequestCookies.js.map +1 -0
- package/lib/core/utils/request/getRequestCookies.mjs +1 -0
- package/lib/core/utils/request/getRequestCookies.mjs.map +1 -0
- package/lib/core/utils/request/onUnhandledRequest.d.mts +12 -0
- package/lib/core/utils/request/onUnhandledRequest.d.ts +2 -2
- package/lib/core/utils/request/onUnhandledRequest.js +1 -0
- package/lib/core/utils/request/onUnhandledRequest.js.map +1 -0
- package/lib/core/utils/request/onUnhandledRequest.mjs +1 -0
- package/lib/core/utils/request/onUnhandledRequest.mjs.map +1 -0
- package/lib/core/utils/request/readResponseCookies.d.mts +3 -0
- package/lib/core/utils/request/readResponseCookies.js +1 -0
- package/lib/core/utils/request/readResponseCookies.js.map +1 -0
- package/lib/core/utils/request/readResponseCookies.mjs +1 -0
- package/lib/core/utils/request/readResponseCookies.mjs.map +1 -0
- package/lib/core/utils/toResponseInit.d.mts +3 -0
- package/lib/core/utils/toResponseInit.js +1 -0
- package/lib/core/utils/toResponseInit.js.map +1 -0
- package/lib/core/utils/toResponseInit.mjs +1 -0
- package/lib/core/utils/toResponseInit.mjs.map +1 -0
- package/lib/core/utils/url/cleanUrl.d.mts +7 -0
- package/lib/core/utils/url/cleanUrl.js +1 -0
- package/lib/core/utils/url/cleanUrl.js.map +1 -0
- package/lib/core/utils/url/cleanUrl.mjs +1 -0
- package/lib/core/utils/url/cleanUrl.mjs.map +1 -0
- package/lib/core/utils/url/getAbsoluteUrl.d.mts +6 -0
- package/lib/core/utils/url/getAbsoluteUrl.js +1 -0
- package/lib/core/utils/url/getAbsoluteUrl.js.map +1 -0
- package/lib/core/utils/url/getAbsoluteUrl.mjs +1 -0
- package/lib/core/utils/url/getAbsoluteUrl.mjs.map +1 -0
- package/lib/core/utils/url/isAbsoluteUrl.d.mts +6 -0
- package/lib/core/utils/url/isAbsoluteUrl.js +1 -0
- package/lib/core/utils/url/isAbsoluteUrl.js.map +1 -0
- package/lib/core/utils/url/isAbsoluteUrl.mjs +1 -0
- package/lib/core/utils/url/isAbsoluteUrl.mjs.map +1 -0
- package/lib/iife/index.js +25 -23
- package/lib/iife/index.js.map +1 -0
- package/lib/mockServiceWorker.js +1 -1
- package/lib/native/index.d.mts +75 -0
- package/lib/native/index.js +1 -0
- package/lib/native/index.js.map +1 -0
- package/lib/native/index.mjs +1 -0
- package/lib/native/index.mjs.map +1 -0
- package/lib/node/index.d.mts +75 -0
- package/lib/node/index.d.ts +1 -1
- package/lib/node/index.js +1 -0
- package/lib/node/index.js.map +1 -0
- package/lib/node/index.mjs +1 -0
- package/lib/node/index.mjs.map +1 -0
- package/package.json +5 -4
- package/src/browser/global.browser.d.ts +1 -0
- package/src/browser/index.ts +3 -0
- package/src/browser/setupWorker/glossary.ts +259 -0
- package/src/browser/setupWorker/setupWorker.node.test.ts +10 -0
- package/src/browser/setupWorker/setupWorker.ts +199 -0
- package/src/browser/setupWorker/start/createFallbackRequestListener.ts +67 -0
- package/src/browser/setupWorker/start/createFallbackStart.ts +21 -0
- package/src/browser/setupWorker/start/createRequestListener.ts +127 -0
- package/src/browser/setupWorker/start/createResponseListener.ts +58 -0
- package/src/browser/setupWorker/start/createStartHandler.ts +143 -0
- package/src/browser/setupWorker/start/utils/createMessageChannel.ts +32 -0
- package/src/browser/setupWorker/start/utils/enableMocking.ts +32 -0
- package/src/browser/setupWorker/start/utils/getWorkerByRegistration.ts +25 -0
- package/src/browser/setupWorker/start/utils/getWorkerInstance.ts +94 -0
- package/src/browser/setupWorker/start/utils/prepareStartHandler.test.ts +59 -0
- package/src/browser/setupWorker/start/utils/prepareStartHandler.ts +44 -0
- package/src/browser/setupWorker/start/utils/printStartMessage.test.ts +84 -0
- package/src/browser/setupWorker/start/utils/printStartMessage.ts +40 -0
- package/src/browser/setupWorker/start/utils/validateWorkerScope.ts +18 -0
- package/src/browser/setupWorker/stop/createFallbackStop.ts +11 -0
- package/src/browser/setupWorker/stop/createStop.ts +29 -0
- package/src/browser/setupWorker/stop/utils/printStopMessage.test.ts +26 -0
- package/src/browser/setupWorker/stop/utils/printStopMessage.ts +12 -0
- package/src/browser/tsconfig.browser.build.json +6 -0
- package/src/browser/tsconfig.browser.json +9 -0
- package/src/browser/utils/deferNetworkRequestsUntil.test.ts +48 -0
- package/src/browser/utils/deferNetworkRequestsUntil.ts +29 -0
- package/src/browser/utils/getAbsoluteWorkerUrl.test.ts +31 -0
- package/src/browser/utils/getAbsoluteWorkerUrl.ts +7 -0
- package/src/browser/utils/parseWorkerRequest.ts +15 -0
- package/src/browser/utils/pruneGetRequestBody.test.ts +53 -0
- package/src/browser/utils/pruneGetRequestBody.ts +21 -0
- package/src/browser/utils/requestIntegrityCheck.ts +23 -0
- package/src/browser/utils/supportsReadableStreamTransfer.ts +17 -0
- package/src/core/HttpResponse.test.ts +200 -0
- package/src/core/HttpResponse.ts +134 -0
- package/src/core/SetupApi.ts +95 -0
- package/src/core/bypass.test.ts +47 -0
- package/src/core/bypass.ts +36 -0
- package/src/core/delay.ts +70 -0
- package/src/core/graphql.test.ts +11 -0
- package/src/core/graphql.ts +146 -0
- package/src/core/handlers/GraphQLHandler.test.ts +835 -0
- package/src/core/handlers/GraphQLHandler.ts +266 -0
- package/src/core/handlers/HttpHandler.test.ts +218 -0
- package/src/core/handlers/HttpHandler.ts +169 -0
- package/src/core/handlers/RequestHandler.ts +343 -0
- package/src/core/http.test.ts +15 -0
- package/src/core/http.ts +64 -0
- package/src/core/index.ts +59 -0
- package/src/core/passthrough.test.ts +13 -0
- package/src/core/passthrough.ts +23 -0
- package/src/core/sharedOptions.ts +66 -0
- package/src/core/typeUtils.ts +20 -0
- package/src/core/utils/HttpResponse/decorators.ts +56 -0
- package/src/core/utils/getResponse.ts +55 -0
- package/src/core/utils/handleRequest.test.ts +554 -0
- package/src/core/utils/handleRequest.ts +132 -0
- package/src/core/utils/internal/Disposable.ts +9 -0
- package/src/core/utils/internal/checkGlobals.ts +17 -0
- package/src/core/utils/internal/devUtils.ts +31 -0
- package/src/core/utils/internal/getCallFrame.test.ts +154 -0
- package/src/core/utils/internal/getCallFrame.ts +35 -0
- package/src/core/utils/internal/isIterable.test.ts +23 -0
- package/src/core/utils/internal/isIterable.ts +12 -0
- package/src/core/utils/internal/isObject.test.ts +20 -0
- package/src/core/utils/internal/isObject.ts +6 -0
- package/src/core/utils/internal/isStringEqual.test.ts +45 -0
- package/src/core/utils/internal/isStringEqual.ts +6 -0
- package/src/core/utils/internal/jsonParse.test.ts +13 -0
- package/src/core/utils/internal/jsonParse.ts +13 -0
- package/src/core/utils/internal/mergeRight.test.ts +43 -0
- package/src/core/utils/internal/mergeRight.ts +27 -0
- package/src/core/utils/internal/parseGraphQLRequest.test.ts +99 -0
- package/src/core/utils/internal/parseGraphQLRequest.ts +205 -0
- package/src/core/utils/internal/parseMultipartData.test.ts +76 -0
- package/src/core/utils/internal/parseMultipartData.ts +104 -0
- package/src/core/utils/internal/pipeEvents.test.ts +14 -0
- package/src/core/utils/internal/pipeEvents.ts +25 -0
- package/src/core/utils/internal/requestHandlerUtils.ts +21 -0
- package/src/core/utils/internal/toReadonlyArray.test.ts +30 -0
- package/src/core/utils/internal/toReadonlyArray.ts +8 -0
- package/src/core/utils/internal/tryCatch.test.ts +29 -0
- package/src/core/utils/internal/tryCatch.ts +11 -0
- package/src/core/utils/internal/uuidv4.ts +3 -0
- package/src/core/utils/logging/getStatusCodeColor.test.ts +22 -0
- package/src/core/utils/logging/getStatusCodeColor.ts +20 -0
- package/src/core/utils/logging/getTimestamp.test.ts +18 -0
- package/src/core/utils/logging/getTimestamp.ts +12 -0
- package/src/core/utils/logging/serializeRequest.test.ts +23 -0
- package/src/core/utils/logging/serializeRequest.ts +23 -0
- package/src/core/utils/logging/serializeResponse.test.ts +77 -0
- package/src/core/utils/logging/serializeResponse.ts +31 -0
- package/src/core/utils/matching/matchRequestUrl.test.ts +114 -0
- package/src/core/utils/matching/matchRequestUrl.ts +73 -0
- package/src/core/utils/matching/normalizePath.node.test.ts +44 -0
- package/src/core/utils/matching/normalizePath.test.ts +50 -0
- package/src/core/utils/matching/normalizePath.ts +21 -0
- package/src/core/utils/request/getPublicUrlFromRequest.test.ts +26 -0
- package/src/core/utils/request/getPublicUrlFromRequest.ts +15 -0
- package/src/core/utils/request/getRequestCookies.node.test.ts +29 -0
- package/src/core/utils/request/getRequestCookies.test.ts +64 -0
- package/src/core/utils/request/getRequestCookies.ts +75 -0
- package/src/core/utils/request/onUnhandledRequest.test.ts +215 -0
- package/src/core/utils/request/onUnhandledRequest.ts +247 -0
- package/src/core/utils/request/readResponseCookies.ts +9 -0
- package/src/core/utils/toResponseInit.ts +7 -0
- package/src/core/utils/url/cleanUrl.test.ts +17 -0
- package/src/core/utils/url/cleanUrl.ts +12 -0
- package/src/core/utils/url/getAbsoluteUrl.node.test.ts +19 -0
- package/src/core/utils/url/getAbsoluteUrl.test.ts +29 -0
- package/src/core/utils/url/getAbsoluteUrl.ts +26 -0
- package/src/core/utils/url/isAbsoluteUrl.test.ts +32 -0
- package/src/core/utils/url/isAbsoluteUrl.ts +6 -0
- package/src/iife/index.ts +2 -0
- package/src/mockServiceWorker.js +287 -0
- package/src/native/index.ts +17 -0
- package/src/node/SetupServerApi.ts +113 -0
- package/src/node/glossary.ts +62 -0
- package/src/node/index.ts +3 -0
- package/src/node/setupServer.ts +21 -0
- package/src/node/utils/isNodeExceptionLike.ts +14 -0
- package/src/tsconfig.core.build.json +6 -0
- package/src/tsconfig.node.build.json +6 -0
- package/src/tsconfig.node.json +8 -0
- package/src/tsconfig.src.json +15 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import type { DocumentNode, GraphQLError, OperationTypeNode } from 'graphql'
|
|
2
|
+
import {
|
|
3
|
+
DefaultBodyType,
|
|
4
|
+
RequestHandler,
|
|
5
|
+
RequestHandlerDefaultInfo,
|
|
6
|
+
RequestHandlerOptions,
|
|
7
|
+
ResponseResolver,
|
|
8
|
+
} from './RequestHandler'
|
|
9
|
+
import { getTimestamp } from '../utils/logging/getTimestamp'
|
|
10
|
+
import { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'
|
|
11
|
+
import { serializeRequest } from '../utils/logging/serializeRequest'
|
|
12
|
+
import { serializeResponse } from '../utils/logging/serializeResponse'
|
|
13
|
+
import { Match, matchRequestUrl, Path } from '../utils/matching/matchRequestUrl'
|
|
14
|
+
import {
|
|
15
|
+
ParsedGraphQLRequest,
|
|
16
|
+
GraphQLMultipartRequestBody,
|
|
17
|
+
parseGraphQLRequest,
|
|
18
|
+
parseDocumentNode,
|
|
19
|
+
} from '../utils/internal/parseGraphQLRequest'
|
|
20
|
+
import { getPublicUrlFromRequest } from '../utils/request/getPublicUrlFromRequest'
|
|
21
|
+
import { devUtils } from '../utils/internal/devUtils'
|
|
22
|
+
import { getAllRequestCookies } from '../utils/request/getRequestCookies'
|
|
23
|
+
|
|
24
|
+
export type ExpectedOperationTypeNode = OperationTypeNode | 'all'
|
|
25
|
+
export type GraphQLHandlerNameSelector = DocumentNode | RegExp | string
|
|
26
|
+
|
|
27
|
+
export type GraphQLQuery = Record<string, any>
|
|
28
|
+
export type GraphQLVariables = Record<string, any>
|
|
29
|
+
|
|
30
|
+
export interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {
|
|
31
|
+
operationType: ExpectedOperationTypeNode
|
|
32
|
+
operationName: GraphQLHandlerNameSelector
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type GraphQLRequestParsedResult = {
|
|
36
|
+
match: Match
|
|
37
|
+
cookies: Record<string, string>
|
|
38
|
+
} & (
|
|
39
|
+
| ParsedGraphQLRequest<GraphQLVariables>
|
|
40
|
+
/**
|
|
41
|
+
* An empty version of the ParsedGraphQLRequest
|
|
42
|
+
* which simplifies the return type of the resolver
|
|
43
|
+
* when the request is to a non-matching endpoint
|
|
44
|
+
*/
|
|
45
|
+
| {
|
|
46
|
+
operationType?: undefined
|
|
47
|
+
operationName?: undefined
|
|
48
|
+
query?: undefined
|
|
49
|
+
variables?: undefined
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
export type GraphQLResolverExtras<Variables extends GraphQLVariables> = {
|
|
54
|
+
query: string
|
|
55
|
+
operationName: string
|
|
56
|
+
variables: Variables
|
|
57
|
+
cookies: Record<string, string>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type GraphQLRequestBody<VariablesType extends GraphQLVariables> =
|
|
61
|
+
| GraphQLJsonRequestBody<VariablesType>
|
|
62
|
+
| GraphQLMultipartRequestBody
|
|
63
|
+
| Record<string, any>
|
|
64
|
+
| undefined
|
|
65
|
+
|
|
66
|
+
export interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {
|
|
67
|
+
query: string
|
|
68
|
+
variables?: Variables
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface GraphQLResponseBody<BodyType extends DefaultBodyType> {
|
|
72
|
+
data?: BodyType | null
|
|
73
|
+
errors?: readonly Partial<GraphQLError>[] | null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function isDocumentNode(
|
|
77
|
+
value: DocumentNode | any,
|
|
78
|
+
): value is DocumentNode {
|
|
79
|
+
if (value == null) {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return typeof value === 'object' && 'kind' in value && 'definitions' in value
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class GraphQLHandler extends RequestHandler<
|
|
87
|
+
GraphQLHandlerInfo,
|
|
88
|
+
GraphQLRequestParsedResult,
|
|
89
|
+
GraphQLResolverExtras<any>
|
|
90
|
+
> {
|
|
91
|
+
private endpoint: Path
|
|
92
|
+
|
|
93
|
+
static parsedRequestCache = new WeakMap<
|
|
94
|
+
Request,
|
|
95
|
+
ParsedGraphQLRequest<GraphQLVariables>
|
|
96
|
+
>()
|
|
97
|
+
|
|
98
|
+
constructor(
|
|
99
|
+
operationType: ExpectedOperationTypeNode,
|
|
100
|
+
operationName: GraphQLHandlerNameSelector,
|
|
101
|
+
endpoint: Path,
|
|
102
|
+
resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>,
|
|
103
|
+
options?: RequestHandlerOptions,
|
|
104
|
+
) {
|
|
105
|
+
let resolvedOperationName = operationName
|
|
106
|
+
|
|
107
|
+
if (isDocumentNode(operationName)) {
|
|
108
|
+
const parsedNode = parseDocumentNode(operationName)
|
|
109
|
+
|
|
110
|
+
if (parsedNode.operationType !== operationType) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Failed to create a GraphQL handler: provided a DocumentNode with a mismatched operation type (expected "${operationType}", but got "${parsedNode.operationType}").`,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!parsedNode.operationName) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Failed to create a GraphQL handler: provided a DocumentNode with no operation name.`,
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
resolvedOperationName = parsedNode.operationName
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const header =
|
|
126
|
+
operationType === 'all'
|
|
127
|
+
? `${operationType} (origin: ${endpoint.toString()})`
|
|
128
|
+
: `${operationType} ${resolvedOperationName} (origin: ${endpoint.toString()})`
|
|
129
|
+
|
|
130
|
+
super({
|
|
131
|
+
info: {
|
|
132
|
+
header,
|
|
133
|
+
operationType,
|
|
134
|
+
operationName: resolvedOperationName,
|
|
135
|
+
},
|
|
136
|
+
resolver,
|
|
137
|
+
options,
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
this.endpoint = endpoint
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Parses the request body, once per request, cached across all
|
|
145
|
+
* GraphQL handlers. This is done to avoid multiple parsing of the
|
|
146
|
+
* request body, which each requires a clone of the request.
|
|
147
|
+
*/
|
|
148
|
+
async parseGraphQLRequestOrGetFromCache(
|
|
149
|
+
request: Request,
|
|
150
|
+
): Promise<ParsedGraphQLRequest<GraphQLVariables>> {
|
|
151
|
+
if (!GraphQLHandler.parsedRequestCache.has(request)) {
|
|
152
|
+
GraphQLHandler.parsedRequestCache.set(
|
|
153
|
+
request,
|
|
154
|
+
await parseGraphQLRequest(request).catch((error) => {
|
|
155
|
+
console.error(error)
|
|
156
|
+
return undefined
|
|
157
|
+
}),
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return GraphQLHandler.parsedRequestCache.get(request)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async parse(args: { request: Request }): Promise<GraphQLRequestParsedResult> {
|
|
165
|
+
/**
|
|
166
|
+
* If the request doesn't match a specified endpoint, there's no
|
|
167
|
+
* need to parse it since there's no case where we would handle this
|
|
168
|
+
*/
|
|
169
|
+
const match = matchRequestUrl(new URL(args.request.url), this.endpoint)
|
|
170
|
+
const cookies = getAllRequestCookies(args.request)
|
|
171
|
+
|
|
172
|
+
if (!match.matches) {
|
|
173
|
+
return { match, cookies }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const parsedResult = await this.parseGraphQLRequestOrGetFromCache(
|
|
177
|
+
args.request,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
if (typeof parsedResult === 'undefined') {
|
|
181
|
+
return { match, cookies }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
match,
|
|
186
|
+
cookies,
|
|
187
|
+
query: parsedResult.query,
|
|
188
|
+
operationType: parsedResult.operationType,
|
|
189
|
+
operationName: parsedResult.operationName,
|
|
190
|
+
variables: parsedResult.variables,
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
predicate(args: {
|
|
195
|
+
request: Request
|
|
196
|
+
parsedResult: GraphQLRequestParsedResult
|
|
197
|
+
}) {
|
|
198
|
+
if (args.parsedResult.operationType === undefined) {
|
|
199
|
+
return false
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!args.parsedResult.operationName && this.info.operationType !== 'all') {
|
|
203
|
+
const publicUrl = getPublicUrlFromRequest(args.request)
|
|
204
|
+
|
|
205
|
+
devUtils.warn(`\
|
|
206
|
+
Failed to intercept a GraphQL request at "${args.request.method} ${publicUrl}": anonymous GraphQL operations are not supported.
|
|
207
|
+
|
|
208
|
+
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`)
|
|
209
|
+
return false
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const hasMatchingOperationType =
|
|
213
|
+
this.info.operationType === 'all' ||
|
|
214
|
+
args.parsedResult.operationType === this.info.operationType
|
|
215
|
+
|
|
216
|
+
const hasMatchingOperationName =
|
|
217
|
+
this.info.operationName instanceof RegExp
|
|
218
|
+
? this.info.operationName.test(args.parsedResult.operationName || '')
|
|
219
|
+
: args.parsedResult.operationName === this.info.operationName
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
args.parsedResult.match.matches &&
|
|
223
|
+
hasMatchingOperationType &&
|
|
224
|
+
hasMatchingOperationName
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
protected extendResolverArgs(args: {
|
|
229
|
+
request: Request
|
|
230
|
+
parsedResult: GraphQLRequestParsedResult
|
|
231
|
+
}) {
|
|
232
|
+
return {
|
|
233
|
+
query: args.parsedResult.query || '',
|
|
234
|
+
operationName: args.parsedResult.operationName || '',
|
|
235
|
+
variables: args.parsedResult.variables || {},
|
|
236
|
+
cookies: args.parsedResult.cookies,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async log(args: {
|
|
241
|
+
request: Request
|
|
242
|
+
response: Response
|
|
243
|
+
parsedResult: GraphQLRequestParsedResult
|
|
244
|
+
}) {
|
|
245
|
+
const loggedRequest = await serializeRequest(args.request)
|
|
246
|
+
const loggedResponse = await serializeResponse(args.response)
|
|
247
|
+
const statusColor = getStatusCodeColor(loggedResponse.status)
|
|
248
|
+
const requestInfo = args.parsedResult.operationName
|
|
249
|
+
? `${args.parsedResult.operationType} ${args.parsedResult.operationName}`
|
|
250
|
+
: `anonymous ${args.parsedResult.operationType}`
|
|
251
|
+
|
|
252
|
+
console.groupCollapsed(
|
|
253
|
+
devUtils.formatMessage(
|
|
254
|
+
`${getTimestamp()} ${requestInfo} (%c${loggedResponse.status} ${
|
|
255
|
+
loggedResponse.statusText
|
|
256
|
+
}%c)`,
|
|
257
|
+
),
|
|
258
|
+
`color:${statusColor}`,
|
|
259
|
+
'color:inherit',
|
|
260
|
+
)
|
|
261
|
+
console.log('Request:', loggedRequest)
|
|
262
|
+
console.log('Handler:', this)
|
|
263
|
+
console.log('Response:', loggedResponse)
|
|
264
|
+
console.groupEnd()
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
import { HttpHandler, HttpRequestResolverExtras } from './HttpHandler'
|
|
5
|
+
import { HttpResponse } from '..'
|
|
6
|
+
import { ResponseResolver } from './RequestHandler'
|
|
7
|
+
|
|
8
|
+
const resolver: ResponseResolver<
|
|
9
|
+
HttpRequestResolverExtras<{ userId: string }>
|
|
10
|
+
> = ({ params }) => {
|
|
11
|
+
return HttpResponse.json({ userId: params.userId })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('info', () => {
|
|
15
|
+
test('exposes request handler information', () => {
|
|
16
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
17
|
+
|
|
18
|
+
expect(handler.info.header).toEqual('GET /user/:userId')
|
|
19
|
+
expect(handler.info.method).toEqual('GET')
|
|
20
|
+
expect(handler.info.path).toEqual('/user/:userId')
|
|
21
|
+
expect(handler.isUsed).toBe(false)
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('parse', () => {
|
|
26
|
+
test('parses a URL given a matching request', async () => {
|
|
27
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
28
|
+
const request = new Request(new URL('/user/abc-123', location.href))
|
|
29
|
+
|
|
30
|
+
expect(await handler.parse({ request })).toEqual({
|
|
31
|
+
match: {
|
|
32
|
+
matches: true,
|
|
33
|
+
params: {
|
|
34
|
+
userId: 'abc-123',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
cookies: {},
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('parses a URL and ignores the request method', async () => {
|
|
42
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
43
|
+
const request = new Request(new URL('/user/def-456', location.href), {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
expect(await handler.parse({ request })).toEqual({
|
|
48
|
+
match: {
|
|
49
|
+
matches: true,
|
|
50
|
+
params: {
|
|
51
|
+
userId: 'def-456',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
cookies: {},
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('returns negative match result given a non-matching request', async () => {
|
|
59
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
60
|
+
const request = new Request(new URL('/login', location.href))
|
|
61
|
+
|
|
62
|
+
expect(await handler.parse({ request })).toEqual({
|
|
63
|
+
match: {
|
|
64
|
+
matches: false,
|
|
65
|
+
params: {},
|
|
66
|
+
},
|
|
67
|
+
cookies: {},
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('predicate', () => {
|
|
73
|
+
test('returns true given a matching request', async () => {
|
|
74
|
+
const handler = new HttpHandler('POST', '/login', resolver)
|
|
75
|
+
const request = new Request(new URL('/login', location.href), {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
expect(
|
|
80
|
+
handler.predicate({
|
|
81
|
+
request,
|
|
82
|
+
parsedResult: await handler.parse({ request }),
|
|
83
|
+
}),
|
|
84
|
+
).toBe(true)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('respects RegExp as the request method', async () => {
|
|
88
|
+
const handler = new HttpHandler(/.+/, '/login', resolver)
|
|
89
|
+
const requests = [
|
|
90
|
+
new Request(new URL('/login', location.href)),
|
|
91
|
+
new Request(new URL('/login', location.href), { method: 'POST' }),
|
|
92
|
+
new Request(new URL('/login', location.href), { method: 'DELETE' }),
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
for (const request of requests) {
|
|
96
|
+
expect(
|
|
97
|
+
handler.predicate({
|
|
98
|
+
request,
|
|
99
|
+
parsedResult: await handler.parse({ request }),
|
|
100
|
+
}),
|
|
101
|
+
).toBe(true)
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('returns false given a non-matching request', async () => {
|
|
106
|
+
const handler = new HttpHandler('POST', '/login', resolver)
|
|
107
|
+
const request = new Request(new URL('/user/abc-123', location.href))
|
|
108
|
+
|
|
109
|
+
expect(
|
|
110
|
+
handler.predicate({
|
|
111
|
+
request,
|
|
112
|
+
parsedResult: await handler.parse({ request }),
|
|
113
|
+
}),
|
|
114
|
+
).toBe(false)
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('test', () => {
|
|
119
|
+
test('returns true given a matching request', async () => {
|
|
120
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
121
|
+
const firstTest = await handler.test({
|
|
122
|
+
request: new Request(new URL('/user/abc-123', location.href)),
|
|
123
|
+
})
|
|
124
|
+
const secondTest = await handler.test({
|
|
125
|
+
request: new Request(new URL('/user/def-456', location.href)),
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
expect(firstTest).toBe(true)
|
|
129
|
+
expect(secondTest).toBe(true)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('returns false given a non-matching request', async () => {
|
|
133
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
134
|
+
const firstTest = await handler.test({
|
|
135
|
+
request: new Request(new URL('/login', location.href)),
|
|
136
|
+
})
|
|
137
|
+
const secondTest = await handler.test({
|
|
138
|
+
request: new Request(new URL('/user/', location.href)),
|
|
139
|
+
})
|
|
140
|
+
const thirdTest = await handler.test({
|
|
141
|
+
request: new Request(new URL('/user/abc-123/extra', location.href)),
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
expect(firstTest).toBe(false)
|
|
145
|
+
expect(secondTest).toBe(false)
|
|
146
|
+
expect(thirdTest).toBe(false)
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
describe('run', () => {
|
|
151
|
+
test('returns a mocked response given a matching request', async () => {
|
|
152
|
+
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
153
|
+
const request = new Request(new URL('/user/abc-123', location.href))
|
|
154
|
+
const result = await handler.run({ request })
|
|
155
|
+
|
|
156
|
+
expect(result!.handler).toEqual(handler)
|
|
157
|
+
expect(result!.parsedResult).toEqual({
|
|
158
|
+
match: {
|
|
159
|
+
matches: true,
|
|
160
|
+
params: {
|
|
161
|
+
userId: 'abc-123',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
cookies: {},
|
|
165
|
+
})
|
|
166
|
+
expect(result!.request.method).toBe('GET')
|
|
167
|
+
expect(result!.request.url).toBe('http://localhost/user/abc-123')
|
|
168
|
+
expect(result!.response?.status).toBe(200)
|
|
169
|
+
expect(result!.response?.statusText).toBe('OK')
|
|
170
|
+
expect(await result?.response?.json()).toEqual({ userId: 'abc-123' })
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('returns null given a non-matching request', async () => {
|
|
174
|
+
const handler = new HttpHandler('POST', '/login', resolver)
|
|
175
|
+
const result = await handler.run({
|
|
176
|
+
request: new Request(new URL('/users', location.href)),
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
expect(result).toBeNull()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('returns an empty "params" object given request with no URL parameters', async () => {
|
|
183
|
+
const handler = new HttpHandler('GET', '/users', resolver)
|
|
184
|
+
const result = await handler.run({
|
|
185
|
+
request: new Request(new URL('/users', location.href)),
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
expect(result?.parsedResult?.match?.params).toEqual({})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('exhauses resolver until its generator completes', async () => {
|
|
192
|
+
const handler = new HttpHandler('GET', '/users', function* () {
|
|
193
|
+
let count = 0
|
|
194
|
+
|
|
195
|
+
while (count < 5) {
|
|
196
|
+
count += 1
|
|
197
|
+
yield HttpResponse.text('pending')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return HttpResponse.text('complete')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
const run = async () => {
|
|
204
|
+
const result = await handler.run({
|
|
205
|
+
request: new Request(new URL('/users', location.href)),
|
|
206
|
+
})
|
|
207
|
+
return result?.response?.text()
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
expect(await run()).toBe('pending')
|
|
211
|
+
expect(await run()).toBe('pending')
|
|
212
|
+
expect(await run()).toBe('pending')
|
|
213
|
+
expect(await run()).toBe('pending')
|
|
214
|
+
expect(await run()).toBe('pending')
|
|
215
|
+
expect(await run()).toBe('complete')
|
|
216
|
+
expect(await run()).toBe('complete')
|
|
217
|
+
})
|
|
218
|
+
})
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { ResponseResolutionContext } from '../utils/getResponse'
|
|
2
|
+
import { devUtils } from '../utils/internal/devUtils'
|
|
3
|
+
import { isStringEqual } from '../utils/internal/isStringEqual'
|
|
4
|
+
import { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'
|
|
5
|
+
import { getTimestamp } from '../utils/logging/getTimestamp'
|
|
6
|
+
import { serializeRequest } from '../utils/logging/serializeRequest'
|
|
7
|
+
import { serializeResponse } from '../utils/logging/serializeResponse'
|
|
8
|
+
import {
|
|
9
|
+
matchRequestUrl,
|
|
10
|
+
Match,
|
|
11
|
+
Path,
|
|
12
|
+
PathParams,
|
|
13
|
+
} from '../utils/matching/matchRequestUrl'
|
|
14
|
+
import { getPublicUrlFromRequest } from '../utils/request/getPublicUrlFromRequest'
|
|
15
|
+
import { getAllRequestCookies } from '../utils/request/getRequestCookies'
|
|
16
|
+
import { cleanUrl, getSearchParams } from '../utils/url/cleanUrl'
|
|
17
|
+
import {
|
|
18
|
+
RequestHandler,
|
|
19
|
+
RequestHandlerDefaultInfo,
|
|
20
|
+
RequestHandlerOptions,
|
|
21
|
+
ResponseResolver,
|
|
22
|
+
} from './RequestHandler'
|
|
23
|
+
|
|
24
|
+
type HttpHandlerMethod = string | RegExp
|
|
25
|
+
|
|
26
|
+
export interface HttpHandlerInfo extends RequestHandlerDefaultInfo {
|
|
27
|
+
method: HttpHandlerMethod
|
|
28
|
+
path: Path
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum HttpMethods {
|
|
32
|
+
HEAD = 'HEAD',
|
|
33
|
+
GET = 'GET',
|
|
34
|
+
POST = 'POST',
|
|
35
|
+
PUT = 'PUT',
|
|
36
|
+
PATCH = 'PATCH',
|
|
37
|
+
OPTIONS = 'OPTIONS',
|
|
38
|
+
DELETE = 'DELETE',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type RequestQuery = {
|
|
42
|
+
[queryName: string]: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type HttpRequestParsedResult = {
|
|
46
|
+
match: Match
|
|
47
|
+
cookies: Record<string, string>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type HttpRequestResolverExtras<Params extends PathParams> = {
|
|
51
|
+
params: Params
|
|
52
|
+
cookies: Record<string, string>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Request handler for HTTP requests.
|
|
57
|
+
* Provides request matching based on method and URL.
|
|
58
|
+
*/
|
|
59
|
+
export class HttpHandler extends RequestHandler<
|
|
60
|
+
HttpHandlerInfo,
|
|
61
|
+
HttpRequestParsedResult,
|
|
62
|
+
HttpRequestResolverExtras<any>
|
|
63
|
+
> {
|
|
64
|
+
constructor(
|
|
65
|
+
method: HttpHandlerMethod,
|
|
66
|
+
path: Path,
|
|
67
|
+
resolver: ResponseResolver<HttpRequestResolverExtras<any>, any, any>,
|
|
68
|
+
options?: RequestHandlerOptions,
|
|
69
|
+
) {
|
|
70
|
+
super({
|
|
71
|
+
info: {
|
|
72
|
+
header: `${method} ${path}`,
|
|
73
|
+
path,
|
|
74
|
+
method,
|
|
75
|
+
},
|
|
76
|
+
resolver,
|
|
77
|
+
options,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
this.checkRedundantQueryParameters()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private checkRedundantQueryParameters() {
|
|
84
|
+
const { method, path } = this.info
|
|
85
|
+
|
|
86
|
+
if (path instanceof RegExp) {
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const url = cleanUrl(path)
|
|
91
|
+
|
|
92
|
+
// Bypass request handler URLs that have no redundant characters.
|
|
93
|
+
if (url === path) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const searchParams = getSearchParams(path)
|
|
98
|
+
const queryParams: string[] = []
|
|
99
|
+
|
|
100
|
+
searchParams.forEach((_, paramName) => {
|
|
101
|
+
queryParams.push(paramName)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
devUtils.warn(
|
|
105
|
+
`Found a redundant usage of query parameters in the request handler URL for "${method} ${path}". Please match against a path instead and access query parameters in the response resolver function using "req.url.searchParams".`,
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async parse(args: {
|
|
110
|
+
request: Request
|
|
111
|
+
resolutionContext?: ResponseResolutionContext
|
|
112
|
+
}) {
|
|
113
|
+
const url = new URL(args.request.url)
|
|
114
|
+
const match = matchRequestUrl(
|
|
115
|
+
url,
|
|
116
|
+
this.info.path,
|
|
117
|
+
args.resolutionContext?.baseUrl,
|
|
118
|
+
)
|
|
119
|
+
const cookies = getAllRequestCookies(args.request)
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
match,
|
|
123
|
+
cookies,
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
predicate(args: { request: Request; parsedResult: HttpRequestParsedResult }) {
|
|
128
|
+
const hasMatchingMethod = this.matchMethod(args.request.method)
|
|
129
|
+
const hasMatchingUrl = args.parsedResult.match.matches
|
|
130
|
+
return hasMatchingMethod && hasMatchingUrl
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private matchMethod(actualMethod: string): boolean {
|
|
134
|
+
return this.info.method instanceof RegExp
|
|
135
|
+
? this.info.method.test(actualMethod)
|
|
136
|
+
: isStringEqual(this.info.method, actualMethod)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
protected extendResolverArgs(args: {
|
|
140
|
+
request: Request
|
|
141
|
+
parsedResult: HttpRequestParsedResult
|
|
142
|
+
}) {
|
|
143
|
+
return {
|
|
144
|
+
params: args.parsedResult.match?.params || {},
|
|
145
|
+
cookies: args.parsedResult.cookies,
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async log(args: { request: Request; response: Response }) {
|
|
150
|
+
const publicUrl = getPublicUrlFromRequest(args.request)
|
|
151
|
+
const loggedRequest = await serializeRequest(args.request)
|
|
152
|
+
const loggedResponse = await serializeResponse(args.response)
|
|
153
|
+
const statusColor = getStatusCodeColor(loggedResponse.status)
|
|
154
|
+
|
|
155
|
+
console.groupCollapsed(
|
|
156
|
+
devUtils.formatMessage(
|
|
157
|
+
`${getTimestamp()} ${args.request.method} ${publicUrl} (%c${
|
|
158
|
+
loggedResponse.status
|
|
159
|
+
} ${loggedResponse.statusText}%c)`,
|
|
160
|
+
),
|
|
161
|
+
`color:${statusColor}`,
|
|
162
|
+
'color:inherit',
|
|
163
|
+
)
|
|
164
|
+
console.log('Request', loggedRequest)
|
|
165
|
+
console.log('Handler:', this)
|
|
166
|
+
console.log('Response', loggedResponse)
|
|
167
|
+
console.groupEnd()
|
|
168
|
+
}
|
|
169
|
+
}
|