Skip to content

Commit fa7af18

Browse files
authored
Upgrade msw (#1580)
1 parent 00664dc commit fa7af18

File tree

5 files changed

+178
-212
lines changed

5 files changed

+178
-212
lines changed

packages/redux-devtools-rtk-query-monitor/demo/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
"@chakra-ui/react": "^2.8.2",
1515
"@emotion/react": "^11.11.1",
1616
"@emotion/styled": "^11.11.0",
17-
"@mswjs/data": "^0.15.0",
17+
"@mswjs/data": "^0.16.1",
1818
"@redux-devtools/core": "^4.0.0",
1919
"@redux-devtools/dock-monitor": "^4.0.0",
2020
"@redux-devtools/rtk-query-monitor": "^5.0.0",
2121
"@reduxjs/toolkit": "^1.9.7",
2222
"framer-motion": "^10.16.16",
23-
"msw": "^1.3.2",
23+
"msw": "^2.0.11",
2424
"react": "^18.2.0",
2525
"react-dom": "^18.2.0",
2626
"react-icons": "^4.12.0",

packages/redux-devtools-rtk-query-monitor/demo/public/mockServiceWorker.js

Lines changed: 77 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
/* tslint:disable */
33

44
/**
5-
* Mock Service Worker (1.3.2).
5+
* Mock Service Worker (2.0.11).
66
* @see https://github.com/mswjs/msw
77
* - Please do NOT modify this file.
88
* - Please do NOT serve this file on production.
99
*/
1010

11-
const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'
11+
const INTEGRITY_CHECKSUM = 'c5f7f8e188b673ea4e677df7ea3c5a39'
12+
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
1213
const activeClientIds = new Set()
1314

1415
self.addEventListener('install', function () {
@@ -86,12 +87,6 @@ self.addEventListener('message', async function (event) {
8687

8788
self.addEventListener('fetch', function (event) {
8889
const { request } = event
89-
const accept = request.headers.get('accept') || ''
90-
91-
// Bypass server-sent events.
92-
if (accept.includes('text/event-stream')) {
93-
return
94-
}
9590

9691
// Bypass navigation requests.
9792
if (request.mode === 'navigate') {
@@ -112,29 +107,8 @@ self.addEventListener('fetch', function (event) {
112107
}
113108

114109
// Generate unique request ID.
115-
const requestId = Math.random().toString(16).slice(2)
116-
117-
event.respondWith(
118-
handleRequest(event, requestId).catch((error) => {
119-
if (error.name === 'NetworkError') {
120-
console.warn(
121-
'[MSW] Successfully emulated a network error for the "%s %s" request.',
122-
request.method,
123-
request.url,
124-
)
125-
return
126-
}
127-
128-
// At this point, any exception indicates an issue with the original request/response.
129-
console.error(
130-
`\
131-
[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`,
132-
request.method,
133-
request.url,
134-
`${error.name}: ${error.message}`,
135-
)
136-
}),
137-
)
110+
const requestId = crypto.randomUUID()
111+
event.respondWith(handleRequest(event, requestId))
138112
})
139113

140114
async function handleRequest(event, requestId) {
@@ -146,21 +120,24 @@ async function handleRequest(event, requestId) {
146120
// this message will pend indefinitely.
147121
if (client && activeClientIds.has(client.id)) {
148122
;(async function () {
149-
const clonedResponse = response.clone()
150-
sendToClient(client, {
151-
type: 'RESPONSE',
152-
payload: {
153-
requestId,
154-
type: clonedResponse.type,
155-
ok: clonedResponse.ok,
156-
status: clonedResponse.status,
157-
statusText: clonedResponse.statusText,
158-
body:
159-
clonedResponse.body === null ? null : await clonedResponse.text(),
160-
headers: Object.fromEntries(clonedResponse.headers.entries()),
161-
redirected: clonedResponse.redirected,
123+
const responseClone = response.clone()
124+
125+
sendToClient(
126+
client,
127+
{
128+
type: 'RESPONSE',
129+
payload: {
130+
requestId,
131+
isMockedResponse: IS_MOCKED_RESPONSE in response,
132+
type: responseClone.type,
133+
status: responseClone.status,
134+
statusText: responseClone.statusText,
135+
body: responseClone.body,
136+
headers: Object.fromEntries(responseClone.headers.entries()),
137+
},
162138
},
163-
})
139+
[responseClone.body],
140+
)
164141
})()
165142
}
166143

@@ -196,20 +173,20 @@ async function resolveMainClient(event) {
196173

197174
async function getResponse(event, client, requestId) {
198175
const { request } = event
199-
const clonedRequest = request.clone()
176+
177+
// Clone the request because it might've been already used
178+
// (i.e. its body has been read and sent to the client).
179+
const requestClone = request.clone()
200180

201181
function passthrough() {
202-
// Clone the request because it might've been already used
203-
// (i.e. its body has been read and sent to the client).
204-
const headers = Object.fromEntries(clonedRequest.headers.entries())
182+
const headers = Object.fromEntries(requestClone.headers.entries())
205183

206-
// Remove MSW-specific request headers so the bypassed requests
207-
// comply with the server's CORS preflight check.
208-
// Operate with the headers as an object because request "Headers"
209-
// are immutable.
210-
delete headers['x-msw-bypass']
184+
// Remove internal MSW request header so the passthrough request
185+
// complies with any potential CORS preflight checks on the server.
186+
// Some servers forbid unknown request headers.
187+
delete headers['x-msw-intention']
211188

212-
return fetch(clonedRequest, { headers })
189+
return fetch(requestClone, { headers })
213190
}
214191

215192
// Bypass mocking when the client is not active.
@@ -227,31 +204,36 @@ async function getResponse(event, client, requestId) {
227204

228205
// Bypass requests with the explicit bypass header.
229206
// Such requests can be issued by "ctx.fetch()".
230-
if (request.headers.get('x-msw-bypass') === 'true') {
207+
const mswIntention = request.headers.get('x-msw-intention')
208+
if (['bypass', 'passthrough'].includes(mswIntention)) {
231209
return passthrough()
232210
}
233211

234212
// Notify the client that a request has been intercepted.
235-
const clientMessage = await sendToClient(client, {
236-
type: 'REQUEST',
237-
payload: {
238-
id: requestId,
239-
url: request.url,
240-
method: request.method,
241-
headers: Object.fromEntries(request.headers.entries()),
242-
cache: request.cache,
243-
mode: request.mode,
244-
credentials: request.credentials,
245-
destination: request.destination,
246-
integrity: request.integrity,
247-
redirect: request.redirect,
248-
referrer: request.referrer,
249-
referrerPolicy: request.referrerPolicy,
250-
body: await request.text(),
251-
bodyUsed: request.bodyUsed,
252-
keepalive: request.keepalive,
213+
const requestBuffer = await request.arrayBuffer()
214+
const clientMessage = await sendToClient(
215+
client,
216+
{
217+
type: 'REQUEST',
218+
payload: {
219+
id: requestId,
220+
url: request.url,
221+
mode: request.mode,
222+
method: request.method,
223+
headers: Object.fromEntries(request.headers.entries()),
224+
cache: request.cache,
225+
credentials: request.credentials,
226+
destination: request.destination,
227+
integrity: request.integrity,
228+
redirect: request.redirect,
229+
referrer: request.referrer,
230+
referrerPolicy: request.referrerPolicy,
231+
body: requestBuffer,
232+
keepalive: request.keepalive,
233+
},
253234
},
254-
})
235+
[requestBuffer],
236+
)
255237

256238
switch (clientMessage.type) {
257239
case 'MOCK_RESPONSE': {
@@ -261,21 +243,12 @@ async function getResponse(event, client, requestId) {
261243
case 'MOCK_NOT_FOUND': {
262244
return passthrough()
263245
}
264-
265-
case 'NETWORK_ERROR': {
266-
const { name, message } = clientMessage.data
267-
const networkError = new Error(message)
268-
networkError.name = name
269-
270-
// Rejecting a "respondWith" promise emulates a network error.
271-
throw networkError
272-
}
273246
}
274247

275248
return passthrough()
276249
}
277250

278-
function sendToClient(client, message) {
251+
function sendToClient(client, message, transferrables = []) {
279252
return new Promise((resolve, reject) => {
280253
const channel = new MessageChannel()
281254

@@ -287,17 +260,28 @@ function sendToClient(client, message) {
287260
resolve(event.data)
288261
}
289262

290-
client.postMessage(message, [channel.port2])
263+
client.postMessage(
264+
message,
265+
[channel.port2].concat(transferrables.filter(Boolean)),
266+
)
291267
})
292268
}
293269

294-
function sleep(timeMs) {
295-
return new Promise((resolve) => {
296-
setTimeout(resolve, timeMs)
270+
async function respondWithMock(response) {
271+
// Setting response status code to 0 is a no-op.
272+
// However, when responding with a "Response.error()", the produced Response
273+
// instance will have status code set to 0. Since it's not possible to create
274+
// a Response instance with status code 0, handle that use-case separately.
275+
if (response.status === 0) {
276+
return Response.error()
277+
}
278+
279+
const mockedResponse = new Response(response.body, response)
280+
281+
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
282+
value: true,
283+
enumerable: true,
297284
})
298-
}
299285

300-
async function respondWithMock(response) {
301-
await sleep(response.delay)
302-
return new Response(response.body, response)
286+
return mockedResponse
303287
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { setupWorker } from 'msw';
1+
import { setupWorker } from 'msw/browser';
22
import { handlers } from './db';
33

44
export const worker = setupWorker(...handlers);

packages/redux-devtools-rtk-query-monitor/demo/src/mocks/db.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { factory, primaryKey } from '@mswjs/data';
22
import { nanoid } from '@reduxjs/toolkit';
3-
import { rest } from 'msw';
3+
import { http, HttpResponse, delay } from 'msw';
44
import { Post } from '../services/posts';
55

66
const db = factory({
@@ -19,16 +19,16 @@ const db = factory({
1919
});
2020

2121
export const handlers = [
22-
rest.post<Post, never, Post | { error: string }>(
22+
http.post<never, Post, Post | { error: string }>(
2323
'/posts',
24-
async (req, res, ctx) => {
25-
const { name } = req.body;
24+
async ({ request }) => {
25+
const { name } = await request.json();
2626

2727
if (Math.random() < 0.3) {
28-
return res(
29-
ctx.json({ error: 'Oh no, there was an error, try again.' }),
30-
ctx.status(500),
31-
ctx.delay(300),
28+
await delay(300);
29+
return HttpResponse.json(
30+
{ error: 'Oh no, there was an error, try again.' },
31+
{ status: 500 },
3232
);
3333
}
3434

@@ -37,28 +37,30 @@ export const handlers = [
3737
name,
3838
});
3939

40-
return res(ctx.json(post), ctx.delay(300));
40+
await delay(300);
41+
return HttpResponse.json(post);
4142
},
4243
),
43-
rest.put<Post, { id: string }, Post | { error: string }>(
44+
http.put<{ id: string }, Post, Post | { error: string }>(
4445
'/posts/:id',
45-
(req, res, ctx) => {
46-
const { name } = req.body;
46+
async ({ params, request }) => {
47+
const { name } = await request.json();
4748

4849
if (Math.random() < 0.3) {
49-
return res(
50-
ctx.json({ error: 'Oh no, there was an error, try again.' }),
51-
ctx.status(500),
52-
ctx.delay(300),
50+
await delay(300);
51+
return HttpResponse.json(
52+
{ error: 'Oh no, there was an error, try again.' },
53+
{ status: 500 },
5354
);
5455
}
5556

5657
const post = db.post.update({
57-
where: { id: { equals: req.params.id } },
58+
where: { id: { equals: params.id } },
5859
data: { name },
5960
});
6061

61-
return res(ctx.json(post!), ctx.delay(300));
62+
await delay(300);
63+
return HttpResponse.json(post);
6264
},
6365
),
6466
...db.post.toHandlers('rest'),

0 commit comments

Comments
 (0)