msw 2.3.0-ws.rc-9 → 2.3.0-ws.rc-11

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.
Files changed (60) hide show
  1. package/lib/browser/index.js +15 -8
  2. package/lib/browser/index.js.map +1 -1
  3. package/lib/browser/index.mjs +15 -8
  4. package/lib/browser/index.mjs.map +1 -1
  5. package/lib/core/utils/handleRequest.d.mts +2 -2
  6. package/lib/core/utils/handleRequest.d.ts +2 -2
  7. package/lib/core/utils/handleRequest.js.map +1 -1
  8. package/lib/core/utils/handleRequest.mjs.map +1 -1
  9. package/lib/core/ws/WebSocketClientManager.d.mts +1 -3
  10. package/lib/core/ws/WebSocketClientManager.d.ts +1 -3
  11. package/lib/core/ws/WebSocketClientManager.js +1 -2
  12. package/lib/core/ws/WebSocketClientManager.js.map +1 -1
  13. package/lib/core/ws/WebSocketClientManager.mjs +1 -2
  14. package/lib/core/ws/WebSocketClientManager.mjs.map +1 -1
  15. package/lib/core/ws/WebSocketClientStore.d.mts +2 -2
  16. package/lib/core/ws/WebSocketClientStore.d.ts +2 -2
  17. package/lib/core/ws/WebSocketClientStore.js.map +1 -1
  18. package/lib/core/ws/WebSocketClientStore.mjs.map +1 -1
  19. package/lib/core/ws/WebSocketIndexedDBClientStore.js +27 -6
  20. package/lib/core/ws/WebSocketIndexedDBClientStore.js.map +1 -1
  21. package/lib/core/ws/WebSocketIndexedDBClientStore.mjs +27 -6
  22. package/lib/core/ws/WebSocketIndexedDBClientStore.mjs.map +1 -1
  23. package/lib/core/ws/handleWebSocketEvent.d.mts +2 -0
  24. package/lib/core/ws/handleWebSocketEvent.d.ts +2 -0
  25. package/lib/core/ws/handleWebSocketEvent.js +30 -13
  26. package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
  27. package/lib/core/ws/handleWebSocketEvent.mjs +32 -13
  28. package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
  29. package/lib/core/ws/utils/attachWebSocketLogger.d.mts +2 -24
  30. package/lib/core/ws/utils/attachWebSocketLogger.d.ts +2 -24
  31. package/lib/core/ws/utils/attachWebSocketLogger.js +41 -60
  32. package/lib/core/ws/utils/attachWebSocketLogger.js.map +1 -1
  33. package/lib/core/ws/utils/attachWebSocketLogger.mjs +41 -60
  34. package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +1 -1
  35. package/lib/core/ws.js +1 -1
  36. package/lib/core/ws.js.map +1 -1
  37. package/lib/core/ws.mjs +1 -1
  38. package/lib/core/ws.mjs.map +1 -1
  39. package/lib/iife/index.js +170 -110
  40. package/lib/iife/index.js.map +1 -1
  41. package/lib/mockServiceWorker.js +1 -1
  42. package/lib/native/index.js +10 -5
  43. package/lib/native/index.js.map +1 -1
  44. package/lib/native/index.mjs +10 -5
  45. package/lib/native/index.mjs.map +1 -1
  46. package/lib/node/index.js +10 -5
  47. package/lib/node/index.js.map +1 -1
  48. package/lib/node/index.mjs +10 -5
  49. package/lib/node/index.mjs.map +1 -1
  50. package/package.json +2 -2
  51. package/src/browser/setupWorker/setupWorker.ts +5 -7
  52. package/src/browser/setupWorker/start/createRequestListener.ts +7 -1
  53. package/src/core/utils/handleRequest.ts +2 -1
  54. package/src/core/ws/WebSocketClientManager.ts +1 -5
  55. package/src/core/ws/WebSocketClientStore.ts +1 -1
  56. package/src/core/ws/WebSocketIndexedDBClientStore.ts +39 -6
  57. package/src/core/ws/handleWebSocketEvent.ts +40 -14
  58. package/src/core/ws/utils/attachWebSocketLogger.ts +45 -79
  59. package/src/core/ws.ts +1 -1
  60. package/src/node/SetupServerCommonApi.ts +17 -6
@@ -2,15 +2,20 @@ import type { WebSocketConnectionData } from '@mswjs/interceptors/lib/browser/in
2
2
  import { RequestHandler } from '../handlers/RequestHandler'
3
3
  import { WebSocketHandler, kDispatchEvent } from '../handlers/WebSocketHandler'
4
4
  import { webSocketInterceptor } from './webSocketInterceptor'
5
+ import {
6
+ onUnhandledRequest,
7
+ UnhandledRequestStrategy,
8
+ } from '../utils/request/onUnhandledRequest'
5
9
 
6
10
  interface HandleWebSocketEventOptions {
11
+ getUnhandledRequestStrategy: () => UnhandledRequestStrategy
7
12
  getHandlers: () => Array<RequestHandler | WebSocketHandler>
8
13
  onMockedConnection: (connection: WebSocketConnectionData) => void
9
14
  onPassthroughConnection: (onnection: WebSocketConnectionData) => void
10
15
  }
11
16
 
12
17
  export function handleWebSocketEvent(options: HandleWebSocketEventOptions) {
13
- webSocketInterceptor.on('connection', (connection) => {
18
+ webSocketInterceptor.on('connection', async (connection) => {
14
19
  const handlers = options.getHandlers()
15
20
 
16
21
  const connectionEvent = new MessageEvent('connection', {
@@ -21,20 +26,21 @@ export function handleWebSocketEvent(options: HandleWebSocketEventOptions) {
21
26
  // match the "ws.link()" endpoint predicate. Don't dispatch
22
27
  // anything yet so the logger can be attached to the connection
23
28
  // 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
- }
29
+ const matchingHandlers: Array<WebSocketHandler> = []
34
30
 
35
- return false
36
- },
37
- )
31
+ for (const handler of handlers) {
32
+ if (
33
+ handler instanceof WebSocketHandler &&
34
+ handler.predicate({
35
+ event: connectionEvent,
36
+ parsedResult: handler.parse({
37
+ event: connectionEvent,
38
+ }),
39
+ })
40
+ ) {
41
+ matchingHandlers.push(handler)
42
+ }
43
+ }
38
44
 
39
45
  if (matchingHandlers.length > 0) {
40
46
  options?.onMockedConnection(connection)
@@ -46,6 +52,26 @@ export function handleWebSocketEvent(options: HandleWebSocketEventOptions) {
46
52
  handler[kDispatchEvent](connectionEvent)
47
53
  }
48
54
  } else {
55
+ // Construct a request representing this WebSocket connection.
56
+ const request = new Request(connection.client.url, {
57
+ headers: {
58
+ upgrade: 'websocket',
59
+ connection: 'upgrade',
60
+ },
61
+ })
62
+ await onUnhandledRequest(
63
+ request,
64
+ options.getUnhandledRequestStrategy(),
65
+ ).catch((error) => {
66
+ const errorEvent = new Event('error')
67
+ Object.defineProperty(errorEvent, 'cause', {
68
+ enumerable: true,
69
+ configurable: false,
70
+ value: error,
71
+ })
72
+ connection.client.socket.dispatchEvent(errorEvent)
73
+ })
74
+
49
75
  options?.onPassthroughConnection(connection)
50
76
 
51
77
  // If none of the "ws" handlers matched,
@@ -10,10 +10,10 @@ import { getMessageLength } from './getMessageLength'
10
10
  import { getPublicData } from './getPublicData'
11
11
 
12
12
  const colors = {
13
- blue: '#3b82f6',
14
- green: '#22c55e',
15
- red: '#ef4444',
16
- orange: '#ff6a33',
13
+ system: '#3b82f6',
14
+ outgoing: '#22c55e',
15
+ incoming: '#ef4444',
16
+ mocked: '#ff6a33',
17
17
  }
18
18
 
19
19
  export function attachWebSocketLogger(
@@ -38,13 +38,6 @@ export function attachWebSocketLogger(
38
38
  logConnectionClose(event)
39
39
  })
40
40
 
41
- // Log the events received by the WebSocket client.
42
- // "client.socket" references the actual WebSocket instance
43
- // so these message events are incoming messages.
44
- client.socket.addEventListener('message', (event) => {
45
- logIncomingClientMessage(event)
46
- })
47
-
48
41
  // Log client errors (connection closures due to errors).
49
42
  client.socket.addEventListener('error', (event) => {
50
43
  logClientError(event)
@@ -66,7 +59,10 @@ export function attachWebSocketLogger(
66
59
  value: client.socket,
67
60
  },
68
61
  })
69
- logIncomingMockedClientMessage(messageEvent)
62
+
63
+ queueMicrotask(() => {
64
+ logIncomingMockedClientMessage(messageEvent)
65
+ })
70
66
 
71
67
  return Reflect.apply(target, thisArg, args)
72
68
  },
@@ -92,12 +88,12 @@ export function attachWebSocketLogger(
92
88
  currentTarget: {
93
89
  enumerable: true,
94
90
  writable: false,
95
- value: server['realWebSocket'],
91
+ value: server.socket,
96
92
  },
97
93
  target: {
98
94
  enumerable: true,
99
95
  writable: false,
100
- value: server['realWebSocket'],
96
+ value: server.socket,
101
97
  },
102
98
  })
103
99
 
@@ -120,7 +116,7 @@ export function logConnectionOpen(client: WebSocketClientConnection) {
120
116
  // eslint-disable-next-line no-console
121
117
  console.groupCollapsed(
122
118
  devUtils.formatMessage(`${getTimestamp()} %c▶%c ${publicUrl}`),
123
- `color:${colors.blue}`,
119
+ `color:${colors.system}`,
124
120
  'color:inherit',
125
121
  )
126
122
  // eslint-disable-next-line no-console
@@ -129,24 +125,17 @@ export function logConnectionOpen(client: WebSocketClientConnection) {
129
125
  console.groupEnd()
130
126
  }
131
127
 
132
- /**
133
- * Prints the outgoing client message.
134
- */
135
- export async function logOutgoingClientMessage(
136
- event: MessageEvent<WebSocketData>,
137
- ) {
138
- const byteLength = getMessageLength(event.data)
139
- const publicData = await getPublicData(event.data)
128
+ function logConnectionClose(event: CloseEvent) {
129
+ const target = event.target as WebSocket
130
+ const publicUrl = toPublicUrl(target.url)
140
131
 
141
132
  // eslint-disable-next-line no-console
142
133
  console.groupCollapsed(
143
134
  devUtils.formatMessage(
144
- `${getTimestamp({ milliseconds: true })} %c↑%c ${publicData} %c${byteLength}%c`,
135
+ `${getTimestamp({ milliseconds: true })} %c■%c ${publicUrl}`,
145
136
  ),
146
- `color:${colors.green}`,
137
+ `color:${colors.system}`,
147
138
  'color:inherit',
148
- 'color:gray;font-weight:normal',
149
- 'color:inherit;font-weight:inherit',
150
139
  )
151
140
  // eslint-disable-next-line no-console
152
141
  console.log(event)
@@ -154,25 +143,17 @@ export async function logOutgoingClientMessage(
154
143
  console.groupEnd()
155
144
  }
156
145
 
157
- /**
158
- * Prints the outgoing client message initiated
159
- * by `server.send()` in the event handler.
160
- */
161
- export async function logOutgoingMockedClientMessage(
162
- event: MessageEvent<WebSocketData>,
163
- ) {
164
- const byteLength = getMessageLength(event.data)
165
- const publicData = await getPublicData(event.data)
146
+ function logClientError(event: Event) {
147
+ const socket = event.target as WebSocket
148
+ const publicUrl = toPublicUrl(socket.url)
166
149
 
167
150
  // eslint-disable-next-line no-console
168
151
  console.groupCollapsed(
169
152
  devUtils.formatMessage(
170
- `${getTimestamp({ milliseconds: true })} %c⇡%c ${publicData} %c${byteLength}%c`,
153
+ `${getTimestamp({ milliseconds: true })} %c\u00D7%c ${publicUrl}`,
171
154
  ),
172
- `color:${colors.orange}`,
155
+ `color:${colors.system}`,
173
156
  'color:inherit',
174
- 'color:gray;font-weight:normal',
175
- 'color:inherit;font-weight:inherit',
176
157
  )
177
158
  // eslint-disable-next-line no-console
178
159
  console.log(event)
@@ -181,23 +162,19 @@ export async function logOutgoingMockedClientMessage(
181
162
  }
182
163
 
183
164
  /**
184
- * Prings the message received by the WebSocket client.
185
- * This is fired when the "message" event is dispatched
186
- * on the actual WebSocket client instance, and translates to
187
- * the client receiving a message from the server.
165
+ * Prints the outgoing client message.
188
166
  */
189
- export async function logIncomingClientMessage(
190
- event: MessageEvent<WebSocketData>,
191
- ) {
167
+ async function logOutgoingClientMessage(event: MessageEvent<WebSocketData>) {
192
168
  const byteLength = getMessageLength(event.data)
193
169
  const publicData = await getPublicData(event.data)
170
+ const arrow = event.defaultPrevented ? '⇡' : '⬆'
194
171
 
195
172
  // eslint-disable-next-line no-console
196
173
  console.groupCollapsed(
197
174
  devUtils.formatMessage(
198
- `${getTimestamp({ milliseconds: true })} %c↓%c ${publicData} %c${byteLength}%c`,
175
+ `${getTimestamp({ milliseconds: true })} %c${arrow}%c ${publicData} %c${byteLength}%c`,
199
176
  ),
200
- `color:${colors.red}`,
177
+ `color:${colors.outgoing}`,
201
178
  'color:inherit',
202
179
  'color:gray;font-weight:normal',
203
180
  'color:inherit;font-weight:inherit',
@@ -210,9 +187,9 @@ export async function logIncomingClientMessage(
210
187
 
211
188
  /**
212
189
  * Prints the outgoing client message initiated
213
- * by `client.send()` in the event handler.
190
+ * by `server.send()` in the event handler.
214
191
  */
215
- export async function logIncomingMockedClientMessage(
192
+ async function logOutgoingMockedClientMessage(
216
193
  event: MessageEvent<WebSocketData>,
217
194
  ) {
218
195
  const byteLength = getMessageLength(event.data)
@@ -221,9 +198,9 @@ export async function logIncomingMockedClientMessage(
221
198
  // eslint-disable-next-line no-console
222
199
  console.groupCollapsed(
223
200
  devUtils.formatMessage(
224
- `${getTimestamp({ milliseconds: true })} %c⇣%c ${publicData} %c${byteLength}%c`,
201
+ `${getTimestamp({ milliseconds: true })} %c⬆%c ${publicData} %c${byteLength}%c`,
225
202
  ),
226
- `color:${colors.orange}`,
203
+ `color:${colors.mocked}`,
227
204
  'color:inherit',
228
205
  'color:gray;font-weight:normal',
229
206
  'color:inherit;font-weight:inherit',
@@ -234,25 +211,11 @@ export async function logIncomingMockedClientMessage(
234
211
  console.groupEnd()
235
212
  }
236
213
 
237
- function logConnectionClose(event: CloseEvent) {
238
- const target = event.target as WebSocket
239
- const publicUrl = toPublicUrl(target.url)
240
-
241
- // eslint-disable-next-line no-console
242
- console.groupCollapsed(
243
- devUtils.formatMessage(
244
- `${getTimestamp({ milliseconds: true })} %c■%c ${publicUrl}`,
245
- ),
246
- `color:${colors.blue}`,
247
- 'color:inherit',
248
- )
249
- // eslint-disable-next-line no-console
250
- console.log(event)
251
- // eslint-disable-next-line no-console
252
- console.groupEnd()
253
- }
254
-
255
- export async function logIncomingServerMessage(
214
+ /**
215
+ * Prints the outgoing client message initiated
216
+ * by `client.send()` in the event handler.
217
+ */
218
+ async function logIncomingMockedClientMessage(
256
219
  event: MessageEvent<WebSocketData>,
257
220
  ) {
258
221
  const byteLength = getMessageLength(event.data)
@@ -261,9 +224,9 @@ export async function logIncomingServerMessage(
261
224
  // eslint-disable-next-line no-console
262
225
  console.groupCollapsed(
263
226
  devUtils.formatMessage(
264
- `${getTimestamp({ milliseconds: true })} %c⇣%c ${publicData} %c${byteLength}%c`,
227
+ `${getTimestamp({ milliseconds: true })} %c⬇%c ${publicData} %c${byteLength}%c`,
265
228
  ),
266
- `color:${colors.green}`,
229
+ `color:${colors.mocked}`,
267
230
  'color:inherit',
268
231
  'color:gray;font-weight:normal',
269
232
  'color:inherit;font-weight:inherit',
@@ -274,17 +237,20 @@ export async function logIncomingServerMessage(
274
237
  console.groupEnd()
275
238
  }
276
239
 
277
- function logClientError(event: Event) {
278
- const socket = event.target as WebSocket
279
- const publicUrl = toPublicUrl(socket.url)
240
+ async function logIncomingServerMessage(event: MessageEvent<WebSocketData>) {
241
+ const byteLength = getMessageLength(event.data)
242
+ const publicData = await getPublicData(event.data)
243
+ const arrow = event.defaultPrevented ? '⇣' : '⬇'
280
244
 
281
245
  // eslint-disable-next-line no-console
282
246
  console.groupCollapsed(
283
247
  devUtils.formatMessage(
284
- `${getTimestamp({ milliseconds: true })} %c\u00D7%c ${publicUrl}`,
248
+ `${getTimestamp({ milliseconds: true })} %c${arrow}%c ${publicData} %c${byteLength}%c`,
285
249
  ),
286
- `color:${colors.blue}`,
250
+ `color:${colors.incoming}`,
287
251
  'color:inherit',
252
+ 'color:gray;font-weight:normal',
253
+ 'color:inherit;font-weight:inherit',
288
254
  )
289
255
  // eslint-disable-next-line no-console
290
256
  console.log(event)
package/src/core/ws.ts CHANGED
@@ -103,7 +103,7 @@ function createWebSocketLinkHandler(url: Path): WebSocketLink {
103
103
  typeof url,
104
104
  )
105
105
 
106
- const clientManager = new WebSocketClientManager(webSocketChannel, url)
106
+ const clientManager = new WebSocketClientManager(webSocketChannel)
107
107
 
108
108
  return {
109
109
  get clients() {
@@ -14,6 +14,8 @@ import type { LifeCycleEventsMap, SharedOptions } from '~/core/sharedOptions'
14
14
  import { SetupApi } from '~/core/SetupApi'
15
15
  import { handleRequest } from '~/core/utils/handleRequest'
16
16
  import type { RequestHandler } from '~/core/handlers/RequestHandler'
17
+ import { HttpHandler } from '~/core/handlers/HttpHandler'
18
+ import { GraphQLHandler } from '~/core/handlers/GraphQLHandler'
17
19
  import type { WebSocketHandler } from '~/core/handlers/WebSocketHandler'
18
20
  import { mergeRight } from '~/core/utils/internal/mergeRight'
19
21
  import { InternalError, devUtils } from '~/core/utils/internal/devUtils'
@@ -61,7 +63,12 @@ export class SetupServerCommonApi
61
63
  const response = await handleRequest(
62
64
  request,
63
65
  requestId,
64
- this.handlersController.currentHandlers(),
66
+ this.handlersController.currentHandlers().filter((handler) => {
67
+ return (
68
+ handler instanceof HttpHandler ||
69
+ handler instanceof GraphQLHandler
70
+ )
71
+ }),
65
72
  this.resolvedOptions,
66
73
  this.emitter,
67
74
  )
@@ -94,7 +101,12 @@ export class SetupServerCommonApi
94
101
  },
95
102
  )
96
103
 
104
+ // Preconfigure the WebSocket interception but don't enable it just yet.
105
+ // It will be enabled when the server starts.
97
106
  handleWebSocketEvent({
107
+ getUnhandledRequestStrategy: () => {
108
+ return this.resolvedOptions.onUnhandledRequest
109
+ },
98
110
  getHandlers: () => {
99
111
  return this.handlersController.currentHandlers()
100
112
  },
@@ -111,12 +123,11 @@ export class SetupServerCommonApi
111
123
 
112
124
  // Apply the interceptor when starting the server.
113
125
  this.interceptor.apply()
114
- webSocketInterceptor.apply()
126
+ this.subscriptions.push(() => this.interceptor.dispose())
115
127
 
116
- this.subscriptions.push(() => {
117
- this.interceptor.dispose()
118
- webSocketInterceptor.dispose()
119
- })
128
+ // Apply the WebSocket interception.
129
+ webSocketInterceptor.apply()
130
+ this.subscriptions.push(() => webSocketInterceptor.dispose())
120
131
 
121
132
  // Assert that the interceptor has been applied successfully.
122
133
  // Also guards us from forgetting to call "interceptor.apply()"