msw 2.11.0 → 2.11.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/lib/browser/index.d.mts +0 -3
- package/lib/browser/index.d.ts +0 -3
- package/lib/browser/index.js +503 -294
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +503 -294
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/{HttpResponse-DiuKTgC7.d.mts → HttpResponse-B4YmE-GJ.d.mts} +1 -1
- package/lib/core/{HttpResponse-DlQEvD4q.d.ts → HttpResponse-BbwAqLE_.d.ts} +1 -1
- 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/getResponse.d.mts +1 -1
- package/lib/core/getResponse.d.ts +1 -1
- package/lib/core/graphql.d.mts +1 -1
- package/lib/core/graphql.d.ts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
- 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.map +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/http.d.mts +1 -1
- package/lib/core/http.d.ts +1 -1
- package/lib/core/index.d.mts +1 -1
- package/lib/core/index.d.ts +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/cookieStore.d.mts +10 -2
- package/lib/core/utils/cookieStore.d.ts +10 -2
- package/lib/core/utils/cookieStore.js +49 -146
- package/lib/core/utils/cookieStore.js.map +1 -1
- package/lib/core/utils/cookieStore.mjs +53 -136
- package/lib/core/utils/cookieStore.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 +1 -1
- package/lib/core/utils/handleRequest.js.map +1 -1
- package/lib/core/utils/handleRequest.mjs +1 -1
- package/lib/core/utils/handleRequest.mjs.map +1 -1
- package/lib/core/utils/internal/devUtils.js.map +1 -1
- package/lib/core/utils/internal/devUtils.mjs.map +1 -1
- package/lib/core/utils/internal/getCallFrame.js +2 -2
- package/lib/core/utils/internal/getCallFrame.js.map +1 -1
- package/lib/core/utils/internal/getCallFrame.mjs +2 -2
- package/lib/core/utils/internal/getCallFrame.mjs.map +1 -1
- package/lib/core/utils/internal/isHandlerKind.d.mts +1 -1
- package/lib/core/utils/internal/isHandlerKind.d.ts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.js +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.js.map +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.mjs +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.mjs.map +1 -1
- 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/matching/matchRequestUrl.js +1 -1
- package/lib/core/utils/matching/matchRequestUrl.js.map +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs.map +1 -1
- package/lib/core/utils/request/getRequestCookies.js +1 -1
- package/lib/core/utils/request/getRequestCookies.js.map +1 -1
- package/lib/core/utils/request/getRequestCookies.mjs +1 -1
- package/lib/core/utils/request/getRequestCookies.mjs.map +1 -1
- package/lib/core/utils/request/storeResponseCookies.d.mts +1 -1
- package/lib/core/utils/request/storeResponseCookies.d.ts +1 -1
- package/lib/core/utils/request/storeResponseCookies.js +2 -2
- package/lib/core/utils/request/storeResponseCookies.js.map +1 -1
- package/lib/core/utils/request/storeResponseCookies.mjs +2 -2
- package/lib/core/utils/request/storeResponseCookies.mjs.map +1 -1
- package/lib/core/utils/url/cleanUrl.js +1 -1
- package/lib/core/utils/url/cleanUrl.js.map +1 -1
- package/lib/core/utils/url/cleanUrl.mjs +1 -1
- package/lib/core/utils/url/cleanUrl.mjs.map +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.js +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.js.map +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.mjs +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.mjs.map +1 -1
- package/lib/core/ws/WebSocketIndexedDBClientStore.js.map +1 -1
- package/lib/core/ws/WebSocketIndexedDBClientStore.mjs.map +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.js.map +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +1 -1
- package/lib/iife/index.js +6885 -16153
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +16 -12
- package/lib/node/index.js.map +1 -1
- package/lib/node/index.mjs.map +1 -1
- package/package.json +22 -15
- package/src/browser/setupWorker/glossary.ts +9 -114
- package/src/browser/setupWorker/setupWorker.ts +83 -120
- package/src/browser/setupWorker/start/createRequestListener.ts +20 -24
- package/src/browser/setupWorker/start/createResponseListener.ts +15 -22
- package/src/browser/setupWorker/start/createStartHandler.ts +24 -18
- package/src/browser/setupWorker/start/utils/enableMocking.ts +18 -21
- package/src/browser/setupWorker/start/utils/printStartMessage.ts +0 -2
- package/src/browser/utils/checkWorkerIntegrity.ts +22 -14
- package/src/browser/utils/workerChannel.ts +146 -0
- package/src/core/HttpResponse.ts +3 -3
- package/src/core/handlers/GraphQLHandler.test.ts +1 -1
- package/src/core/handlers/GraphQLHandler.ts +0 -3
- package/src/core/handlers/HttpHandler.ts +0 -2
- package/src/core/utils/cookieStore.ts +56 -198
- package/src/core/utils/handleRequest.ts +1 -1
- package/src/core/utils/internal/devUtils.ts +0 -2
- package/src/core/utils/internal/getCallFrame.ts +2 -2
- package/src/core/utils/internal/parseGraphQLRequest.ts +1 -0
- package/src/core/utils/matching/matchRequestUrl.ts +2 -2
- package/src/core/utils/request/getRequestCookies.ts +1 -1
- package/src/core/utils/request/onUnhandledRequest.test.ts +1 -1
- package/src/core/utils/request/storeResponseCookies.ts +3 -3
- package/src/core/utils/request/toPublicUrl.test.ts +1 -1
- package/src/core/utils/url/cleanUrl.ts +1 -1
- package/src/core/utils/url/isAbsoluteUrl.ts +1 -1
- package/src/core/ws/WebSocketClientManager.test.ts +1 -1
- package/src/core/ws/WebSocketIndexedDBClientStore.ts +0 -4
- package/src/core/ws/utils/attachWebSocketLogger.ts +0 -14
- package/src/mockServiceWorker.js +14 -10
- package/src/node/SetupServerApi.ts +1 -1
- package/src/browser/setupWorker/start/createFallbackStart.ts +0 -21
- package/src/browser/setupWorker/start/utils/createMessageChannel.ts +0 -32
- package/src/browser/setupWorker/stop/createFallbackStop.ts +0 -11
- package/src/browser/setupWorker/stop/createStop.ts +0 -35
|
@@ -1,45 +1,34 @@
|
|
|
1
1
|
import { invariant } from 'outvariant'
|
|
2
2
|
import { isNodeProcess } from 'is-node-process'
|
|
3
|
-
import {
|
|
3
|
+
import type {
|
|
4
4
|
SetupWorkerInternalContext,
|
|
5
|
-
ServiceWorkerIncomingEventsMap,
|
|
6
5
|
StartReturnType,
|
|
7
|
-
StopHandler,
|
|
8
|
-
StartHandler,
|
|
9
6
|
StartOptions,
|
|
7
|
+
SetupWorker,
|
|
10
8
|
} from './glossary'
|
|
11
|
-
import { createStartHandler } from './start/createStartHandler'
|
|
12
|
-
import { createStop } from './stop/createStop'
|
|
13
|
-
import { ServiceWorkerMessage } from './start/utils/createMessageChannel'
|
|
14
9
|
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
15
10
|
import { DEFAULT_START_OPTIONS } from './start/utils/prepareStartHandler'
|
|
16
|
-
import {
|
|
17
|
-
import { createFallbackStop } from './stop/createFallbackStop'
|
|
11
|
+
import { createStartHandler } from './start/createStartHandler'
|
|
18
12
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
19
13
|
import { SetupApi } from '~/core/SetupApi'
|
|
20
14
|
import { mergeRight } from '~/core/utils/internal/mergeRight'
|
|
21
15
|
import type { LifeCycleEventsMap } from '~/core/sharedOptions'
|
|
22
16
|
import type { WebSocketHandler } from '~/core/handlers/WebSocketHandler'
|
|
23
|
-
import { SetupWorker } from './glossary'
|
|
24
17
|
import { supportsReadableStreamTransfer } from '../utils/supportsReadableStreamTransfer'
|
|
25
18
|
import { webSocketInterceptor } from '~/core/ws/webSocketInterceptor'
|
|
26
19
|
import { handleWebSocketEvent } from '~/core/ws/handleWebSocketEvent'
|
|
27
20
|
import { attachWebSocketLogger } from '~/core/ws/utils/attachWebSocketLogger'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
21
|
+
import { WorkerChannel } from '../utils/workerChannel'
|
|
22
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
23
|
+
import { createFallbackRequestListener } from './start/createFallbackRequestListener'
|
|
24
|
+
import { printStartMessage } from './start/utils/printStartMessage'
|
|
25
|
+
import { printStopMessage } from './stop/utils/printStopMessage'
|
|
34
26
|
|
|
35
27
|
export class SetupWorkerApi
|
|
36
28
|
extends SetupApi<LifeCycleEventsMap>
|
|
37
29
|
implements SetupWorker
|
|
38
30
|
{
|
|
39
31
|
private context: SetupWorkerInternalContext
|
|
40
|
-
private startHandler: StartHandler = null as any
|
|
41
|
-
private stopHandler: StopHandler = null as any
|
|
42
|
-
private listeners: Array<Listener>
|
|
43
32
|
|
|
44
33
|
constructor(...handlers: Array<RequestHandler | WebSocketHandler>) {
|
|
45
34
|
super(...handlers)
|
|
@@ -51,129 +40,53 @@ export class SetupWorkerApi
|
|
|
51
40
|
),
|
|
52
41
|
)
|
|
53
42
|
|
|
54
|
-
this.listeners = []
|
|
55
43
|
this.context = this.createWorkerContext()
|
|
56
44
|
}
|
|
57
45
|
|
|
58
46
|
private createWorkerContext(): SetupWorkerInternalContext {
|
|
59
|
-
const
|
|
47
|
+
const workerPromise = new DeferredPromise<ServiceWorker>()
|
|
48
|
+
|
|
49
|
+
return {
|
|
60
50
|
// Mocking is not considered enabled until the worker
|
|
61
51
|
// signals back the successful activation event.
|
|
62
52
|
isMockingEnabled: false,
|
|
63
53
|
startOptions: null as any,
|
|
64
|
-
|
|
54
|
+
workerPromise,
|
|
55
|
+
registration: undefined,
|
|
65
56
|
getRequestHandlers: () => {
|
|
66
57
|
return this.handlersController.currentHandlers()
|
|
67
58
|
},
|
|
68
|
-
registration: null,
|
|
69
59
|
emitter: this.emitter,
|
|
70
|
-
workerChannel: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
MessageEvent<ServiceWorkerMessage<typeof eventType, any>>
|
|
74
|
-
>(navigator.serviceWorker, 'message', (event) => {
|
|
75
|
-
// Avoid messages broadcasted from unrelated workers.
|
|
76
|
-
if (event.source !== this.context.worker) {
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const message = event.data
|
|
81
|
-
|
|
82
|
-
if (!message) {
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (message.type === eventType) {
|
|
87
|
-
callback(event, message)
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
},
|
|
91
|
-
send: (type) => {
|
|
92
|
-
this.context.worker?.postMessage(type)
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
events: {
|
|
96
|
-
addListener: (target, eventType, callback) => {
|
|
97
|
-
target.addEventListener(eventType, callback as EventListener)
|
|
98
|
-
this.listeners.push({
|
|
99
|
-
eventType,
|
|
100
|
-
target,
|
|
101
|
-
callback: callback as EventListener,
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
return () => {
|
|
105
|
-
target.removeEventListener(eventType, callback as EventListener)
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
removeAllListeners: () => {
|
|
109
|
-
for (const { target, eventType, callback } of this.listeners) {
|
|
110
|
-
target.removeEventListener(eventType, callback)
|
|
111
|
-
}
|
|
112
|
-
this.listeners = []
|
|
113
|
-
},
|
|
114
|
-
once: (eventType) => {
|
|
115
|
-
const bindings: Array<() => void> = []
|
|
116
|
-
|
|
117
|
-
return new Promise<
|
|
118
|
-
ServiceWorkerMessage<
|
|
119
|
-
typeof eventType,
|
|
120
|
-
ServiceWorkerIncomingEventsMap[typeof eventType]
|
|
121
|
-
>
|
|
122
|
-
>((resolve, reject) => {
|
|
123
|
-
const handleIncomingMessage = (event: MessageEvent) => {
|
|
124
|
-
try {
|
|
125
|
-
const message = event.data
|
|
126
|
-
|
|
127
|
-
if (message.type === eventType) {
|
|
128
|
-
resolve(message)
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
reject(error)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
bindings.push(
|
|
136
|
-
this.context.events.addListener(
|
|
137
|
-
navigator.serviceWorker,
|
|
138
|
-
'message',
|
|
139
|
-
handleIncomingMessage,
|
|
140
|
-
),
|
|
141
|
-
this.context.events.addListener(
|
|
142
|
-
navigator.serviceWorker,
|
|
143
|
-
'messageerror',
|
|
144
|
-
reject,
|
|
145
|
-
),
|
|
146
|
-
)
|
|
147
|
-
}).finally(() => {
|
|
148
|
-
bindings.forEach((unbind) => unbind())
|
|
149
|
-
})
|
|
150
|
-
},
|
|
151
|
-
},
|
|
60
|
+
workerChannel: new WorkerChannel({
|
|
61
|
+
worker: workerPromise,
|
|
62
|
+
}),
|
|
152
63
|
supports: {
|
|
153
64
|
serviceWorkerApi:
|
|
154
|
-
|
|
65
|
+
'serviceWorker' in navigator && location.protocol !== 'file:',
|
|
155
66
|
readableStreamTransfer: supportsReadableStreamTransfer(),
|
|
156
67
|
},
|
|
157
68
|
}
|
|
158
|
-
|
|
159
|
-
this.startHandler = context.supports.serviceWorkerApi
|
|
160
|
-
? createFallbackStart(context)
|
|
161
|
-
: createStartHandler(context)
|
|
162
|
-
|
|
163
|
-
this.stopHandler = context.supports.serviceWorkerApi
|
|
164
|
-
? createFallbackStop(context)
|
|
165
|
-
: createStop(context)
|
|
166
|
-
|
|
167
|
-
return context
|
|
168
69
|
}
|
|
169
70
|
|
|
170
71
|
public async start(options: StartOptions = {}): StartReturnType {
|
|
171
|
-
if (
|
|
72
|
+
if ('waitUntilReady' in options) {
|
|
172
73
|
devUtils.warn(
|
|
173
74
|
'The "waitUntilReady" option has been deprecated. Please remove it from this "worker.start()" call. Follow the recommended Browser integration (https://mswjs.io/docs/integrations/browser) to eliminate any race conditions between the Service Worker registration and any requests made by your application on initial render.',
|
|
174
75
|
)
|
|
175
76
|
}
|
|
176
77
|
|
|
78
|
+
// Warn the developer on multiple "worker.start()" calls.
|
|
79
|
+
// While this will not affect the worker in any way,
|
|
80
|
+
// it likely indicates an issue with the developer's code.
|
|
81
|
+
if (this.context.isMockingEnabled) {
|
|
82
|
+
devUtils.warn(
|
|
83
|
+
`Found a redundant "worker.start()" call. Note that starting the worker while mocking is already enabled will have no effect. Consider removing this "worker.start()" call.`,
|
|
84
|
+
)
|
|
85
|
+
return this.context.registration
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.context.workerStoppedAt = undefined
|
|
89
|
+
|
|
177
90
|
this.context.startOptions = mergeRight(
|
|
178
91
|
DEFAULT_START_OPTIONS,
|
|
179
92
|
options,
|
|
@@ -202,14 +115,64 @@ export class SetupWorkerApi
|
|
|
202
115
|
webSocketInterceptor.dispose()
|
|
203
116
|
})
|
|
204
117
|
|
|
205
|
-
|
|
118
|
+
// Use a fallback interception algorithm in the environments
|
|
119
|
+
// where the Service Worker API isn't supported.
|
|
120
|
+
if (!this.context.supports.serviceWorkerApi) {
|
|
121
|
+
const fallbackInterceptor = createFallbackRequestListener(
|
|
122
|
+
this.context,
|
|
123
|
+
this.context.startOptions,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
this.subscriptions.push(() => {
|
|
127
|
+
fallbackInterceptor.dispose()
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
this.context.isMockingEnabled = true
|
|
131
|
+
|
|
132
|
+
printStartMessage({
|
|
133
|
+
message: 'Mocking enabled (fallback mode).',
|
|
134
|
+
quiet: this.context.startOptions.quiet,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return undefined
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const startHandler = createStartHandler(this.context)
|
|
141
|
+
const registration = await startHandler(this.context.startOptions, options)
|
|
142
|
+
|
|
143
|
+
this.context.isMockingEnabled = true
|
|
144
|
+
|
|
145
|
+
return registration
|
|
206
146
|
}
|
|
207
147
|
|
|
208
148
|
public stop(): void {
|
|
209
149
|
super.dispose()
|
|
210
|
-
|
|
150
|
+
|
|
151
|
+
if (!this.context.isMockingEnabled) {
|
|
152
|
+
devUtils.warn(
|
|
153
|
+
'Found a redundant "worker.stop()" call. Notice that stopping the worker after it has already been stopped has no effect. Consider removing this "worker.stop()" call.',
|
|
154
|
+
)
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.context.isMockingEnabled = false
|
|
159
|
+
this.context.workerStoppedAt = Date.now()
|
|
211
160
|
this.context.emitter.removeAllListeners()
|
|
212
|
-
|
|
161
|
+
|
|
162
|
+
if (this.context.supports.serviceWorkerApi) {
|
|
163
|
+
this.context.workerChannel.removeAllListeners('RESPONSE')
|
|
164
|
+
window.clearInterval(this.context.keepAliveInterval)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Post the internal stop message on the window
|
|
168
|
+
// to let any logic know when the worker has stopped.
|
|
169
|
+
// E.g. the WebSocket client manager needs this to know
|
|
170
|
+
// when to clear its in-memory clients list.
|
|
171
|
+
window.postMessage({ type: 'msw/worker:stop' })
|
|
172
|
+
|
|
173
|
+
printStopMessage({
|
|
174
|
+
quiet: this.context.startOptions?.quiet,
|
|
175
|
+
})
|
|
213
176
|
}
|
|
214
177
|
}
|
|
215
178
|
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
SetupWorkerInternalContext,
|
|
4
|
-
ServiceWorkerIncomingEventsMap,
|
|
5
|
-
} from '../glossary'
|
|
6
|
-
import {
|
|
7
|
-
ServiceWorkerMessage,
|
|
8
|
-
WorkerChannel,
|
|
9
|
-
} from './utils/createMessageChannel'
|
|
1
|
+
import { Emitter } from 'rettime'
|
|
2
|
+
import { StartOptions, SetupWorkerInternalContext } from '../glossary'
|
|
10
3
|
import { deserializeRequest } from '../../utils/deserializeRequest'
|
|
11
4
|
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
12
5
|
import { handleRequest } from '~/core/utils/handleRequest'
|
|
@@ -18,18 +11,21 @@ import { isHandlerKind } from '~/core/utils/internal/isHandlerKind'
|
|
|
18
11
|
export const createRequestListener = (
|
|
19
12
|
context: SetupWorkerInternalContext,
|
|
20
13
|
options: RequiredDeep<StartOptions>,
|
|
21
|
-
) => {
|
|
22
|
-
return async (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
): Emitter.ListenerType<typeof context.workerChannel, 'REQUEST'> => {
|
|
15
|
+
return async (event) => {
|
|
16
|
+
// Treat any incoming requests from the worker as passthrough
|
|
17
|
+
// if `worker.stop()` has been called for this client.
|
|
18
|
+
if (
|
|
19
|
+
!context.isMockingEnabled &&
|
|
20
|
+
context.workerStoppedAt &&
|
|
21
|
+
event.data.interceptedAt > context.workerStoppedAt
|
|
22
|
+
) {
|
|
23
|
+
event.postMessage('PASSTHROUGH')
|
|
24
|
+
return
|
|
25
|
+
}
|
|
30
26
|
|
|
31
|
-
const requestId =
|
|
32
|
-
const request = deserializeRequest(
|
|
27
|
+
const requestId = event.data.id
|
|
28
|
+
const request = deserializeRequest(event.data)
|
|
33
29
|
const requestCloneForLogs = request.clone()
|
|
34
30
|
|
|
35
31
|
// Make this the first request clone before the
|
|
@@ -48,7 +44,7 @@ export const createRequestListener = (
|
|
|
48
44
|
context.emitter,
|
|
49
45
|
{
|
|
50
46
|
onPassthroughResponse() {
|
|
51
|
-
|
|
47
|
+
event.postMessage('PASSTHROUGH')
|
|
52
48
|
},
|
|
53
49
|
async onMockedResponse(response, { handler, parsedResult }) {
|
|
54
50
|
// Clone the mocked response so its body could be read
|
|
@@ -65,7 +61,7 @@ export const createRequestListener = (
|
|
|
65
61
|
if (context.supports.readableStreamTransfer) {
|
|
66
62
|
const responseStreamOrNull = response.body
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
event.postMessage(
|
|
69
65
|
'MOCK_RESPONSE',
|
|
70
66
|
{
|
|
71
67
|
...responseInit,
|
|
@@ -85,7 +81,7 @@ export const createRequestListener = (
|
|
|
85
81
|
? null
|
|
86
82
|
: await responseClone.arrayBuffer()
|
|
87
83
|
|
|
88
|
-
|
|
84
|
+
event.postMessage('MOCK_RESPONSE', {
|
|
89
85
|
...responseInit,
|
|
90
86
|
body: responseBufferOrNull,
|
|
91
87
|
})
|
|
@@ -118,7 +114,7 @@ This exception has been gracefully handled as a 500 response, however, it's stro
|
|
|
118
114
|
|
|
119
115
|
// Treat all other exceptions in a request handler as unintended,
|
|
120
116
|
// alerting that there is a problem that needs fixing.
|
|
121
|
-
|
|
117
|
+
event.postMessage('MOCK_RESPONSE', {
|
|
122
118
|
status: 500,
|
|
123
119
|
statusText: 'Request Handler Error',
|
|
124
120
|
headers: {
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { FetchResponse } from '@mswjs/interceptors'
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
SetupWorkerInternalContext,
|
|
5
|
-
} from '../glossary'
|
|
6
|
-
import type { ServiceWorkerMessage } from './utils/createMessageChannel'
|
|
2
|
+
import type { Emitter } from 'rettime'
|
|
3
|
+
import type { SetupWorkerInternalContext } from '../glossary'
|
|
7
4
|
import { deserializeRequest } from '../../utils/deserializeRequest'
|
|
8
5
|
|
|
9
|
-
export function createResponseListener(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
>,
|
|
16
|
-
) => {
|
|
17
|
-
const { payload: responseJson } = message
|
|
18
|
-
const request = deserializeRequest(responseJson.request)
|
|
6
|
+
export function createResponseListener(
|
|
7
|
+
context: SetupWorkerInternalContext,
|
|
8
|
+
): Emitter.ListenerType<typeof context.workerChannel, 'RESPONSE'> {
|
|
9
|
+
return (event) => {
|
|
10
|
+
const responseMessage = event.data
|
|
11
|
+
const request = deserializeRequest(responseMessage.request)
|
|
19
12
|
|
|
20
13
|
/**
|
|
21
14
|
* CORS requests with `mode: "no-cors"` result in "opaque" responses.
|
|
@@ -24,12 +17,12 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
|
|
|
24
17
|
* @see https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
|
|
25
18
|
* @see https://github.com/mswjs/msw/issues/529
|
|
26
19
|
*/
|
|
27
|
-
if (
|
|
20
|
+
if (responseMessage.response.type?.includes('opaque')) {
|
|
28
21
|
return
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
const response =
|
|
32
|
-
|
|
25
|
+
responseMessage.response.status === 0
|
|
33
26
|
? Response.error()
|
|
34
27
|
: new FetchResponse(
|
|
35
28
|
/**
|
|
@@ -38,11 +31,11 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
|
|
|
38
31
|
* throw when passed a non-null body, so ensure it's null here
|
|
39
32
|
* for those codes
|
|
40
33
|
*/
|
|
41
|
-
FetchResponse.isResponseWithBody(
|
|
42
|
-
?
|
|
34
|
+
FetchResponse.isResponseWithBody(responseMessage.response.status)
|
|
35
|
+
? responseMessage.response.body
|
|
43
36
|
: null,
|
|
44
37
|
{
|
|
45
|
-
...
|
|
38
|
+
...responseMessage,
|
|
46
39
|
/**
|
|
47
40
|
* Set response URL if it's not set already.
|
|
48
41
|
* @see https://github.com/mswjs/msw/issues/2030
|
|
@@ -53,9 +46,9 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
|
|
|
53
46
|
)
|
|
54
47
|
|
|
55
48
|
context.emitter.emit(
|
|
56
|
-
|
|
49
|
+
responseMessage.isMockedResponse ? 'response:mocked' : 'response:bypass',
|
|
57
50
|
{
|
|
58
|
-
requestId:
|
|
51
|
+
requestId: responseMessage.request.id,
|
|
59
52
|
request,
|
|
60
53
|
response,
|
|
61
54
|
},
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
2
2
|
import { getWorkerInstance } from './utils/getWorkerInstance'
|
|
3
3
|
import { enableMocking } from './utils/enableMocking'
|
|
4
|
-
import { SetupWorkerInternalContext, StartHandler } from '../glossary'
|
|
4
|
+
import type { SetupWorkerInternalContext, StartHandler } from '../glossary'
|
|
5
5
|
import { createRequestListener } from './createRequestListener'
|
|
6
6
|
import { checkWorkerIntegrity } from '../../utils/checkWorkerIntegrity'
|
|
7
7
|
import { createResponseListener } from './createResponseListener'
|
|
8
8
|
import { validateWorkerScope } from './utils/validateWorkerScope'
|
|
9
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
9
10
|
|
|
10
11
|
export const createStartHandler = (
|
|
11
12
|
context: SetupWorkerInternalContext,
|
|
@@ -15,7 +16,7 @@ export const createStartHandler = (
|
|
|
15
16
|
// Remove all previously existing event listeners.
|
|
16
17
|
// This way none of the listeners persists between Fast refresh
|
|
17
18
|
// of the application's code.
|
|
18
|
-
context.
|
|
19
|
+
context.workerChannel.removeAllListeners()
|
|
19
20
|
|
|
20
21
|
// Handle requests signaled by the worker.
|
|
21
22
|
context.workerChannel.on(
|
|
@@ -57,17 +58,18 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
|
|
|
57
58
|
throw new Error(missingWorkerMessage)
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
context.worker
|
|
61
|
+
context.workerPromise.resolve(worker)
|
|
61
62
|
context.registration = registration
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
window.addEventListener('beforeunload', () => {
|
|
64
65
|
if (worker.state !== 'redundant') {
|
|
65
66
|
// Notify the Service Worker that this client has closed.
|
|
66
67
|
// Internally, it's similar to disabling the mocking, only
|
|
67
68
|
// client close event has a handler that self-terminates
|
|
68
69
|
// the Service Worker when there are no open clients.
|
|
69
|
-
context.workerChannel.
|
|
70
|
+
context.workerChannel.postMessage('CLIENT_CLOSED')
|
|
70
71
|
}
|
|
72
|
+
|
|
71
73
|
// Make sure we're always clearing the interval - there are reports that not doing this can
|
|
72
74
|
// cause memory leaks in headless browser environments.
|
|
73
75
|
window.clearInterval(context.keepAliveInterval)
|
|
@@ -82,14 +84,13 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
|
|
|
82
84
|
// by the currently installed version of MSW.
|
|
83
85
|
await checkWorkerIntegrity(context).catch((error) => {
|
|
84
86
|
devUtils.error(
|
|
85
|
-
'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues)
|
|
87
|
+
'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues) and include the original error below.',
|
|
86
88
|
)
|
|
87
|
-
// eslint-disable-next-line no-console
|
|
88
89
|
console.error(error)
|
|
89
90
|
})
|
|
90
91
|
|
|
91
92
|
context.keepAliveInterval = window.setInterval(
|
|
92
|
-
() => context.workerChannel.
|
|
93
|
+
() => context.workerChannel.postMessage('KEEPALIVE_REQUEST'),
|
|
93
94
|
5000,
|
|
94
95
|
)
|
|
95
96
|
|
|
@@ -104,22 +105,27 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
|
|
|
104
105
|
async (registration) => {
|
|
105
106
|
const pendingInstance = registration.installing || registration.waiting
|
|
106
107
|
|
|
107
|
-
// Wait until the worker is activated.
|
|
108
|
-
// Assume the worker is already activated if there's no pending registration
|
|
109
|
-
// (i.e. when reloading the page after a successful activation).
|
|
110
108
|
if (pendingInstance) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
109
|
+
const activationPromise = new DeferredPromise<void>()
|
|
110
|
+
|
|
111
|
+
pendingInstance.addEventListener('statechange', () => {
|
|
112
|
+
if (pendingInstance.state === 'activated') {
|
|
113
|
+
activationPromise.resolve()
|
|
114
|
+
}
|
|
117
115
|
})
|
|
116
|
+
|
|
117
|
+
// Wait until the worker is activated.
|
|
118
|
+
// Assume the worker is already activated if there's no pending registration
|
|
119
|
+
// (i.e. when reloading the page after a successful activation).
|
|
120
|
+
await activationPromise
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// Print the activation message only after the worker has been activated.
|
|
121
124
|
await enableMocking(context, options).catch((error) => {
|
|
122
|
-
|
|
125
|
+
devUtils.error(
|
|
126
|
+
'Failed to enable mocking. Please report this on GitHub (https://github.com/mswjs/msw/issues) and include the original error below.',
|
|
127
|
+
)
|
|
128
|
+
throw error
|
|
123
129
|
})
|
|
124
130
|
|
|
125
131
|
return registration
|
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { StartOptions, SetupWorkerInternalContext } from '../../glossary'
|
|
1
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
2
|
+
import type { StartOptions, SetupWorkerInternalContext } from '../../glossary'
|
|
3
3
|
import { printStartMessage } from './printStartMessage'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Signals the worker to enable the interception of requests.
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
8
|
+
export function enableMocking(
|
|
9
9
|
context: SetupWorkerInternalContext,
|
|
10
10
|
options: StartOptions,
|
|
11
|
-
) {
|
|
12
|
-
|
|
13
|
-
const { payload } = await context.events.once('MOCKING_ENABLED')
|
|
11
|
+
): Promise<boolean> {
|
|
12
|
+
const mockingEnabledPromise = new DeferredPromise<boolean>()
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
devUtils.warn(
|
|
20
|
-
`Found a redundant "worker.start()" call. Note that starting the worker while mocking is already enabled will have no effect. Consider removing this "worker.start()" call.`,
|
|
21
|
-
)
|
|
22
|
-
return
|
|
23
|
-
}
|
|
14
|
+
context.workerChannel.postMessage('MOCK_ACTIVATE')
|
|
15
|
+
context.workerChannel.once('MOCKING_ENABLED', async (event) => {
|
|
16
|
+
context.isMockingEnabled = true
|
|
17
|
+
const worker = await context.workerPromise
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
printStartMessage({
|
|
20
|
+
quiet: options.quiet,
|
|
21
|
+
workerScope: context.registration?.scope,
|
|
22
|
+
workerUrl: worker.scriptURL,
|
|
23
|
+
client: event.data.client,
|
|
24
|
+
})
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
quiet: options.quiet,
|
|
29
|
-
workerScope: context.registration?.scope,
|
|
30
|
-
workerUrl: context.worker?.scriptURL,
|
|
31
|
-
client: payload.client,
|
|
26
|
+
mockingEnabledPromise.resolve(true)
|
|
32
27
|
})
|
|
28
|
+
|
|
29
|
+
return mockingEnabledPromise
|
|
33
30
|
}
|
|
@@ -19,7 +19,6 @@ export function printStartMessage(args: PrintStartMessageArgs = {}) {
|
|
|
19
19
|
|
|
20
20
|
const message = args.message || 'Mocking enabled.'
|
|
21
21
|
|
|
22
|
-
// eslint-disable-next-line no-console
|
|
23
22
|
console.groupCollapsed(
|
|
24
23
|
`%c${devUtils.formatMessage(message)}`,
|
|
25
24
|
'color:orangered;font-weight:bold;',
|
|
@@ -48,6 +47,5 @@ export function printStartMessage(args: PrintStartMessageArgs = {}) {
|
|
|
48
47
|
console.log('Client ID: %s (%s)', args.client.id, args.client.frameType)
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
// eslint-disable-next-line no-console
|
|
52
50
|
console.groupEnd()
|
|
53
51
|
}
|
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
2
2
|
import type { SetupWorkerInternalContext } from '../setupWorker/glossary'
|
|
3
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Check whether the registered Service Worker has been
|
|
6
7
|
* generated by the installed version of the library.
|
|
7
8
|
* Prints a warning message if the worker scripts mismatch.
|
|
8
9
|
*/
|
|
9
|
-
export
|
|
10
|
+
export function checkWorkerIntegrity(
|
|
10
11
|
context: SetupWorkerInternalContext,
|
|
11
12
|
): Promise<void> {
|
|
12
|
-
|
|
13
|
-
context.workerChannel.send('INTEGRITY_CHECK_REQUEST')
|
|
13
|
+
const integrityCheckPromise = new DeferredPromise<void>()
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// Request the integrity checksum from the registered worker.
|
|
16
|
+
context.workerChannel.postMessage('INTEGRITY_CHECK_REQUEST')
|
|
17
|
+
context.workerChannel.once('INTEGRITY_CHECK_RESPONSE', (event) => {
|
|
18
|
+
const { checksum, packageVersion } = event.data
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
// Compare the response from the Service Worker and the
|
|
21
|
+
// global variable set during the build.
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// The integrity is validated based on the worker script's checksum
|
|
24
|
+
// that's derived from its minified content during the build.
|
|
25
|
+
// The "SERVICE_WORKER_CHECKSUM" global variable is injected by the build.
|
|
26
|
+
if (checksum !== SERVICE_WORKER_CHECKSUM) {
|
|
27
|
+
devUtils.warn(
|
|
28
|
+
`The currently registered Service Worker has been generated by a different version of MSW (${packageVersion}) and may not be fully compatible with the installed version.
|
|
26
29
|
|
|
27
30
|
It's recommended you update your worker script by running this command:
|
|
28
31
|
|
|
29
32
|
\u2022 npx msw init <PUBLIC_DIR>
|
|
30
33
|
|
|
31
34
|
You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`,
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
integrityCheckPromise.resolve()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return integrityCheckPromise
|
|
34
42
|
}
|