Skip to content

Commit df3e3f3

Browse files
committed
update msw to latest and cypress to 15 beta
1 parent 7f8c7b9 commit df3e3f3

29 files changed

+3522
-1866
lines changed

angular-standalone/package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

angular-standalone/package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"@angular/platform-browser": "^20.1.6",
2020
"@angular/platform-browser-dynamic": "^20.1.6",
2121
"@angular/router": "^20.1.6",
22-
"msw": "^2.3.1",
22+
"msw": "^2.10.5",
2323
"rxjs": "~7.8.2",
2424
"tslib": "^2.8.1",
2525
"zone.js": "~0.15.1"
@@ -30,7 +30,7 @@
3030
"@angular/compiler-cli": "^20.1.6",
3131
"@tailwindcss/postcss": "^4.1.11",
3232
"@types/jasmine": "~5.1.0",
33-
"cypress": "^14.0.0",
33+
"cypress": "https://cdn.cypress.io/beta/npm/15.0.0/linux-x64/develop-c8606c21ae148459fe54d74e040fd2ec5bdc3d08/cypress.tgz",
3434
"jasmine-core": "~5.8.0",
3535
"karma": "~6.4.0",
3636
"karma-chrome-launcher": "~3.2.0",
@@ -40,5 +40,10 @@
4040
"postcss": "^8.5.6",
4141
"tailwindcss": "^4.1.11",
4242
"typescript": "~5.8.3"
43+
},
44+
"msw": {
45+
"workerDirectory": [
46+
"public"
47+
]
4348
}
44-
}
49+
}

angular-standalone/public/mockServiceWorker.js

Lines changed: 120 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,23 @@
55
* Mock Service Worker.
66
* @see https://github.com/mswjs/msw
77
* - Please do NOT modify this file.
8-
* - Please do NOT serve this file on production.
98
*/
109

11-
const PACKAGE_VERSION = '2.3.1'
12-
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
10+
const PACKAGE_VERSION = '2.10.5'
11+
const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af'
1312
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
1413
const activeClientIds = new Set()
1514

16-
self.addEventListener('install', function () {
15+
addEventListener('install', function () {
1716
self.skipWaiting()
1817
})
1918

20-
self.addEventListener('activate', function (event) {
19+
addEventListener('activate', function (event) {
2120
event.waitUntil(self.clients.claim())
2221
})
2322

24-
self.addEventListener('message', async function (event) {
25-
const clientId = event.source.id
23+
addEventListener('message', async function (event) {
24+
const clientId = Reflect.get(event.source || {}, 'id')
2625

2726
if (!clientId || !self.clients) {
2827
return
@@ -62,7 +61,12 @@ self.addEventListener('message', async function (event) {
6261

6362
sendToClient(client, {
6463
type: 'MOCKING_ENABLED',
65-
payload: true,
64+
payload: {
65+
client: {
66+
id: client.id,
67+
frameType: client.frameType,
68+
},
69+
},
6670
})
6771
break
6872
}
@@ -89,17 +93,18 @@ self.addEventListener('message', async function (event) {
8993
}
9094
})
9195

92-
self.addEventListener('fetch', function (event) {
93-
const { request } = event
94-
96+
addEventListener('fetch', function (event) {
9597
// Bypass navigation requests.
96-
if (request.mode === 'navigate') {
98+
if (event.request.mode === 'navigate') {
9799
return
98100
}
99101

100102
// Opening the DevTools triggers the "only-if-cached" request
101103
// that cannot be handled by the worker. Bypass such requests.
102-
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
104+
if (
105+
event.request.cache === 'only-if-cached' &&
106+
event.request.mode !== 'same-origin'
107+
) {
103108
return
104109
}
105110

@@ -110,51 +115,69 @@ self.addEventListener('fetch', function (event) {
110115
return
111116
}
112117

113-
// Generate unique request ID.
114118
const requestId = crypto.randomUUID()
115119
event.respondWith(handleRequest(event, requestId))
116120
})
117121

122+
/**
123+
* @param {FetchEvent} event
124+
* @param {string} requestId
125+
*/
118126
async function handleRequest(event, requestId) {
119127
const client = await resolveMainClient(event)
128+
const requestCloneForEvents = event.request.clone()
120129
const response = await getResponse(event, client, requestId)
121130

122131
// Send back the response clone for the "response:*" life-cycle events.
123132
// Ensure MSW is active and ready to handle the message, otherwise
124133
// this message will pend indefinitely.
125134
if (client && activeClientIds.has(client.id)) {
126-
;(async function () {
127-
const responseClone = response.clone()
128-
129-
sendToClient(
130-
client,
131-
{
132-
type: 'RESPONSE',
133-
payload: {
134-
requestId,
135-
isMockedResponse: IS_MOCKED_RESPONSE in response,
135+
const serializedRequest = await serializeRequest(requestCloneForEvents)
136+
137+
// Clone the response so both the client and the library could consume it.
138+
const responseClone = response.clone()
139+
140+
sendToClient(
141+
client,
142+
{
143+
type: 'RESPONSE',
144+
payload: {
145+
isMockedResponse: IS_MOCKED_RESPONSE in response,
146+
request: {
147+
id: requestId,
148+
...serializedRequest,
149+
},
150+
response: {
136151
type: responseClone.type,
137152
status: responseClone.status,
138153
statusText: responseClone.statusText,
139-
body: responseClone.body,
140154
headers: Object.fromEntries(responseClone.headers.entries()),
155+
body: responseClone.body,
141156
},
142157
},
143-
[responseClone.body],
144-
)
145-
})()
158+
},
159+
responseClone.body ? [serializedRequest.body, responseClone.body] : [],
160+
)
146161
}
147162

148163
return response
149164
}
150165

151-
// Resolve the main client for the given event.
152-
// Client that issues a request doesn't necessarily equal the client
153-
// that registered the worker. It's with the latter the worker should
154-
// communicate with during the response resolving phase.
166+
/**
167+
* Resolve the main client for the given event.
168+
* Client that issues a request doesn't necessarily equal the client
169+
* that registered the worker. It's with the latter the worker should
170+
* communicate with during the response resolving phase.
171+
* @param {FetchEvent} event
172+
* @returns {Promise<Client | undefined>}
173+
*/
155174
async function resolveMainClient(event) {
156175
const client = await self.clients.get(event.clientId)
157176

177+
if (activeClientIds.has(event.clientId)) {
178+
return client
179+
}
180+
158181
if (client?.frameType === 'top-level') {
159182
return client
160183
}
@@ -175,20 +198,38 @@ async function resolveMainClient(event) {
175198
})
176199
}
177200

201+
/**
202+
* @param {FetchEvent} event
203+
* @param {Client | undefined} client
204+
* @param {string} requestId
205+
* @returns {Promise<Response>}
206+
*/
178207
async function getResponse(event, client, requestId) {
179-
const { request } = event
180-
181208
// Clone the request because it might've been already used
182209
// (i.e. its body has been read and sent to the client).
183-
const requestClone = request.clone()
210+
const requestClone = event.request.clone()
184211

185212
function passthrough() {
186-
const headers = Object.fromEntries(requestClone.headers.entries())
213+
// Cast the request headers to a new Headers instance
214+
// so the headers can be manipulated with.
215+
const headers = new Headers(requestClone.headers)
216+
217+
// Remove the "accept" header value that marked this request as passthrough.
218+
// This prevents request alteration and also keeps it compliant with the
219+
// user-defined CORS policies.
220+
const acceptHeader = headers.get('accept')
221+
if (acceptHeader) {
222+
const values = acceptHeader.split(',').map((value) => value.trim())
223+
const filteredValues = values.filter(
224+
(value) => value !== 'msw/passthrough',
225+
)
187226

188-
// Remove internal MSW request header so the passthrough request
189-
// complies with any potential CORS preflight checks on the server.
190-
// Some servers forbid unknown request headers.
191-
delete headers['x-msw-intention']
227+
if (filteredValues.length > 0) {
228+
headers.set('accept', filteredValues.join(', '))
229+
} else {
230+
headers.delete('accept')
231+
}
232+
}
192233

193234
return fetch(requestClone, { headers })
194235
}
@@ -207,29 +248,17 @@ async function getResponse(event, client, requestId) {
207248
}
208249

209250
// Notify the client that a request has been intercepted.
210-
const requestBuffer = await request.arrayBuffer()
251+
const serializedRequest = await serializeRequest(event.request)
211252
const clientMessage = await sendToClient(
212253
client,
213254
{
214255
type: 'REQUEST',
215256
payload: {
216257
id: requestId,
217-
url: request.url,
218-
mode: request.mode,
219-
method: request.method,
220-
headers: Object.fromEntries(request.headers.entries()),
221-
cache: request.cache,
222-
credentials: request.credentials,
223-
destination: request.destination,
224-
integrity: request.integrity,
225-
redirect: request.redirect,
226-
referrer: request.referrer,
227-
referrerPolicy: request.referrerPolicy,
228-
body: requestBuffer,
229-
keepalive: request.keepalive,
258+
...serializedRequest,
230259
},
231260
},
232-
[requestBuffer],
261+
[serializedRequest.body],
233262
)
234263

235264
switch (clientMessage.type) {
@@ -245,6 +274,12 @@ async function getResponse(event, client, requestId) {
245274
return passthrough()
246275
}
247276

277+
/**
278+
* @param {Client} client
279+
* @param {any} message
280+
* @param {Array<Transferable>} transferrables
281+
* @returns {Promise<any>}
282+
*/
248283
function sendToClient(client, message, transferrables = []) {
249284
return new Promise((resolve, reject) => {
250285
const channel = new MessageChannel()
@@ -257,14 +292,18 @@ function sendToClient(client, message, transferrables = []) {
257292
resolve(event.data)
258293
}
259294

260-
client.postMessage(
261-
message,
262-
[channel.port2].concat(transferrables.filter(Boolean)),
263-
)
295+
client.postMessage(message, [
296+
channel.port2,
297+
...transferrables.filter(Boolean),
298+
])
264299
})
265300
}
266301

267-
async function respondWithMock(response) {
302+
/**
303+
* @param {Response} response
304+
* @returns {Response}
305+
*/
306+
function respondWithMock(response) {
268307
// Setting response status code to 0 is a no-op.
269308
// However, when responding with a "Response.error()", the produced Response
270309
// instance will have status code set to 0. Since it's not possible to create
@@ -282,3 +321,24 @@ async function respondWithMock(response) {
282321

283322
return mockedResponse
284323
}
324+
325+
/**
326+
* @param {Request} request
327+
*/
328+
async function serializeRequest(request) {
329+
return {
330+
url: request.url,
331+
mode: request.mode,
332+
method: request.method,
333+
headers: Object.fromEntries(request.headers.entries()),
334+
cache: request.cache,
335+
credentials: request.credentials,
336+
destination: request.destination,
337+
integrity: request.integrity,
338+
redirect: request.redirect,
339+
referrer: request.referrer,
340+
referrerPolicy: request.referrerPolicy,
341+
body: await request.arrayBuffer(),
342+
keepalive: request.keepalive,
343+
}
344+
}

0 commit comments

Comments
 (0)