msw 2.2.13 → 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/cli/init.js +0 -0
- package/config/scripts/postinstall.js +0 -0
- package/lib/browser/index.d.mts +7 -6
- package/lib/browser/index.d.ts +7 -6
- package/lib/browser/index.js +26 -7
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +26 -7
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/{GraphQLHandler-bom2Dn82.d.ts → GraphQLHandler-3gvpA65n.d.ts} +1 -1
- package/lib/core/{GraphQLHandler-yJ_I6j54.d.mts → GraphQLHandler-4DPdxG0R.d.mts} +1 -1
- package/lib/core/{HttpResponse-vQNlixkj.d.ts → HttpResponse-aJY-D0oG.d.ts} +2 -2
- package/lib/core/{HttpResponse-3-NyzyF7.d.mts → HttpResponse-xuSipbNt.d.mts} +2 -2
- package/lib/core/HttpResponse.d.mts +1 -1
- package/lib/core/HttpResponse.d.ts +1 -1
- package/lib/core/SetupApi.d.mts +15 -12
- package/lib/core/SetupApi.d.ts +15 -12
- package/lib/core/SetupApi.js +3 -1
- package/lib/core/SetupApi.js.map +1 -1
- package/lib/core/SetupApi.mjs +3 -1
- package/lib/core/SetupApi.mjs.map +1 -1
- package/lib/core/getResponse.d.mts +1 -1
- package/lib/core/getResponse.d.ts +1 -1
- package/lib/core/graphql.d.mts +2 -2
- package/lib/core/graphql.d.ts +2 -2
- package/lib/core/handlers/GraphQLHandler.d.mts +2 -2
- package/lib/core/handlers/GraphQLHandler.d.ts +2 -2
- package/lib/core/handlers/HttpHandler.d.mts +1 -1
- package/lib/core/handlers/HttpHandler.d.ts +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 +32 -0
- package/lib/core/handlers/WebSocketHandler.d.ts +32 -0
- package/lib/core/handlers/WebSocketHandler.js +62 -0
- package/lib/core/handlers/WebSocketHandler.js.map +1 -0
- package/lib/core/handlers/WebSocketHandler.mjs +44 -0
- package/lib/core/handlers/WebSocketHandler.mjs.map +1 -0
- package/lib/core/http.d.mts +1 -1
- package/lib/core/http.d.ts +1 -1
- package/lib/core/index.d.mts +5 -2
- package/lib/core/index.d.ts +5 -2
- package/lib/core/index.js +5 -1
- package/lib/core/index.js.map +1 -1
- package/lib/core/index.mjs +7 -1
- 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/utils/HttpResponse/decorators.d.mts +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.ts +1 -1
- package/lib/core/utils/executeHandlers.d.mts +1 -1
- package/lib/core/utils/executeHandlers.d.ts +1 -1
- package/lib/core/utils/executeHandlers.js +4 -0
- package/lib/core/utils/executeHandlers.js.map +1 -1
- package/lib/core/utils/executeHandlers.mjs +6 -0
- package/lib/core/utils/executeHandlers.mjs.map +1 -1
- package/lib/core/utils/handleRequest.d.mts +2 -2
- package/lib/core/utils/handleRequest.d.ts +2 -2
- 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 +16 -0
- package/lib/core/utils/handleWebSocketEvent.d.ts +16 -0
- package/lib/core/utils/handleWebSocketEvent.js +59 -0
- package/lib/core/utils/handleWebSocketEvent.js.map +1 -0
- package/lib/core/utils/handleWebSocketEvent.mjs +39 -0
- package/lib/core/utils/handleWebSocketEvent.mjs.map +1 -0
- 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/utils/matching/matchRequestUrl.d.mts +2 -1
- package/lib/core/utils/matching/matchRequestUrl.d.ts +2 -1
- package/lib/core/utils/matching/matchRequestUrl.js +4 -0
- package/lib/core/utils/matching/matchRequestUrl.js.map +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs +4 -0
- package/lib/core/utils/matching/matchRequestUrl.mjs.map +1 -1
- package/lib/core/ws/WebSocketClientManager.d.mts +64 -0
- package/lib/core/ws/WebSocketClientManager.d.ts +64 -0
- package/lib/core/ws/WebSocketClientManager.js +123 -0
- package/lib/core/ws/WebSocketClientManager.js.map +1 -0
- package/lib/core/ws/WebSocketClientManager.mjs +103 -0
- package/lib/core/ws/WebSocketClientManager.mjs.map +1 -0
- 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/ws/utils/truncateMessage.js +31 -0
- 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/core/ws/webSocketInterceptor.d.mts +5 -0
- package/lib/core/ws/webSocketInterceptor.d.ts +5 -0
- package/lib/core/ws/webSocketInterceptor.js +26 -0
- package/lib/core/ws/webSocketInterceptor.js.map +1 -0
- package/lib/core/ws/webSocketInterceptor.mjs +6 -0
- package/lib/core/ws/webSocketInterceptor.mjs.map +1 -0
- package/lib/core/ws/ws.d.mts +44 -0
- package/lib/core/ws/ws.d.ts +44 -0
- package/lib/core/ws/ws.js +82 -0
- package/lib/core/ws/ws.js.map +1 -0
- package/lib/core/ws/ws.mjs +65 -0
- package/lib/core/ws/ws.mjs.map +1 -0
- package/lib/iife/index.js +967 -11
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/lib/native/index.d.mts +6 -5
- package/lib/native/index.d.ts +6 -5
- package/lib/native/index.js +13 -0
- package/lib/native/index.js.map +1 -1
- package/lib/native/index.mjs +13 -0
- package/lib/native/index.mjs.map +1 -1
- package/lib/node/index.d.mts +8 -7
- package/lib/node/index.d.ts +8 -7
- package/lib/node/index.js +13 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/index.mjs +13 -0
- package/lib/node/index.mjs.map +1 -1
- package/package.json +26 -21
- package/src/browser/setupWorker/glossary.ts +10 -10
- package/src/browser/setupWorker/setupWorker.ts +34 -3
- package/src/core/SetupApi.ts +28 -20
- package/src/core/handlers/WebSocketHandler.ts +71 -0
- package/src/core/index.ts +8 -1
- package/src/core/utils/executeHandlers.ts +6 -2
- package/src/core/utils/handleRequest.ts +1 -2
- package/src/core/utils/handleWebSocketEvent.ts +59 -0
- package/src/core/utils/logging/getTimestamp.test.ts +20 -6
- package/src/core/utils/logging/getTimestamp.ts +11 -6
- package/src/core/utils/matching/matchRequestUrl.test.ts +44 -0
- package/src/core/utils/matching/matchRequestUrl.ts +4 -0
- package/src/core/ws/WebSocketClientManager.test.ts +159 -0
- package/src/core/ws/WebSocketClientManager.ts +170 -0
- 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/core/ws/webSocketInterceptor.ts +3 -0
- package/src/core/ws/ws.test.ts +23 -0
- package/src/core/ws/ws.ts +108 -0
- package/src/node/SetupServerApi.ts +8 -7
- package/src/node/SetupServerCommonApi.ts +14 -1
- package/src/node/glossary.ts +5 -7
- package/src/node/setupServer.ts +2 -1
|
@@ -5,13 +5,11 @@ import {
|
|
|
5
5
|
SharedOptions,
|
|
6
6
|
} from '~/core/sharedOptions'
|
|
7
7
|
import { ServiceWorkerMessage } from './start/utils/createMessageChannel'
|
|
8
|
-
import {
|
|
9
|
-
RequestHandler,
|
|
10
|
-
RequestHandlerDefaultInfo,
|
|
11
|
-
} from '~/core/handlers/RequestHandler'
|
|
8
|
+
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
12
9
|
import type { HttpRequestEventMap, Interceptor } from '@mswjs/interceptors'
|
|
13
|
-
import { Path } from '~/core/utils/matching/matchRequestUrl'
|
|
14
|
-
import { RequiredDeep } from '~/core/typeUtils'
|
|
10
|
+
import type { Path } from '~/core/utils/matching/matchRequestUrl'
|
|
11
|
+
import type { RequiredDeep } from '~/core/typeUtils'
|
|
12
|
+
import type { WebSocketHandler } from '~/core/handlers/WebSocketHandler'
|
|
15
13
|
|
|
16
14
|
export type ResolvedPath = Path | URL
|
|
17
15
|
|
|
@@ -87,7 +85,7 @@ export interface SetupWorkerInternalContext {
|
|
|
87
85
|
startOptions: RequiredDeep<StartOptions>
|
|
88
86
|
worker: ServiceWorker | null
|
|
89
87
|
registration: ServiceWorkerRegistration | null
|
|
90
|
-
getRequestHandlers(): Array<RequestHandler>
|
|
88
|
+
getRequestHandlers(): Array<RequestHandler | WebSocketHandler>
|
|
91
89
|
requests: Map<string, Request>
|
|
92
90
|
emitter: Emitter<LifeCycleEventsMap>
|
|
93
91
|
keepAliveInterval?: number
|
|
@@ -211,7 +209,7 @@ export interface SetupWorker {
|
|
|
211
209
|
*
|
|
212
210
|
* @see {@link https://mswjs.io/docs/api/setup-worker/use `worker.use()` API reference}
|
|
213
211
|
*/
|
|
214
|
-
use: (...handlers: RequestHandler
|
|
212
|
+
use: (...handlers: Array<RequestHandler | WebSocketHandler>) => void
|
|
215
213
|
|
|
216
214
|
/**
|
|
217
215
|
* Marks all request handlers that respond using `res.once()` as unused.
|
|
@@ -226,14 +224,16 @@ export interface SetupWorker {
|
|
|
226
224
|
*
|
|
227
225
|
* @see {@link https://mswjs.io/docs/api/setup-worker/reset-handlers `worker.resetHandlers()` API reference}
|
|
228
226
|
*/
|
|
229
|
-
resetHandlers: (
|
|
227
|
+
resetHandlers: (
|
|
228
|
+
...nextHandlers: Array<RequestHandler | WebSocketHandler>
|
|
229
|
+
) => void
|
|
230
230
|
|
|
231
231
|
/**
|
|
232
232
|
* Returns a readonly list of currently active request handlers.
|
|
233
233
|
*
|
|
234
234
|
* @see {@link https://mswjs.io/docs/api/setup-worker/list-handlers `worker.listHandlers()` API reference}
|
|
235
235
|
*/
|
|
236
|
-
listHandlers(): ReadonlyArray<RequestHandler
|
|
236
|
+
listHandlers(): ReadonlyArray<RequestHandler | WebSocketHandler>
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
239
|
* Life-cycle events.
|
|
@@ -18,9 +18,13 @@ import { createFallbackStop } from './stop/createFallbackStop'
|
|
|
18
18
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
19
19
|
import { SetupApi } from '~/core/SetupApi'
|
|
20
20
|
import { mergeRight } from '~/core/utils/internal/mergeRight'
|
|
21
|
-
import { LifeCycleEventsMap } from '~/core/sharedOptions'
|
|
21
|
+
import type { LifeCycleEventsMap } from '~/core/sharedOptions'
|
|
22
|
+
import type { WebSocketHandler } from '~/core/handlers/WebSocketHandler'
|
|
22
23
|
import { SetupWorker } from './glossary'
|
|
23
24
|
import { supportsReadableStreamTransfer } from '../utils/supportsReadableStreamTransfer'
|
|
25
|
+
import { webSocketInterceptor } from '~/core/ws/webSocketInterceptor'
|
|
26
|
+
import { handleWebSocketEvent } from '~/core/utils/handleWebSocketEvent'
|
|
27
|
+
import { attachWebSocketLogger } from '~/core/ws/utils/attachWebSocketLogger'
|
|
24
28
|
|
|
25
29
|
interface Listener {
|
|
26
30
|
target: EventTarget
|
|
@@ -37,7 +41,7 @@ export class SetupWorkerApi
|
|
|
37
41
|
private stopHandler: StopHandler = null as any
|
|
38
42
|
private listeners: Array<Listener>
|
|
39
43
|
|
|
40
|
-
constructor(...handlers: Array<RequestHandler>) {
|
|
44
|
+
constructor(...handlers: Array<RequestHandler | WebSocketHandler>) {
|
|
41
45
|
super(...handlers)
|
|
42
46
|
|
|
43
47
|
invariant(
|
|
@@ -176,6 +180,31 @@ export class SetupWorkerApi
|
|
|
176
180
|
options,
|
|
177
181
|
) as SetupWorkerInternalContext['startOptions']
|
|
178
182
|
|
|
183
|
+
// Enable WebSocket interception.
|
|
184
|
+
handleWebSocketEvent({
|
|
185
|
+
getHandlers: () => {
|
|
186
|
+
return this.handlersController.currentHandlers()
|
|
187
|
+
},
|
|
188
|
+
onMockedConnection: (connection) => {
|
|
189
|
+
if (!this.context.startOptions.quiet) {
|
|
190
|
+
// Attach the logger for mocked connections since
|
|
191
|
+
// those won't be visible in the browser's devtools.
|
|
192
|
+
attachWebSocketLogger(connection)
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
onPassthroughConnection() {
|
|
196
|
+
/**
|
|
197
|
+
* @fixme Call some "onUnhandledConnection".
|
|
198
|
+
*/
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
webSocketInterceptor.apply()
|
|
203
|
+
|
|
204
|
+
this.subscriptions.push(() => {
|
|
205
|
+
webSocketInterceptor.dispose()
|
|
206
|
+
})
|
|
207
|
+
|
|
179
208
|
return await this.startHandler(this.context.startOptions, options)
|
|
180
209
|
}
|
|
181
210
|
|
|
@@ -193,6 +222,8 @@ export class SetupWorkerApi
|
|
|
193
222
|
*
|
|
194
223
|
* @see {@link https://mswjs.io/docs/api/setup-worker `setupWorker()` API reference}
|
|
195
224
|
*/
|
|
196
|
-
export function setupWorker(
|
|
225
|
+
export function setupWorker(
|
|
226
|
+
...handlers: Array<RequestHandler | WebSocketHandler>
|
|
227
|
+
): SetupWorker {
|
|
197
228
|
return new SetupWorkerApi(...handlers)
|
|
198
229
|
}
|
package/src/core/SetupApi.ts
CHANGED
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
import { invariant } from 'outvariant'
|
|
2
2
|
import { EventMap, Emitter } from 'strict-event-emitter'
|
|
3
|
-
import {
|
|
4
|
-
RequestHandler,
|
|
5
|
-
RequestHandlerDefaultInfo,
|
|
6
|
-
} from './handlers/RequestHandler'
|
|
3
|
+
import { RequestHandler } from './handlers/RequestHandler'
|
|
7
4
|
import { LifeCycleEventEmitter } from './sharedOptions'
|
|
8
5
|
import { devUtils } from './utils/internal/devUtils'
|
|
9
6
|
import { pipeEvents } from './utils/internal/pipeEvents'
|
|
10
7
|
import { toReadonlyArray } from './utils/internal/toReadonlyArray'
|
|
11
8
|
import { Disposable } from './utils/internal/Disposable'
|
|
9
|
+
import type { WebSocketHandler } from './handlers/WebSocketHandler'
|
|
12
10
|
|
|
13
11
|
export abstract class HandlersController {
|
|
14
|
-
abstract prepend(
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
abstract prepend(
|
|
13
|
+
runtimeHandlers: Array<RequestHandler | WebSocketHandler>,
|
|
14
|
+
): void
|
|
15
|
+
abstract reset(nextHandles: Array<RequestHandler | WebSocketHandler>): void
|
|
16
|
+
abstract currentHandlers(): Array<RequestHandler | WebSocketHandler>
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export class InMemoryHandlersController implements HandlersController {
|
|
20
|
-
private handlers: Array<RequestHandler>
|
|
20
|
+
private handlers: Array<RequestHandler | WebSocketHandler>
|
|
21
21
|
|
|
22
|
-
constructor(
|
|
22
|
+
constructor(
|
|
23
|
+
private initialHandlers: Array<RequestHandler | WebSocketHandler>,
|
|
24
|
+
) {
|
|
23
25
|
this.handlers = [...initialHandlers]
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
public prepend(
|
|
28
|
+
public prepend(
|
|
29
|
+
runtimeHandles: Array<RequestHandler | WebSocketHandler>,
|
|
30
|
+
): void {
|
|
27
31
|
this.handlers.unshift(...runtimeHandles)
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
public reset(nextHandlers: Array<RequestHandler>): void {
|
|
34
|
+
public reset(nextHandlers: Array<RequestHandler | WebSocketHandler>): void {
|
|
31
35
|
this.handlers =
|
|
32
36
|
nextHandlers.length > 0 ? [...nextHandlers] : [...this.initialHandlers]
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
public currentHandlers(): Array<RequestHandler> {
|
|
39
|
+
public currentHandlers(): Array<RequestHandler | WebSocketHandler> {
|
|
36
40
|
return this.handlers
|
|
37
41
|
}
|
|
38
42
|
}
|
|
@@ -47,7 +51,7 @@ export abstract class SetupApi<EventsMap extends EventMap> extends Disposable {
|
|
|
47
51
|
|
|
48
52
|
public readonly events: LifeCycleEventEmitter<EventsMap>
|
|
49
53
|
|
|
50
|
-
constructor(...initialHandlers: Array<RequestHandler>) {
|
|
54
|
+
constructor(...initialHandlers: Array<RequestHandler | WebSocketHandler>) {
|
|
51
55
|
super()
|
|
52
56
|
|
|
53
57
|
invariant(
|
|
@@ -71,12 +75,14 @@ export abstract class SetupApi<EventsMap extends EventMap> extends Disposable {
|
|
|
71
75
|
})
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
private validateHandlers(handlers: ReadonlyArray<
|
|
78
|
+
private validateHandlers(handlers: ReadonlyArray<unknown>): boolean {
|
|
75
79
|
// Guard against incorrect call signature of the setup API.
|
|
76
80
|
return handlers.every((handler) => !Array.isArray(handler))
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
public use(
|
|
83
|
+
public use(
|
|
84
|
+
...runtimeHandlers: Array<RequestHandler | WebSocketHandler>
|
|
85
|
+
): void {
|
|
80
86
|
invariant(
|
|
81
87
|
this.validateHandlers(runtimeHandlers),
|
|
82
88
|
devUtils.formatMessage(
|
|
@@ -89,17 +95,19 @@ export abstract class SetupApi<EventsMap extends EventMap> extends Disposable {
|
|
|
89
95
|
|
|
90
96
|
public restoreHandlers(): void {
|
|
91
97
|
this.handlersController.currentHandlers().forEach((handler) => {
|
|
92
|
-
|
|
98
|
+
if ('isUsed' in handler) {
|
|
99
|
+
handler.isUsed = false
|
|
100
|
+
}
|
|
93
101
|
})
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
public resetHandlers(
|
|
104
|
+
public resetHandlers(
|
|
105
|
+
...nextHandlers: Array<RequestHandler | WebSocketHandler>
|
|
106
|
+
): void {
|
|
97
107
|
this.handlersController.reset(nextHandlers)
|
|
98
108
|
}
|
|
99
109
|
|
|
100
|
-
public listHandlers(): ReadonlyArray<
|
|
101
|
-
RequestHandler<RequestHandlerDefaultInfo, any, any>
|
|
102
|
-
> {
|
|
110
|
+
public listHandlers(): ReadonlyArray<RequestHandler | WebSocketHandler> {
|
|
103
111
|
return toReadonlyArray(this.handlersController.currentHandlers())
|
|
104
112
|
}
|
|
105
113
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Emitter } from 'strict-event-emitter'
|
|
2
|
+
import type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'
|
|
3
|
+
import {
|
|
4
|
+
type Match,
|
|
5
|
+
type Path,
|
|
6
|
+
type PathParams,
|
|
7
|
+
matchRequestUrl,
|
|
8
|
+
} from '../utils/matching/matchRequestUrl'
|
|
9
|
+
import { getCallFrame } from '../utils/internal/getCallFrame'
|
|
10
|
+
|
|
11
|
+
type WebSocketHandlerParsedResult = {
|
|
12
|
+
match: Match
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type WebSocketHandlerEventMap = {
|
|
16
|
+
connection: [args: WebSocketHandlerConnection]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface WebSocketHandlerConnection extends WebSocketConnectionData {
|
|
20
|
+
params: PathParams
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const kEmitter = Symbol('kEmitter')
|
|
24
|
+
export const kDispatchEvent = Symbol('kDispatchEvent')
|
|
25
|
+
export const kSender = Symbol('kSender')
|
|
26
|
+
|
|
27
|
+
export class WebSocketHandler {
|
|
28
|
+
public callFrame?: string
|
|
29
|
+
|
|
30
|
+
protected [kEmitter]: Emitter<WebSocketHandlerEventMap>
|
|
31
|
+
|
|
32
|
+
constructor(private readonly url: Path) {
|
|
33
|
+
this[kEmitter] = new Emitter()
|
|
34
|
+
this.callFrame = getCallFrame(new Error())
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public parse(args: {
|
|
38
|
+
event: MessageEvent<WebSocketConnectionData>
|
|
39
|
+
}): WebSocketHandlerParsedResult {
|
|
40
|
+
const connection = args.event.data
|
|
41
|
+
const match = matchRequestUrl(connection.client.url, this.url)
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
match,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public predicate(args: {
|
|
49
|
+
event: MessageEvent<WebSocketConnectionData>
|
|
50
|
+
parsedResult: WebSocketHandlerParsedResult
|
|
51
|
+
}): boolean {
|
|
52
|
+
return args.parsedResult.match.matches
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async [kDispatchEvent](
|
|
56
|
+
event: MessageEvent<WebSocketConnectionData>,
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
const parsedResult = this.parse({ event })
|
|
59
|
+
const connection = event.data
|
|
60
|
+
|
|
61
|
+
const resolvedConnection: WebSocketHandlerConnection = {
|
|
62
|
+
client: connection.client,
|
|
63
|
+
server: connection.server,
|
|
64
|
+
params: parsedResult.match.params || {},
|
|
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)
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/core/index.ts
CHANGED
|
@@ -2,13 +2,20 @@ 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 handler */
|
|
13
|
+
export { ws } from './ws/ws'
|
|
14
|
+
export {
|
|
15
|
+
WebSocketHandler,
|
|
16
|
+
type WebSocketHandlerEventMap,
|
|
17
|
+
} from './handlers/WebSocketHandler'
|
|
18
|
+
|
|
12
19
|
/* Utils */
|
|
13
20
|
export { matchRequestUrl } from './utils/matching/matchRequestUrl'
|
|
14
21
|
export * from './utils/handleRequest'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RequestHandler,
|
|
3
|
-
RequestHandlerExecutionResult,
|
|
3
|
+
type RequestHandlerExecutionResult,
|
|
4
4
|
} from '../handlers/RequestHandler'
|
|
5
5
|
|
|
6
6
|
export interface HandlersExecutionResult {
|
|
@@ -18,7 +18,7 @@ export interface ResponseResolutionContext {
|
|
|
18
18
|
* Returns the execution result object containing any matching request
|
|
19
19
|
* handler and any mocked response it returned.
|
|
20
20
|
*/
|
|
21
|
-
export const executeHandlers = async <Handlers extends Array<
|
|
21
|
+
export const executeHandlers = async <Handlers extends Array<unknown>>({
|
|
22
22
|
request,
|
|
23
23
|
requestId,
|
|
24
24
|
handlers,
|
|
@@ -33,6 +33,10 @@ export const executeHandlers = async <Handlers extends Array<RequestHandler>>({
|
|
|
33
33
|
let result: RequestHandlerExecutionResult<any> | null = null
|
|
34
34
|
|
|
35
35
|
for (const handler of handlers) {
|
|
36
|
+
if (!(handler instanceof RequestHandler)) {
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
result = await handler.run({ request, requestId, resolutionContext })
|
|
37
41
|
|
|
38
42
|
// If the handler produces some result for this request,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { until } from '@open-draft/until'
|
|
2
2
|
import { Emitter } from 'strict-event-emitter'
|
|
3
|
-
import { RequestHandler } from '../handlers/RequestHandler'
|
|
4
3
|
import { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
|
|
5
4
|
import { RequiredDeep } from '../typeUtils'
|
|
6
5
|
import { HandlersExecutionResult, executeHandlers } from './executeHandlers'
|
|
@@ -45,7 +44,7 @@ export interface HandleRequestOptions {
|
|
|
45
44
|
export async function handleRequest(
|
|
46
45
|
request: Request,
|
|
47
46
|
requestId: string,
|
|
48
|
-
handlers: Array<
|
|
47
|
+
handlers: Array<unknown>,
|
|
49
48
|
options: RequiredDeep<SharedOptions>,
|
|
50
49
|
emitter: Emitter<LifeCycleEventsMap>,
|
|
51
50
|
handleRequestOptions?: HandleRequestOptions,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { WebSocketConnectionData } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket'
|
|
2
|
+
import { RequestHandler } from '../handlers/RequestHandler'
|
|
3
|
+
import { WebSocketHandler, kDispatchEvent } from '../handlers/WebSocketHandler'
|
|
4
|
+
import { webSocketInterceptor } from '../ws/webSocketInterceptor'
|
|
5
|
+
|
|
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) {
|
|
13
|
+
webSocketInterceptor.on('connection', (connection) => {
|
|
14
|
+
const handlers = options.getHandlers()
|
|
15
|
+
|
|
16
|
+
const connectionEvent = new MessageEvent('connection', {
|
|
17
|
+
data: connection,
|
|
18
|
+
})
|
|
19
|
+
|
|
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
|
+
}
|
|
34
|
+
|
|
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) {
|
|
46
|
+
handler[kDispatchEvent](connectionEvent)
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
options?.onPassthroughConnection(connection)
|
|
50
|
+
|
|
51
|
+
// If none of the "ws" handlers matched,
|
|
52
|
+
// establish the WebSocket connection as-is.
|
|
53
|
+
connection.server.connect()
|
|
54
|
+
connection.client.addEventListener('message', (event) => {
|
|
55
|
+
connection.server.send(event.data)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import { getTimestamp } from './getTimestamp'
|
|
2
2
|
|
|
3
3
|
beforeAll(() => {
|
|
4
|
-
|
|
5
|
-
// to always produce a predictable value for testing purposes.
|
|
6
|
-
vi.spyOn(global.Date.prototype, 'getHours').mockImplementation(() => 12)
|
|
7
|
-
vi.spyOn(global.Date.prototype, 'getMinutes').mockImplementation(() => 4)
|
|
8
|
-
vi.spyOn(global.Date.prototype, 'getSeconds').mockImplementation(() => 8)
|
|
4
|
+
vi.useFakeTimers()
|
|
9
5
|
})
|
|
10
6
|
|
|
11
7
|
afterAll(() => {
|
|
12
|
-
vi.
|
|
8
|
+
vi.useRealTimers()
|
|
13
9
|
})
|
|
14
10
|
|
|
15
11
|
test('returns a timestamp string of the invocation time', () => {
|
|
12
|
+
vi.setSystemTime(new Date('2024-01-01 12:4:8'))
|
|
16
13
|
const timestamp = getTimestamp()
|
|
17
14
|
expect(timestamp).toBe('12:04:08')
|
|
18
15
|
})
|
|
16
|
+
|
|
17
|
+
test('returns a timestamp with milliseconds', () => {
|
|
18
|
+
vi.setSystemTime(new Date('2024-01-01 12:4:8'))
|
|
19
|
+
expect(getTimestamp({ milliseconds: true })).toBe('12:04:08.000')
|
|
20
|
+
|
|
21
|
+
vi.setSystemTime(new Date('2024-01-01 12:4:8.000'))
|
|
22
|
+
expect(getTimestamp({ milliseconds: true })).toBe('12:04:08.000')
|
|
23
|
+
|
|
24
|
+
vi.setSystemTime(new Date('2024-01-01 12:4:8.4'))
|
|
25
|
+
expect(getTimestamp({ milliseconds: true })).toBe('12:04:08.400')
|
|
26
|
+
|
|
27
|
+
vi.setSystemTime(new Date('2024-01-01 12:4:8.123'))
|
|
28
|
+
expect(getTimestamp({ milliseconds: true })).toBe('12:04:08.123')
|
|
29
|
+
|
|
30
|
+
vi.setSystemTime(new Date('2024-01-01 12:00:00'))
|
|
31
|
+
expect(getTimestamp({ milliseconds: true })).toBe('12:00:00.000')
|
|
32
|
+
})
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
interface GetTimestampOptions {
|
|
2
|
+
milliseconds?: boolean
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* Returns a timestamp string in a "HH:MM:SS" format.
|
|
3
7
|
*/
|
|
4
|
-
export function getTimestamp(): string {
|
|
8
|
+
export function getTimestamp(options?: GetTimestampOptions): string {
|
|
5
9
|
const now = new Date()
|
|
10
|
+
const timestamp = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`
|
|
11
|
+
|
|
12
|
+
if (options?.milliseconds) {
|
|
13
|
+
return `${timestamp}.${now.getMilliseconds().toString().padStart(3, '0')}`
|
|
14
|
+
}
|
|
6
15
|
|
|
7
|
-
return
|
|
8
|
-
.map(String)
|
|
9
|
-
.map((chunk) => chunk.slice(0, 2))
|
|
10
|
-
.map((chunk) => chunk.padStart(2, '0'))
|
|
11
|
-
.join(':')
|
|
16
|
+
return timestamp
|
|
12
17
|
}
|
|
@@ -61,6 +61,50 @@ describe('matchRequestUrl', () => {
|
|
|
61
61
|
expect(match).toHaveProperty('matches', false)
|
|
62
62
|
expect(match).toHaveProperty('params', {})
|
|
63
63
|
})
|
|
64
|
+
|
|
65
|
+
test('returns true for matching WebSocket URL', () => {
|
|
66
|
+
expect(
|
|
67
|
+
matchRequestUrl(new URL('ws://test.mswjs.io'), 'ws://test.mswjs.io'),
|
|
68
|
+
).toEqual({
|
|
69
|
+
matches: true,
|
|
70
|
+
params: {},
|
|
71
|
+
})
|
|
72
|
+
expect(
|
|
73
|
+
matchRequestUrl(new URL('wss://test.mswjs.io'), 'wss://test.mswjs.io'),
|
|
74
|
+
).toEqual({
|
|
75
|
+
matches: true,
|
|
76
|
+
params: {},
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('returns false for non-matching WebSocket URL', () => {
|
|
81
|
+
expect(
|
|
82
|
+
matchRequestUrl(new URL('ws://test.mswjs.io'), 'ws://foo.mswjs.io'),
|
|
83
|
+
).toEqual({
|
|
84
|
+
matches: false,
|
|
85
|
+
params: {},
|
|
86
|
+
})
|
|
87
|
+
expect(
|
|
88
|
+
matchRequestUrl(new URL('wss://test.mswjs.io'), 'wss://completely.diff'),
|
|
89
|
+
).toEqual({
|
|
90
|
+
matches: false,
|
|
91
|
+
params: {},
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test('returns path parameters when matched a WebSocket URL', () => {
|
|
96
|
+
expect(
|
|
97
|
+
matchRequestUrl(
|
|
98
|
+
new URL('wss://test.mswjs.io'),
|
|
99
|
+
'wss://:service.mswjs.io',
|
|
100
|
+
),
|
|
101
|
+
).toEqual({
|
|
102
|
+
matches: true,
|
|
103
|
+
params: {
|
|
104
|
+
service: 'test',
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
})
|
|
64
108
|
})
|
|
65
109
|
|
|
66
110
|
describe('coercePath', () => {
|