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.
@@ -2,7 +2,7 @@
2
2
  /* tslint:disable */
3
3
 
4
4
  /**
5
- * Mock Service Worker (2.1.3).
5
+ * Mock Service Worker (2.1.4).
6
6
  * @see https://github.com/mswjs/msw
7
7
  * - Please do NOT modify this file.
8
8
  * - Please do NOT serve this file on production.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msw",
3
- "version": "2.1.3",
3
+ "version": "2.1.4",
4
4
  "description": "Seamless REST/GraphQL API mocking library for browser and Node.js.",
5
5
  "main": "./lib/core/index.js",
6
6
  "module": "./lib/core/index.mjs",
@@ -93,13 +93,11 @@
93
93
  "sideEffects": false,
94
94
  "dependencies": {
95
95
  "@bundled-es-modules/cookie": "^2.0.0",
96
- "@bundled-es-modules/js-levenshtein": "^2.0.1",
97
96
  "@bundled-es-modules/statuses": "^1.0.1",
98
97
  "@mswjs/cookies": "^1.1.0",
99
98
  "@mswjs/interceptors": "^0.25.14",
100
99
  "@open-draft/until": "^2.1.0",
101
100
  "@types/cookie": "^0.6.0",
102
- "@types/js-levenshtein": "^1.1.3",
103
101
  "@types/statuses": "^2.0.4",
104
102
  "chalk": "^4.1.2",
105
103
  "chokidar": "^3.4.2",
@@ -107,7 +105,6 @@
107
105
  "headers-polyfill": "^4.0.2",
108
106
  "inquirer": "^8.2.0",
109
107
  "is-node-process": "^1.2.0",
110
- "js-levenshtein": "^1.1.6",
111
108
  "outvariant": "^1.4.2",
112
109
  "path-to-regexp": "^6.2.0",
113
110
  "strict-event-emitter": "^0.5.1",
@@ -82,7 +82,7 @@ export async function handleRequest(
82
82
  // If the handler lookup returned nothing, no request handler was found
83
83
  // matching this request. Report the request as unhandled.
84
84
  if (!lookupResult.data) {
85
- await onUnhandledRequest(request, handlers, options.onUnhandledRequest)
85
+ await onUnhandledRequest(request, options.onUnhandledRequest)
86
86
  emitter.emit('request:unhandled', { request, requestId })
87
87
  emitter.emit('request:end', { request, requestId })
88
88
  handleRequestOptions?.onPassthroughResponse?.(request)
@@ -5,10 +5,6 @@ import {
5
5
  onUnhandledRequest,
6
6
  UnhandledRequestCallback,
7
7
  } from './onUnhandledRequest'
8
- import { HttpHandler, HttpMethods } from '../../handlers/HttpHandler'
9
- import { ResponseResolver } from '../../handlers/RequestHandler'
10
-
11
- const resolver: ResponseResolver = () => void 0
12
8
 
13
9
  const fixtures = {
14
10
  warningWithoutSuggestions: `\
@@ -24,18 +20,6 @@ Read more: https://mswjs.io/docs/getting-started/mocks`,
24
20
 
25
21
  • GET /api
26
22
 
27
- If you still wish to intercept this unhandled request, please create a request handler for it.
28
- Read more: https://mswjs.io/docs/getting-started/mocks`,
29
-
30
- warningWithSuggestions: (suggestions: string) => `\
31
- [MSW] Warning: intercepted a request without a matching request handler:
32
-
33
- • GET /api
34
-
35
- Did you mean to request one of the following resources instead?
36
-
37
- ${suggestions}
38
-
39
23
  If you still wish to intercept this unhandled request, please create a request handler for it.
40
24
  Read more: https://mswjs.io/docs/getting-started/mocks`,
41
25
  }
@@ -52,7 +36,6 @@ afterEach(() => {
52
36
  test('supports the "bypass" request strategy', async () => {
53
37
  await onUnhandledRequest(
54
38
  new Request(new URL('http://localhost/api')),
55
- [],
56
39
  'bypass',
57
40
  )
58
41
 
@@ -61,22 +44,14 @@ test('supports the "bypass" request strategy', async () => {
61
44
  })
62
45
 
63
46
  test('supports the "warn" request strategy', async () => {
64
- await onUnhandledRequest(
65
- new Request(new URL('http://localhost/api')),
66
- [],
67
- 'warn',
68
- )
47
+ await onUnhandledRequest(new Request(new URL('http://localhost/api')), 'warn')
69
48
 
70
49
  expect(console.warn).toHaveBeenCalledWith(fixtures.warningWithoutSuggestions)
71
50
  })
72
51
 
73
52
  test('supports the "error" request strategy', async () => {
74
53
  await expect(
75
- onUnhandledRequest(
76
- new Request(new URL('http://localhost/api')),
77
- [],
78
- 'error',
79
- ),
54
+ onUnhandledRequest(new Request(new URL('http://localhost/api')), 'error'),
80
55
  ).rejects.toThrow(
81
56
  '[MSW] Cannot bypass a request when using the "error" strategy for the "onUnhandledRequest" option.',
82
57
  )
@@ -89,7 +64,7 @@ test('supports a custom callback function', async () => {
89
64
  console.warn(`callback: ${request.method} ${request.url}`)
90
65
  })
91
66
  const request = new Request(new URL('/user', 'http://localhost:3000'))
92
- await onUnhandledRequest(request, [], callback)
67
+ await onUnhandledRequest(request, callback)
93
68
 
94
69
  expect(callback).toHaveBeenCalledTimes(1)
95
70
  expect(callback).toHaveBeenCalledWith(request, {
@@ -111,7 +86,7 @@ test('supports calling default strategies from the custom callback function', as
111
86
  },
112
87
  )
113
88
  const request = new Request(new URL('http://localhost/api'))
114
- await expect(onUnhandledRequest(request, [], callback)).rejects.toThrow(
89
+ await expect(onUnhandledRequest(request, callback)).rejects.toThrow(
115
90
  `[MSW] Cannot bypass a request when using the "error" strategy for the "onUnhandledRequest" option.`,
116
91
  )
117
92
 
@@ -126,86 +101,15 @@ test('supports calling default strategies from the custom callback function', as
126
101
  })
127
102
 
128
103
  test('does not print any suggestions given no handlers to suggest', async () => {
129
- await onUnhandledRequest(
130
- new Request(new URL('http://localhost/api')),
131
- [],
132
- 'warn',
133
- )
134
-
135
- expect(console.warn).toHaveBeenCalledWith(fixtures.warningWithoutSuggestions)
136
- })
137
-
138
- test('does not print any suggestions given no handlers are similar', async () => {
139
- await onUnhandledRequest(
140
- new Request(new URL('http://localhost/api')),
141
- [
142
- // None of the defined request handlers match the actual request URL
143
- // to be used as suggestions.
144
- new HttpHandler(HttpMethods.GET, 'https://api.github.com', resolver),
145
- new HttpHandler(HttpMethods.GET, 'https://api.stripe.com', resolver),
146
- ],
147
- 'warn',
148
- )
104
+ await onUnhandledRequest(new Request(new URL('http://localhost/api')), 'warn')
149
105
 
150
106
  expect(console.warn).toHaveBeenCalledWith(fixtures.warningWithoutSuggestions)
151
107
  })
152
108
 
153
- test('respects RegExp as a request handler method', async () => {
154
- await onUnhandledRequest(
155
- new Request(new URL('http://localhost/api')),
156
- [new HttpHandler(/^GE/, 'http://localhost/api', resolver)],
157
- 'warn',
158
- )
159
-
160
- expect(console.warn).toHaveBeenCalledWith(fixtures.warningWithoutSuggestions)
161
- })
162
-
163
- test('sorts the suggestions by relevance', async () => {
164
- await onUnhandledRequest(
165
- new Request(new URL('http://localhost/api')),
166
- [
167
- new HttpHandler(HttpMethods.GET, '/', resolver),
168
- new HttpHandler(HttpMethods.GET, 'https://api.example.com/api', resolver),
169
- new HttpHandler(HttpMethods.POST, '/api', resolver),
170
- ],
171
- 'warn',
172
- )
173
-
174
- expect(console.warn).toHaveBeenCalledWith(
175
- fixtures.warningWithSuggestions(`\
176
- • POST /api
177
- • GET /`),
178
- )
179
- })
180
-
181
- test('does not print more than 4 suggestions', async () => {
182
- await onUnhandledRequest(
183
- new Request(new URL('http://localhost/api')),
184
- [
185
- new HttpHandler(HttpMethods.GET, '/ap', resolver),
186
- new HttpHandler(HttpMethods.GET, '/api', resolver),
187
- new HttpHandler(HttpMethods.GET, '/api-1', resolver),
188
- new HttpHandler(HttpMethods.GET, '/api-2', resolver),
189
- new HttpHandler(HttpMethods.GET, '/api-3', resolver),
190
- new HttpHandler(HttpMethods.GET, '/api-4', resolver),
191
- ],
192
- 'warn',
193
- )
194
-
195
- expect(console.warn).toHaveBeenCalledWith(
196
- fixtures.warningWithSuggestions(`\
197
- • GET /api
198
- • GET /ap
199
- • GET /api-1
200
- • GET /api-2`),
201
- )
202
- })
203
-
204
109
  test('throws an exception given unknown request strategy', async () => {
205
110
  await expect(
206
111
  onUnhandledRequest(
207
112
  new Request(new URL('http://localhost/api')),
208
- [],
209
113
  // @ts-expect-error Intentional unknown strategy.
210
114
  'invalid-strategy',
211
115
  ),
@@ -1,22 +1,6 @@
1
- import jsLevenshtein from '@bundled-es-modules/js-levenshtein'
2
- import { RequestHandler } from '../../handlers/RequestHandler'
3
- import { HttpHandler } from '../../handlers/HttpHandler'
4
- import { GraphQLHandler } from '../../handlers/GraphQLHandler'
5
- import {
6
- ParsedGraphQLQuery,
7
- ParsedGraphQLRequest,
8
- parseGraphQLRequest,
9
- } from '../internal/parseGraphQLRequest'
10
1
  import { getPublicUrlFromRequest } from './getPublicUrlFromRequest'
11
- import { isStringEqual } from '../internal/isStringEqual'
12
2
  import { devUtils } from '../internal/devUtils'
13
3
 
14
- const getStringMatchScore = jsLevenshtein
15
-
16
- const MAX_MATCH_SCORE = 3
17
- const MAX_SUGGESTION_COUNT = 4
18
- const TYPE_MATCH_DELTA = 0.5
19
-
20
4
  export interface UnhandledRequestPrint {
21
5
  warning(): void
22
6
  error(): void
@@ -33,183 +17,18 @@ export type UnhandledRequestStrategy =
33
17
  | 'error'
34
18
  | UnhandledRequestCallback
35
19
 
36
- interface RequestHandlerGroups {
37
- http: Array<HttpHandler>
38
- graphql: Array<GraphQLHandler>
39
- }
40
-
41
- function groupHandlersByType(
42
- handlers: Array<RequestHandler>,
43
- ): RequestHandlerGroups {
44
- return handlers.reduce<RequestHandlerGroups>(
45
- (groups, handler) => {
46
- if (handler instanceof HttpHandler) {
47
- groups.http.push(handler)
48
- }
49
-
50
- if (handler instanceof GraphQLHandler) {
51
- groups.graphql.push(handler)
52
- }
53
-
54
- return groups
55
- },
56
- {
57
- http: [],
58
- graphql: [],
59
- },
60
- )
61
- }
62
-
63
- type RequestHandlerSuggestion = [number, RequestHandler]
64
-
65
- type ScoreGetterFn<RequestHandlerType extends RequestHandler> = (
66
- request: Request,
67
- handler: RequestHandlerType,
68
- ) => number
69
-
70
- function getHttpHandlerScore(): ScoreGetterFn<HttpHandler> {
71
- return (request, handler) => {
72
- const { path, method } = handler.info
73
-
74
- if (path instanceof RegExp || method instanceof RegExp) {
75
- return Infinity
76
- }
77
-
78
- const hasSameMethod = isStringEqual(request.method, method)
79
-
80
- // Always treat a handler with the same method as a more similar one.
81
- const methodScoreDelta = hasSameMethod ? TYPE_MATCH_DELTA : 0
82
- const requestPublicUrl = getPublicUrlFromRequest(request)
83
- const score = getStringMatchScore(requestPublicUrl, path)
84
-
85
- return score - methodScoreDelta
86
- }
87
- }
88
-
89
- function getGraphQLHandlerScore(
90
- parsedQuery: ParsedGraphQLQuery,
91
- ): ScoreGetterFn<GraphQLHandler> {
92
- return (_, handler) => {
93
- if (typeof parsedQuery.operationName === 'undefined') {
94
- return Infinity
95
- }
96
-
97
- const { operationType, operationName } = handler.info
98
-
99
- if (typeof operationName !== 'string') {
100
- return Infinity
101
- }
102
-
103
- const hasSameOperationType = parsedQuery.operationType === operationType
104
- // Always treat a handler with the same operation type as a more similar one.
105
- const operationTypeScoreDelta = hasSameOperationType ? TYPE_MATCH_DELTA : 0
106
- const score = getStringMatchScore(parsedQuery.operationName, operationName)
107
-
108
- return score - operationTypeScoreDelta
109
- }
110
- }
111
-
112
- function getSuggestedHandler(
113
- request: Request,
114
- handlers: Array<HttpHandler> | Array<GraphQLHandler>,
115
- getScore: ScoreGetterFn<HttpHandler> | ScoreGetterFn<GraphQLHandler>,
116
- ): Array<RequestHandler> {
117
- const suggestedHandlers = (handlers as Array<RequestHandler>)
118
- .reduce<Array<RequestHandlerSuggestion>>((suggestions, handler) => {
119
- const score = getScore(request, handler as any)
120
- return suggestions.concat([[score, handler]])
121
- }, [])
122
- .sort(([leftScore], [rightScore]) => leftScore - rightScore)
123
- .filter(([score]) => score <= MAX_MATCH_SCORE)
124
- .slice(0, MAX_SUGGESTION_COUNT)
125
- .map(([, handler]) => handler)
126
-
127
- return suggestedHandlers
128
- }
129
-
130
- function getSuggestedHandlersMessage(handlers: RequestHandler[]) {
131
- if (handlers.length > 1) {
132
- return `\
133
- Did you mean to request one of the following resources instead?
134
-
135
- ${handlers.map((handler) => ` • ${handler.info.header}`).join('\n')}`
136
- }
137
-
138
- return `Did you mean to request "${handlers[0].info.header}" instead?`
139
- }
140
-
141
20
  export async function onUnhandledRequest(
142
21
  request: Request,
143
- handlers: Array<RequestHandler>,
144
22
  strategy: UnhandledRequestStrategy = 'warn',
145
23
  ): Promise<void> {
146
- const parsedGraphQLQuery = await parseGraphQLRequest(request).catch(
147
- () => null,
148
- )
149
24
  const publicUrl = getPublicUrlFromRequest(request)
150
-
151
- function generateHandlerSuggestion(): string {
152
- /**
153
- * @note Ignore exceptions during GraphQL request parsing because at this point
154
- * we cannot assume the unhandled request is a valid GraphQL request.
155
- * If the GraphQL parsing fails, just don't treat it as a GraphQL request.
156
- */
157
- const handlerGroups = groupHandlersByType(handlers)
158
- const relevantHandlers = parsedGraphQLQuery
159
- ? handlerGroups.graphql
160
- : handlerGroups.http
161
-
162
- const suggestedHandlers = getSuggestedHandler(
163
- request,
164
- relevantHandlers,
165
- parsedGraphQLQuery
166
- ? getGraphQLHandlerScore(parsedGraphQLQuery)
167
- : getHttpHandlerScore(),
168
- )
169
-
170
- return suggestedHandlers.length > 0
171
- ? getSuggestedHandlersMessage(suggestedHandlers)
172
- : ''
173
- }
174
-
175
- function getGraphQLRequestHeader(
176
- parsedGraphQLRequest: ParsedGraphQLRequest<any>,
177
- ): string {
178
- if (!parsedGraphQLRequest?.operationName) {
179
- return `anonymous ${parsedGraphQLRequest?.operationType} (${request.method} ${publicUrl})`
180
- }
181
-
182
- return `${parsedGraphQLRequest.operationType} ${parsedGraphQLRequest.operationName} (${request.method} ${publicUrl})`
183
- }
184
-
185
- function generateUnhandledRequestMessage(): string {
186
- const requestHeader = parsedGraphQLQuery
187
- ? getGraphQLRequestHeader(parsedGraphQLQuery)
188
- : `${request.method} ${publicUrl}`
189
- const handlerSuggestion = generateHandlerSuggestion()
190
-
191
- const messageTemplate = [
192
- `intercepted a request without a matching request handler:`,
193
- ` \u2022 ${requestHeader}`,
194
- handlerSuggestion,
195
- `\
196
- If you still wish to intercept this unhandled request, please create a request handler for it.
197
- Read more: https://mswjs.io/docs/getting-started/mocks\
198
- `,
199
- ].filter(Boolean)
200
- return messageTemplate.join('\n\n')
201
- }
25
+ 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`
202
26
 
203
27
  function applyStrategy(strategy: UnhandledRequestStrategy) {
204
- // Generate handler suggestions only when applying the strategy.
205
- // This saves bandwidth for scenarios when developers opt-out
206
- // from the default unhandled request handling strategy.
207
- const message = generateUnhandledRequestMessage()
208
-
209
28
  switch (strategy) {
210
29
  case 'error': {
211
30
  // Print a developer-friendly error.
212
- devUtils.error('Error: %s', message)
31
+ devUtils.error('Error: %s', unhandledRequestMessage)
213
32
 
214
33
  // Throw an exception to halt request processing and not perform the original request.
215
34
  throw new Error(
@@ -220,7 +39,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks\
220
39
  }
221
40
 
222
41
  case 'warn': {
223
- devUtils.warn('Warning: %s', message)
42
+ devUtils.warn('Warning: %s', unhandledRequestMessage)
224
43
  break
225
44
  }
226
45