msw 2.3.0-ws.rc-1 → 2.3.0-ws.rc-2
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/README.md +8 -3
- package/cli/init.js +1 -1
- package/lib/browser/index.d.mts +4 -4
- package/lib/browser/index.js +64 -59
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +64 -59
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/{GraphQLHandler-Cbu12sb0.d.ts → GraphQLHandler-3gvpA65n.d.ts} +3 -3
- package/lib/core/{GraphQLHandler-QGQY_9Rc.d.mts → GraphQLHandler-4DPdxG0R.d.mts} +3 -3
- package/lib/core/{HttpResponse-BWB1yDNM.d.mts → HttpResponse-aJY-D0oG.d.ts} +3 -3
- package/lib/core/{HttpResponse-DeJBWGN5.d.ts → HttpResponse-xuSipbNt.d.mts} +3 -3
- package/lib/core/HttpResponse.d.mts +1 -1
- package/lib/core/HttpResponse.d.ts +1 -1
- package/lib/core/HttpResponse.js.map +1 -1
- package/lib/core/HttpResponse.mjs.map +1 -1
- package/lib/core/SetupApi.d.mts +1 -1
- package/lib/core/SetupApi.d.ts +1 -1
- package/lib/core/bypass.js +6 -1
- package/lib/core/bypass.js.map +1 -1
- package/lib/core/bypass.mjs +6 -1
- package/lib/core/bypass.mjs.map +1 -1
- package/lib/core/getResponse.d.mts +1 -1
- package/lib/core/getResponse.d.ts +1 -1
- package/lib/core/getResponse.js +2 -2
- package/lib/core/getResponse.js.map +1 -1
- package/lib/core/getResponse.mjs +2 -2
- package/lib/core/getResponse.mjs.map +1 -1
- package/lib/core/graphql.d.mts +8 -6
- package/lib/core/graphql.d.ts +8 -6
- package/lib/core/graphql.js.map +1 -1
- package/lib/core/graphql.mjs.map +1 -1
- package/lib/core/handlers/GraphQLHandler.d.mts +2 -2
- package/lib/core/handlers/GraphQLHandler.d.ts +2 -2
- package/lib/core/handlers/GraphQLHandler.js.map +1 -1
- package/lib/core/handlers/GraphQLHandler.mjs.map +1 -1
- package/lib/core/handlers/HttpHandler.d.mts +1 -1
- package/lib/core/handlers/HttpHandler.d.ts +1 -1
- package/lib/core/handlers/HttpHandler.js +1 -1
- package/lib/core/handlers/HttpHandler.js.map +1 -1
- package/lib/core/handlers/HttpHandler.mjs +1 -1
- package/lib/core/handlers/HttpHandler.mjs.map +1 -1
- package/lib/core/handlers/RequestHandler.d.mts +1 -1
- package/lib/core/handlers/RequestHandler.d.ts +1 -1
- package/lib/core/handlers/WebSocketHandler.d.mts +11 -17
- package/lib/core/handlers/WebSocketHandler.d.ts +11 -17
- package/lib/core/handlers/WebSocketHandler.js +9 -12
- package/lib/core/handlers/WebSocketHandler.js.map +1 -1
- package/lib/core/handlers/WebSocketHandler.mjs +9 -12
- package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
- package/lib/core/http.d.mts +1 -1
- package/lib/core/http.d.ts +1 -1
- package/lib/core/index.d.mts +4 -4
- package/lib/core/index.d.ts +4 -4
- package/lib/core/index.js +2 -0
- package/lib/core/index.js.map +1 -1
- package/lib/core/index.mjs +4 -0
- package/lib/core/index.mjs.map +1 -1
- package/lib/core/passthrough.d.mts +1 -1
- package/lib/core/passthrough.d.ts +1 -1
- package/lib/core/typeUtils.d.mts +6 -1
- package/lib/core/typeUtils.d.ts +6 -1
- package/lib/core/typeUtils.js.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.mts +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.ts +1 -1
- package/lib/core/utils/HttpResponse/decorators.js +4 -1
- package/lib/core/utils/HttpResponse/decorators.js.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.mjs +4 -1
- package/lib/core/utils/HttpResponse/decorators.mjs.map +1 -1
- package/lib/core/utils/executeHandlers.d.mts +1 -1
- package/lib/core/utils/executeHandlers.d.ts +1 -1
- package/lib/core/utils/handleRequest.d.mts +1 -1
- package/lib/core/utils/handleRequest.d.ts +1 -1
- package/lib/core/utils/handleRequest.js.map +1 -1
- package/lib/core/utils/handleRequest.mjs.map +1 -1
- package/lib/core/utils/handleWebSocketEvent.d.mts +8 -2
- package/lib/core/utils/handleWebSocketEvent.d.ts +8 -2
- package/lib/core/utils/handleWebSocketEvent.js +20 -17
- package/lib/core/utils/handleWebSocketEvent.js.map +1 -1
- package/lib/core/utils/handleWebSocketEvent.mjs +21 -22
- package/lib/core/utils/handleWebSocketEvent.mjs.map +1 -1
- package/lib/core/utils/internal/mergeRight.js +15 -12
- package/lib/core/utils/internal/mergeRight.js.map +1 -1
- package/lib/core/utils/internal/mergeRight.mjs +15 -12
- package/lib/core/utils/internal/mergeRight.mjs.map +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +2 -2
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +2 -2
- package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
- package/lib/core/utils/internal/requestHandlerUtils.d.mts +1 -1
- package/lib/core/utils/internal/requestHandlerUtils.d.ts +1 -1
- package/lib/core/utils/logging/getTimestamp.d.mts +4 -1
- package/lib/core/utils/logging/getTimestamp.d.ts +4 -1
- package/lib/core/utils/logging/getTimestamp.js +6 -2
- package/lib/core/utils/logging/getTimestamp.js.map +1 -1
- package/lib/core/utils/logging/getTimestamp.mjs +6 -2
- package/lib/core/utils/logging/getTimestamp.mjs.map +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.d.mts +34 -0
- package/lib/core/ws/utils/attachWebSocketLogger.d.ts +34 -0
- package/lib/core/ws/utils/attachWebSocketLogger.js +211 -0
- package/lib/core/ws/utils/attachWebSocketLogger.js.map +1 -0
- package/lib/core/ws/utils/attachWebSocketLogger.mjs +191 -0
- package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +1 -0
- package/lib/core/ws/utils/getMessageLength.d.mts +11 -0
- package/lib/core/ws/utils/getMessageLength.d.ts +11 -0
- package/lib/core/ws/utils/getMessageLength.js +33 -0
- package/lib/core/ws/utils/getMessageLength.js.map +1 -0
- package/lib/core/ws/utils/getMessageLength.mjs +13 -0
- package/lib/core/ws/utils/getMessageLength.mjs.map +1 -0
- package/lib/core/ws/utils/getPublicData.d.mts +5 -0
- package/lib/core/ws/utils/getPublicData.d.ts +5 -0
- package/lib/core/ws/utils/getPublicData.js +36 -0
- package/lib/core/ws/utils/getPublicData.js.map +1 -0
- package/lib/core/ws/utils/getPublicData.mjs +16 -0
- package/lib/core/ws/utils/getPublicData.mjs.map +1 -0
- package/lib/core/ws/utils/truncateMessage.d.mts +3 -0
- package/lib/core/ws/utils/truncateMessage.d.ts +3 -0
- package/lib/core/{utils/internal/randomId.js → ws/utils/truncateMessage.js} +11 -7
- package/lib/core/ws/utils/truncateMessage.js.map +1 -0
- package/lib/core/ws/utils/truncateMessage.mjs +11 -0
- package/lib/core/ws/utils/truncateMessage.mjs.map +1 -0
- package/lib/iife/index.js +508 -231
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +8 -11
- package/lib/native/index.d.mts +4 -4
- package/lib/native/index.js +8 -2
- package/lib/native/index.js.map +1 -1
- package/lib/native/index.mjs +8 -2
- package/lib/native/index.mjs.map +1 -1
- package/lib/node/index.d.mts +6 -6
- package/lib/node/index.d.ts +2 -2
- package/lib/node/index.js +8 -2
- package/lib/node/index.js.map +1 -1
- package/lib/node/index.mjs +8 -2
- package/lib/node/index.mjs.map +1 -1
- package/package.json +8 -11
- package/src/browser/setupWorker/glossary.ts +4 -1
- package/src/browser/setupWorker/setupWorker.ts +19 -2
- package/src/browser/setupWorker/start/createRequestListener.ts +1 -1
- package/src/browser/setupWorker/start/createStartHandler.ts +9 -19
- package/src/browser/setupWorker/start/utils/createMessageChannel.ts +1 -1
- package/src/browser/utils/checkWorkerIntegrity.ts +34 -0
- package/src/core/HttpResponse.ts +3 -2
- package/src/core/bypass.test.ts +22 -0
- package/src/core/bypass.ts +9 -1
- package/src/core/getResponse.ts +2 -2
- package/src/core/graphql.ts +6 -3
- package/src/core/handlers/GraphQLHandler.test.ts +4 -5
- package/src/core/handlers/GraphQLHandler.ts +7 -4
- package/src/core/handlers/HttpHandler.test.ts +5 -5
- package/src/core/handlers/HttpHandler.ts +1 -1
- package/src/core/handlers/WebSocketHandler.ts +21 -39
- package/src/core/index.ts +6 -2
- package/src/core/typeUtils.ts +16 -10
- package/src/core/utils/HttpResponse/decorators.ts +8 -4
- package/src/core/utils/handleRequest.test.ts +14 -14
- package/src/core/utils/handleRequest.ts +1 -1
- package/src/core/utils/handleWebSocketEvent.ts +39 -29
- package/src/core/utils/internal/mergeRight.ts +16 -13
- package/src/core/utils/logging/getTimestamp.test.ts +20 -6
- package/src/core/utils/logging/getTimestamp.ts +11 -6
- package/src/core/ws/utils/attachWebSocketLogger.ts +262 -0
- package/src/core/ws/utils/getMessageLength.test.ts +16 -0
- package/src/core/ws/utils/getMessageLength.ts +19 -0
- package/src/core/ws/utils/getPublicData.test.ts +38 -0
- package/src/core/ws/utils/getPublicData.ts +17 -0
- package/src/core/ws/utils/truncateMessage.test.ts +12 -0
- package/src/core/ws/utils/truncateMessage.ts +9 -0
- package/src/mockServiceWorker.js +7 -10
- package/src/node/SetupServerApi.ts +4 -4
- package/src/node/SetupServerCommonApi.ts +6 -2
- package/src/node/glossary.ts +3 -3
- package/lib/core/utils/internal/randomId.d.mts +0 -3
- package/lib/core/utils/internal/randomId.d.ts +0 -3
- package/lib/core/utils/internal/randomId.js.map +0 -1
- package/lib/core/utils/internal/randomId.mjs +0 -7
- package/lib/core/utils/internal/randomId.mjs.map +0 -1
- package/src/browser/utils/requestIntegrityCheck.ts +0 -23
- package/src/core/utils/internal/randomId.ts +0 -3
package/src/core/bypass.test.ts
CHANGED
|
@@ -45,3 +45,25 @@ it('returns bypassed request given request instance', async () => {
|
|
|
45
45
|
'x-msw-intention': 'bypass',
|
|
46
46
|
})
|
|
47
47
|
})
|
|
48
|
+
|
|
49
|
+
it('allows modifying the bypassed request instance', async () => {
|
|
50
|
+
const original = new Request('http://localhost/resource', {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
body: 'hello world',
|
|
53
|
+
})
|
|
54
|
+
const request = bypass(original, {
|
|
55
|
+
method: 'PUT',
|
|
56
|
+
headers: { 'x-modified-header': 'yes' },
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
expect(request.method).toBe('PUT')
|
|
60
|
+
expect(Object.fromEntries(request.headers.entries())).toEqual({
|
|
61
|
+
'x-msw-intention': 'bypass',
|
|
62
|
+
'x-modified-header': 'yes',
|
|
63
|
+
})
|
|
64
|
+
expect(original.bodyUsed).toBe(false)
|
|
65
|
+
expect(request.bodyUsed).toBe(false)
|
|
66
|
+
|
|
67
|
+
expect(await request.text()).toBe('hello world')
|
|
68
|
+
expect(original.bodyUsed).toBe(false)
|
|
69
|
+
})
|
package/src/core/bypass.ts
CHANGED
|
@@ -15,7 +15,15 @@ export type BypassRequestInput = string | URL | Request
|
|
|
15
15
|
* @see {@link https://mswjs.io/docs/api/bypass `bypass()` API reference}
|
|
16
16
|
*/
|
|
17
17
|
export function bypass(input: BypassRequestInput, init?: RequestInit): Request {
|
|
18
|
-
|
|
18
|
+
// Always create a new Request instance.
|
|
19
|
+
// This way, the "init" modifications will propagate
|
|
20
|
+
// to the bypass request instance automatically.
|
|
21
|
+
const request = new Request(
|
|
22
|
+
// If given a Request instance, clone it not to exhaust
|
|
23
|
+
// the original request's body.
|
|
24
|
+
input instanceof Request ? input.clone() : input,
|
|
25
|
+
init,
|
|
26
|
+
)
|
|
19
27
|
|
|
20
28
|
invariant(
|
|
21
29
|
!request.bodyUsed,
|
package/src/core/getResponse.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { createRequestId } from '@mswjs/interceptors'
|
|
1
2
|
import type { RequestHandler } from './handlers/RequestHandler'
|
|
2
3
|
import { executeHandlers } from './utils/executeHandlers'
|
|
3
|
-
import { randomId } from './utils/internal/randomId'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Finds a response for the given request instance
|
|
@@ -15,7 +15,7 @@ export const getResponse = async (
|
|
|
15
15
|
): Promise<Response | undefined> => {
|
|
16
16
|
const result = await executeHandlers({
|
|
17
17
|
request,
|
|
18
|
-
requestId:
|
|
18
|
+
requestId: createRequestId(),
|
|
19
19
|
handlers,
|
|
20
20
|
})
|
|
21
21
|
|
package/src/core/graphql.ts
CHANGED
|
@@ -31,7 +31,10 @@ export type GraphQLRequestHandler = <
|
|
|
31
31
|
| GraphQLHandlerNameSelector
|
|
32
32
|
| DocumentNode
|
|
33
33
|
| TypedDocumentNode<Query, Variables>,
|
|
34
|
-
resolver: GraphQLResponseResolver<
|
|
34
|
+
resolver: GraphQLResponseResolver<
|
|
35
|
+
[Query] extends [never] ? GraphQLQuery : Query,
|
|
36
|
+
Variables
|
|
37
|
+
>,
|
|
35
38
|
options?: RequestHandlerOptions,
|
|
36
39
|
) => GraphQLHandler
|
|
37
40
|
|
|
@@ -41,7 +44,7 @@ export type GraphQLResponseResolver<
|
|
|
41
44
|
> = ResponseResolver<
|
|
42
45
|
GraphQLResolverExtras<Variables>,
|
|
43
46
|
null,
|
|
44
|
-
GraphQLResponseBody<Query>
|
|
47
|
+
GraphQLResponseBody<[Query] extends [never] ? GraphQLQuery : Query>
|
|
45
48
|
>
|
|
46
49
|
|
|
47
50
|
function createScopedGraphQLHandler(
|
|
@@ -61,7 +64,7 @@ function createScopedGraphQLHandler(
|
|
|
61
64
|
|
|
62
65
|
function createGraphQLOperationHandler(url: Path) {
|
|
63
66
|
return <
|
|
64
|
-
Query extends
|
|
67
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
65
68
|
Variables extends GraphQLVariables = GraphQLVariables,
|
|
66
69
|
>(
|
|
67
70
|
resolver: ResponseResolver<
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment jsdom
|
|
3
3
|
*/
|
|
4
|
-
import { encodeBuffer } from '@mswjs/interceptors'
|
|
4
|
+
import { createRequestId, encodeBuffer } from '@mswjs/interceptors'
|
|
5
5
|
import { OperationTypeNode, parse } from 'graphql'
|
|
6
6
|
import {
|
|
7
7
|
GraphQLHandler,
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
GraphQLResolverExtras,
|
|
10
10
|
isDocumentNode,
|
|
11
11
|
} from './GraphQLHandler'
|
|
12
|
-
import { randomId } from '../utils/internal/randomId'
|
|
13
12
|
import { HttpResponse } from '../HttpResponse'
|
|
14
13
|
import { ResponseResolver } from './RequestHandler'
|
|
15
14
|
|
|
@@ -737,7 +736,7 @@ describe('run', () => {
|
|
|
737
736
|
userId: 'abc-123',
|
|
738
737
|
},
|
|
739
738
|
})
|
|
740
|
-
const requestId =
|
|
739
|
+
const requestId = createRequestId()
|
|
741
740
|
const result = await handler.run({ request, requestId })
|
|
742
741
|
|
|
743
742
|
expect(result!.handler).toEqual(handler)
|
|
@@ -779,7 +778,7 @@ describe('run', () => {
|
|
|
779
778
|
const request = createPostGraphQLRequest({
|
|
780
779
|
query: LOGIN,
|
|
781
780
|
})
|
|
782
|
-
const requestId =
|
|
781
|
+
const requestId = createRequestId()
|
|
783
782
|
const result = await handler.run({ request, requestId })
|
|
784
783
|
|
|
785
784
|
expect(result).toBeNull()
|
|
@@ -827,7 +826,7 @@ describe('request', () => {
|
|
|
827
826
|
`,
|
|
828
827
|
})
|
|
829
828
|
|
|
830
|
-
const requestId =
|
|
829
|
+
const requestId = createRequestId()
|
|
831
830
|
await handler.run({ request, requestId })
|
|
832
831
|
|
|
833
832
|
expect(matchAllResolver).toHaveBeenCalledTimes(1)
|
|
@@ -68,10 +68,13 @@ export interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {
|
|
|
68
68
|
variables?: Variables
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
export type GraphQLResponseBody<BodyType extends DefaultBodyType> =
|
|
72
|
+
| {
|
|
73
|
+
data?: BodyType | null
|
|
74
|
+
errors?: readonly Partial<GraphQLError>[] | null
|
|
75
|
+
}
|
|
76
|
+
| null
|
|
77
|
+
| undefined
|
|
75
78
|
|
|
76
79
|
export function isDocumentNode(
|
|
77
80
|
value: DocumentNode | any,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @vitest-environment jsdom
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { createRequestId } from '@mswjs/interceptors'
|
|
5
5
|
import { HttpHandler, HttpRequestResolverExtras } from './HttpHandler'
|
|
6
6
|
import { HttpResponse } from '..'
|
|
7
7
|
import { ResponseResolver } from './RequestHandler'
|
|
@@ -152,7 +152,7 @@ describe('run', () => {
|
|
|
152
152
|
test('returns a mocked response given a matching request', async () => {
|
|
153
153
|
const handler = new HttpHandler('GET', '/user/:userId', resolver)
|
|
154
154
|
const request = new Request(new URL('/user/abc-123', location.href))
|
|
155
|
-
const requestId =
|
|
155
|
+
const requestId = createRequestId()
|
|
156
156
|
const result = await handler.run({ request, requestId })
|
|
157
157
|
|
|
158
158
|
expect(result!.handler).toEqual(handler)
|
|
@@ -176,7 +176,7 @@ describe('run', () => {
|
|
|
176
176
|
const handler = new HttpHandler('POST', '/login', resolver)
|
|
177
177
|
const result = await handler.run({
|
|
178
178
|
request: new Request(new URL('/users', location.href)),
|
|
179
|
-
requestId:
|
|
179
|
+
requestId: createRequestId(),
|
|
180
180
|
})
|
|
181
181
|
|
|
182
182
|
expect(result).toBeNull()
|
|
@@ -186,7 +186,7 @@ describe('run', () => {
|
|
|
186
186
|
const handler = new HttpHandler('GET', '/users', resolver)
|
|
187
187
|
const result = await handler.run({
|
|
188
188
|
request: new Request(new URL('/users', location.href)),
|
|
189
|
-
requestId:
|
|
189
|
+
requestId: createRequestId(),
|
|
190
190
|
})
|
|
191
191
|
|
|
192
192
|
expect(result?.parsedResult?.match?.params).toEqual({})
|
|
@@ -207,7 +207,7 @@ describe('run', () => {
|
|
|
207
207
|
const run = async () => {
|
|
208
208
|
const result = await handler.run({
|
|
209
209
|
request: new Request(new URL('/users', location.href)),
|
|
210
|
-
requestId:
|
|
210
|
+
requestId: createRequestId(),
|
|
211
211
|
})
|
|
212
212
|
return result?.response?.text()
|
|
213
213
|
}
|
|
@@ -102,7 +102,7 @@ export class HttpHandler extends RequestHandler<
|
|
|
102
102
|
})
|
|
103
103
|
|
|
104
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
|
|
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 using "new URL(request.url).searchParams" instead. Learn more: https://mswjs.io/docs/recipes/query-parameters`,
|
|
106
106
|
)
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -1,47 +1,41 @@
|
|
|
1
1
|
import { Emitter } from 'strict-event-emitter'
|
|
2
|
-
import type {
|
|
3
|
-
WebSocketClientConnection,
|
|
4
|
-
WebSocketServerConnection,
|
|
5
|
-
} from '@mswjs/interceptors/WebSocket'
|
|
2
|
+
import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'
|
|
6
3
|
import {
|
|
7
4
|
type Match,
|
|
8
5
|
type Path,
|
|
9
6
|
type PathParams,
|
|
10
7
|
matchRequestUrl,
|
|
11
8
|
} from '../utils/matching/matchRequestUrl'
|
|
9
|
+
import { getCallFrame } from '../utils/internal/getCallFrame'
|
|
12
10
|
|
|
13
11
|
type WebSocketHandlerParsedResult = {
|
|
14
12
|
match: Match
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
export type WebSocketHandlerEventMap = {
|
|
18
|
-
connection: [
|
|
19
|
-
args: {
|
|
20
|
-
client: WebSocketClientConnection
|
|
21
|
-
server: WebSocketServerConnection
|
|
22
|
-
params: PathParams
|
|
23
|
-
},
|
|
24
|
-
]
|
|
16
|
+
connection: [args: WebSocketHandlerConnection]
|
|
25
17
|
}
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}>
|
|
19
|
+
interface WebSocketHandlerConnection extends WebSocketConnectionData {
|
|
20
|
+
params: PathParams
|
|
21
|
+
}
|
|
31
22
|
|
|
32
23
|
export const kEmitter = Symbol('kEmitter')
|
|
33
24
|
export const kDispatchEvent = Symbol('kDispatchEvent')
|
|
34
|
-
export const
|
|
25
|
+
export const kSender = Symbol('kSender')
|
|
35
26
|
|
|
36
27
|
export class WebSocketHandler {
|
|
28
|
+
public callFrame?: string
|
|
29
|
+
|
|
37
30
|
protected [kEmitter]: Emitter<WebSocketHandlerEventMap>
|
|
38
31
|
|
|
39
32
|
constructor(private readonly url: Path) {
|
|
40
33
|
this[kEmitter] = new Emitter()
|
|
34
|
+
this.callFrame = getCallFrame(new Error())
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
public parse(args: {
|
|
44
|
-
event:
|
|
38
|
+
event: MessageEvent<WebSocketConnectionData>
|
|
45
39
|
}): WebSocketHandlerParsedResult {
|
|
46
40
|
const connection = args.event.data
|
|
47
41
|
const match = matchRequestUrl(connection.client.url, this.url)
|
|
@@ -52,38 +46,26 @@ export class WebSocketHandler {
|
|
|
52
46
|
}
|
|
53
47
|
|
|
54
48
|
public predicate(args: {
|
|
55
|
-
event:
|
|
49
|
+
event: MessageEvent<WebSocketConnectionData>
|
|
56
50
|
parsedResult: WebSocketHandlerParsedResult
|
|
57
51
|
}): boolean {
|
|
58
52
|
return args.parsedResult.match.matches
|
|
59
53
|
}
|
|
60
54
|
|
|
61
|
-
async [kDispatchEvent](
|
|
55
|
+
async [kDispatchEvent](
|
|
56
|
+
event: MessageEvent<WebSocketConnectionData>,
|
|
57
|
+
): Promise<void> {
|
|
62
58
|
const parsedResult = this.parse({ event })
|
|
63
|
-
const shouldIntercept = this.predicate({ event, parsedResult })
|
|
64
|
-
|
|
65
|
-
if (!shouldIntercept) {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Account for other matching event handlers that've already prevented this event.
|
|
70
|
-
if (!Reflect.get(event, kDefaultPrevented)) {
|
|
71
|
-
// At this point, the WebSocket connection URL has matched the handler.
|
|
72
|
-
// Prevent the default behavior of establishing the connection as-is.
|
|
73
|
-
// Use internal symbol because we aren't actually dispatching this
|
|
74
|
-
// event. Events can only marked as cancelable and can be prevented
|
|
75
|
-
// when dispatched on an EventTarget.
|
|
76
|
-
Reflect.set(event, kDefaultPrevented, true)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
59
|
const connection = event.data
|
|
80
60
|
|
|
81
|
-
|
|
82
|
-
// This is what the developer adds listeners for.
|
|
83
|
-
this[kEmitter].emit('connection', {
|
|
61
|
+
const resolvedConnection: WebSocketHandlerConnection = {
|
|
84
62
|
client: connection.client,
|
|
85
63
|
server: connection.server,
|
|
86
64
|
params: parsedResult.match.params || {},
|
|
87
|
-
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Emit the connection event on the handler.
|
|
68
|
+
// This is what the developer adds listeners for.
|
|
69
|
+
this[kEmitter].emit('connection', resolvedConnection)
|
|
88
70
|
}
|
|
89
71
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -2,15 +2,19 @@ import { checkGlobals } from './utils/internal/checkGlobals'
|
|
|
2
2
|
|
|
3
3
|
export { SetupApi } from './SetupApi'
|
|
4
4
|
|
|
5
|
-
/*
|
|
5
|
+
/* HTTP handlers */
|
|
6
6
|
export { RequestHandler } from './handlers/RequestHandler'
|
|
7
7
|
export { http } from './http'
|
|
8
8
|
export { HttpHandler, HttpMethods } from './handlers/HttpHandler'
|
|
9
9
|
export { graphql } from './graphql'
|
|
10
10
|
export { GraphQLHandler } from './handlers/GraphQLHandler'
|
|
11
11
|
|
|
12
|
-
/* WebSocket */
|
|
12
|
+
/* WebSocket handler */
|
|
13
13
|
export { ws } from './ws/ws'
|
|
14
|
+
export {
|
|
15
|
+
WebSocketHandler,
|
|
16
|
+
type WebSocketHandlerEventMap,
|
|
17
|
+
} from './handlers/WebSocketHandler'
|
|
14
18
|
|
|
15
19
|
/* Utils */
|
|
16
20
|
export { matchRequestUrl } from './utils/matching/matchRequestUrl'
|
package/src/core/typeUtils.ts
CHANGED
|
@@ -8,13 +8,19 @@ export type RequiredDeep<
|
|
|
8
8
|
> = Type extends Fn
|
|
9
9
|
? Type
|
|
10
10
|
: /**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
* @note The "Fn" type satisfies the predicate below.
|
|
12
|
+
* It must always come first, before the Record check.
|
|
13
|
+
*/
|
|
14
|
+
Type extends Record<string, any>
|
|
15
|
+
? {
|
|
16
|
+
[Key in keyof Type]-?: NonNullable<Type[Key]> extends NonNullable<U>
|
|
17
|
+
? NonNullable<Type[Key]>
|
|
18
|
+
: RequiredDeep<NonNullable<Type[Key]>, U>
|
|
19
|
+
}
|
|
20
|
+
: Type
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @fixme Remove this once TS 5.4 is the lowest supported version.
|
|
24
|
+
* Because "NoInfer" is a built-in type utility there.
|
|
25
|
+
*/
|
|
26
|
+
export type NoInfer<T> = [T][T extends any ? 0 : never]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import statuses from '@bundled-es-modules/statuses'
|
|
2
2
|
import type { HttpResponseInit } from '../../HttpResponse'
|
|
3
|
+
import { Headers as HeadersPolyfill } from 'headers-polyfill'
|
|
3
4
|
|
|
4
5
|
const { message } = statuses
|
|
5
6
|
|
|
@@ -40,10 +41,13 @@ export function decorateResponse(
|
|
|
40
41
|
// Cookie forwarding is only relevant in the browser.
|
|
41
42
|
if (typeof document !== 'undefined') {
|
|
42
43
|
// Write the mocked response cookies to the document.
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
44
|
+
// Use `headers-polyfill` to get the Set-Cookie header value correctly.
|
|
45
|
+
// This is an alternative until TypeScript 5.2
|
|
46
|
+
// and Node.js v20 become the minimum supported version
|
|
47
|
+
// and getSetCookie in Headers can be used directly.
|
|
48
|
+
const responseCookies = HeadersPolyfill.prototype.getSetCookie.call(
|
|
49
|
+
init.headers,
|
|
50
|
+
)
|
|
47
51
|
|
|
48
52
|
for (const cookieString of responseCookies) {
|
|
49
53
|
// No need to parse the cookie headers because it's defined
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* @vitest-environment jsdom
|
|
3
3
|
*/
|
|
4
4
|
import { Emitter } from 'strict-event-emitter'
|
|
5
|
+
import { createRequestId } from '@mswjs/interceptors'
|
|
5
6
|
import { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
|
|
6
7
|
import { RequestHandler } from '../handlers/RequestHandler'
|
|
7
8
|
import { http } from '../http'
|
|
8
9
|
import { handleRequest, HandleRequestOptions } from './handleRequest'
|
|
9
10
|
import { RequiredDeep } from '../typeUtils'
|
|
10
|
-
import { randomId } from './internal/randomId'
|
|
11
11
|
import { HttpResponse } from '../HttpResponse'
|
|
12
12
|
import { passthrough } from '../passthrough'
|
|
13
13
|
|
|
@@ -51,7 +51,7 @@ afterEach(() => {
|
|
|
51
51
|
test('returns undefined for a request with the "x-msw-intention" header equal to "bypass"', async () => {
|
|
52
52
|
const { emitter, events } = setup()
|
|
53
53
|
|
|
54
|
-
const requestId =
|
|
54
|
+
const requestId = createRequestId()
|
|
55
55
|
const request = new Request(new URL('http://localhost/user'), {
|
|
56
56
|
headers: new Headers({
|
|
57
57
|
'x-msw-intention': 'bypass',
|
|
@@ -97,7 +97,7 @@ test('does not bypass a request with "x-msw-intention" header set to arbitrary v
|
|
|
97
97
|
|
|
98
98
|
const result = await handleRequest(
|
|
99
99
|
request,
|
|
100
|
-
|
|
100
|
+
createRequestId(),
|
|
101
101
|
handlers,
|
|
102
102
|
options,
|
|
103
103
|
emitter,
|
|
@@ -112,7 +112,7 @@ test('does not bypass a request with "x-msw-intention" header set to arbitrary v
|
|
|
112
112
|
test('reports request as unhandled when it has no matching request handlers', async () => {
|
|
113
113
|
const { emitter, events } = setup()
|
|
114
114
|
|
|
115
|
-
const requestId =
|
|
115
|
+
const requestId = createRequestId()
|
|
116
116
|
const request = new Request(new URL('http://localhost/user'))
|
|
117
117
|
const handlers: Array<RequestHandler> = []
|
|
118
118
|
|
|
@@ -145,7 +145,7 @@ test('reports request as unhandled when it has no matching request handlers', as
|
|
|
145
145
|
test('returns undefined on a request handler that returns no response', async () => {
|
|
146
146
|
const { emitter, events } = setup()
|
|
147
147
|
|
|
148
|
-
const requestId =
|
|
148
|
+
const requestId = createRequestId()
|
|
149
149
|
const request = new Request(new URL('http://localhost/user'))
|
|
150
150
|
const handlers: Array<RequestHandler> = [
|
|
151
151
|
http.get('/user', () => {
|
|
@@ -184,7 +184,7 @@ test('returns undefined on a request handler that returns no response', async ()
|
|
|
184
184
|
test('returns the mocked response for a request with a matching request handler', async () => {
|
|
185
185
|
const { emitter, events } = setup()
|
|
186
186
|
|
|
187
|
-
const requestId =
|
|
187
|
+
const requestId = createRequestId()
|
|
188
188
|
const request = new Request(new URL('http://localhost/user'))
|
|
189
189
|
const mockedResponse = HttpResponse.json({ firstName: 'John' })
|
|
190
190
|
const handlers: Array<RequestHandler> = [
|
|
@@ -242,7 +242,7 @@ test('returns the mocked response for a request with a matching request handler'
|
|
|
242
242
|
test('returns a transformed response if the "transformResponse" option is provided', async () => {
|
|
243
243
|
const { emitter, events } = setup()
|
|
244
244
|
|
|
245
|
-
const requestId =
|
|
245
|
+
const requestId = createRequestId()
|
|
246
246
|
const request = new Request(new URL('http://localhost/user'))
|
|
247
247
|
const mockedResponse = HttpResponse.json({ firstName: 'John' })
|
|
248
248
|
const handlers: Array<RequestHandler> = [
|
|
@@ -325,7 +325,7 @@ test('returns a transformed response if the "transformResponse" option is provid
|
|
|
325
325
|
it('returns undefined without warning on a passthrough request', async () => {
|
|
326
326
|
const { emitter, events } = setup()
|
|
327
327
|
|
|
328
|
-
const requestId =
|
|
328
|
+
const requestId = createRequestId()
|
|
329
329
|
const request = new Request(new URL('http://localhost/user'))
|
|
330
330
|
const handlers: Array<RequestHandler> = [
|
|
331
331
|
http.get('/user', () => {
|
|
@@ -358,7 +358,7 @@ it('returns undefined without warning on a passthrough request', async () => {
|
|
|
358
358
|
it('calls the handler with the requestId', async () => {
|
|
359
359
|
const { emitter } = setup()
|
|
360
360
|
|
|
361
|
-
const requestId =
|
|
361
|
+
const requestId = createRequestId()
|
|
362
362
|
const request = new Request(new URL('http://localhost/user'))
|
|
363
363
|
const handlerFn = vi.fn()
|
|
364
364
|
const handlers: Array<RequestHandler> = [http.get('/user', handlerFn)]
|
|
@@ -390,7 +390,7 @@ it('marks the first matching one-time handler as used', async () => {
|
|
|
390
390
|
})
|
|
391
391
|
const handlers: Array<RequestHandler> = [oneTimeHandler, anotherHandler]
|
|
392
392
|
|
|
393
|
-
const requestId =
|
|
393
|
+
const requestId = createRequestId()
|
|
394
394
|
const request = new Request('http://localhost/resource')
|
|
395
395
|
const firstResult = await handleRequest(
|
|
396
396
|
request,
|
|
@@ -438,7 +438,7 @@ it('does not mark non-matching one-time handlers as used', async () => {
|
|
|
438
438
|
)
|
|
439
439
|
const handlers: Array<RequestHandler> = [oneTimeHandler, anotherHandler]
|
|
440
440
|
|
|
441
|
-
const requestId =
|
|
441
|
+
const requestId = createRequestId()
|
|
442
442
|
const firstResult = await handleRequest(
|
|
443
443
|
new Request('http://localhost/another'),
|
|
444
444
|
requestId,
|
|
@@ -481,7 +481,7 @@ it('handles parallel requests with one-time handlers', async () => {
|
|
|
481
481
|
})
|
|
482
482
|
const handlers: Array<RequestHandler> = [oneTimeHandler, anotherHandler]
|
|
483
483
|
|
|
484
|
-
const requestId =
|
|
484
|
+
const requestId = createRequestId()
|
|
485
485
|
const request = new Request('http://localhost/resource')
|
|
486
486
|
const firstResultPromise = handleRequest(
|
|
487
487
|
request,
|
|
@@ -526,7 +526,7 @@ describe('[Private] - resolutionContext - used for extensions', () => {
|
|
|
526
526
|
|
|
527
527
|
const handlers: Array<RequestHandler> = [handler]
|
|
528
528
|
|
|
529
|
-
const requestId =
|
|
529
|
+
const requestId = createRequestId()
|
|
530
530
|
const request = new Request(new URL('/resource', baseUrl))
|
|
531
531
|
const response = await handleRequest(
|
|
532
532
|
request,
|
|
@@ -555,7 +555,7 @@ describe('[Private] - resolutionContext - used for extensions', () => {
|
|
|
555
555
|
|
|
556
556
|
const handlers: Array<RequestHandler> = [handler]
|
|
557
557
|
|
|
558
|
-
const requestId =
|
|
558
|
+
const requestId = createRequestId()
|
|
559
559
|
const request = new Request(
|
|
560
560
|
new URL('/resource', `http://not-the-base-url.com`),
|
|
561
561
|
)
|
|
@@ -51,7 +51,7 @@ export async function handleRequest(
|
|
|
51
51
|
): Promise<Response | undefined> {
|
|
52
52
|
emitter.emit('request:start', { request, requestId })
|
|
53
53
|
|
|
54
|
-
// Perform bypassed requests (i.e.
|
|
54
|
+
// Perform bypassed requests (i.e. wrapped in "bypass()") as-is.
|
|
55
55
|
if (request.headers.get('x-msw-intention') === 'bypass') {
|
|
56
56
|
emitter.emit('request:end', { request, requestId })
|
|
57
57
|
handleRequestOptions?.onPassthroughResponse?.(request)
|
|
@@ -1,45 +1,55 @@
|
|
|
1
|
+
import type { WebSocketConnectionData } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket'
|
|
1
2
|
import { RequestHandler } from '../handlers/RequestHandler'
|
|
2
|
-
import {
|
|
3
|
-
WebSocketHandler,
|
|
4
|
-
kDefaultPrevented,
|
|
5
|
-
kDispatchEvent,
|
|
6
|
-
} from '../handlers/WebSocketHandler'
|
|
3
|
+
import { WebSocketHandler, kDispatchEvent } from '../handlers/WebSocketHandler'
|
|
7
4
|
import { webSocketInterceptor } from '../ws/webSocketInterceptor'
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
)
|
|
6
|
+
interface HandleWebSocketEventOptions {
|
|
7
|
+
getHandlers: () => Array<RequestHandler | WebSocketHandler>
|
|
8
|
+
onMockedConnection: (connection: WebSocketConnectionData) => void
|
|
9
|
+
onPassthroughConnection: (onnection: WebSocketConnectionData) => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function handleWebSocketEvent(options: HandleWebSocketEventOptions) {
|
|
12
13
|
webSocketInterceptor.on('connection', (connection) => {
|
|
13
|
-
const handlers =
|
|
14
|
+
const handlers = options.getHandlers()
|
|
14
15
|
|
|
15
16
|
const connectionEvent = new MessageEvent('connection', {
|
|
16
17
|
data: connection,
|
|
17
|
-
/**
|
|
18
|
-
* @note This message event should be marked as "cancelable"
|
|
19
|
-
* to have its default prevented using "event.preventDefault()".
|
|
20
|
-
* There's a bug in Node.js that breaks the "cancelable" flag.
|
|
21
|
-
* @see https://github.com/nodejs/node/issues/51767
|
|
22
|
-
*/
|
|
23
18
|
})
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
// First, filter only those WebSocket handlers that
|
|
21
|
+
// match the "ws.link()" endpoint predicate. Don't dispatch
|
|
22
|
+
// anything yet so the logger can be attached to the connection
|
|
23
|
+
// before it potentially sends events.
|
|
24
|
+
const matchingHandlers = handlers.filter<WebSocketHandler>(
|
|
25
|
+
(handler): handler is WebSocketHandler => {
|
|
26
|
+
if (handler instanceof WebSocketHandler) {
|
|
27
|
+
return handler.predicate({
|
|
28
|
+
event: connectionEvent,
|
|
29
|
+
parsedResult: handler.parse({
|
|
30
|
+
event: connectionEvent,
|
|
31
|
+
}),
|
|
32
|
+
})
|
|
33
|
+
}
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
return false
|
|
36
|
+
},
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if (matchingHandlers.length > 0) {
|
|
40
|
+
options?.onMockedConnection(connection)
|
|
41
|
+
|
|
42
|
+
// Iterate over the handlers and forward the connection
|
|
43
|
+
// event to WebSocket event handlers. This is equivalent
|
|
44
|
+
// to dispatching that event onto multiple listeners.
|
|
45
|
+
for (const handler of matchingHandlers) {
|
|
36
46
|
handler[kDispatchEvent](connectionEvent)
|
|
37
47
|
}
|
|
38
|
-
}
|
|
48
|
+
} else {
|
|
49
|
+
options?.onPassthroughConnection(connection)
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (!Reflect.get(connectionEvent, kDefaultPrevented)) {
|
|
51
|
+
// If none of the "ws" handlers matched,
|
|
52
|
+
// establish the WebSocket connection as-is.
|
|
43
53
|
connection.server.connect()
|
|
44
54
|
connection.client.addEventListener('message', (event) => {
|
|
45
55
|
connection.server.send(event.data)
|
|
@@ -8,20 +8,23 @@ export function mergeRight(
|
|
|
8
8
|
left: Record<string, any>,
|
|
9
9
|
right: Record<string, any>,
|
|
10
10
|
) {
|
|
11
|
-
return Object.entries(right).reduce(
|
|
12
|
-
|
|
11
|
+
return Object.entries(right).reduce(
|
|
12
|
+
(result, [key, rightValue]) => {
|
|
13
|
+
const leftValue = result[key]
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
if (Array.isArray(leftValue) && Array.isArray(rightValue)) {
|
|
16
|
+
result[key] = leftValue.concat(rightValue)
|
|
17
|
+
return result
|
|
18
|
+
}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
if (isObject(leftValue) && isObject(rightValue)) {
|
|
21
|
+
result[key] = mergeRight(leftValue, rightValue)
|
|
22
|
+
return result
|
|
23
|
+
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
result[key] = rightValue
|
|
26
|
+
return result
|
|
27
|
+
},
|
|
28
|
+
Object.assign({}, left),
|
|
29
|
+
)
|
|
27
30
|
}
|