Skip to content

Commit 95029c7

Browse files
committed
fix
1 parent f281229 commit 95029c7

File tree

3 files changed

+439
-462
lines changed

3 files changed

+439
-462
lines changed

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,7 @@
9191
"vite": "6.3.5",
9292
"vite-plugin-externalize-deps": "0.9.0",
9393
"vite-plugin-html": "3.2.2",
94-
<<<<<<< HEAD
9594
"vitest": "3.2.3",
96-
=======
97-
"vitest": "3.2.1",
98-
>>>>>>> a725409855 (Legg til vitest browser mode)
9995
"vitest-canvas-mock": "0.3.3"
10096
},
10197
"resolutions": {

public/mockServiceWorker.js

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
/* eslint-disable */
2+
/* tslint:disable */
3+
4+
/**
5+
* Mock Service Worker.
6+
* @see https://github.com/mswjs/msw
7+
* - Please do NOT modify this file.
8+
*/
9+
10+
const PACKAGE_VERSION = '2.10.2'
11+
const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af'
12+
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
13+
const activeClientIds = new Set()
14+
15+
addEventListener('install', function () {
16+
self.skipWaiting()
17+
})
18+
19+
addEventListener('activate', function (event) {
20+
event.waitUntil(self.clients.claim())
21+
})
22+
23+
addEventListener('message', async function (event) {
24+
const clientId = Reflect.get(event.source || {}, 'id')
25+
26+
if (!clientId || !self.clients) {
27+
return
28+
}
29+
30+
const client = await self.clients.get(clientId)
31+
32+
if (!client) {
33+
return
34+
}
35+
36+
const allClients = await self.clients.matchAll({
37+
type: 'window',
38+
})
39+
40+
switch (event.data) {
41+
case 'KEEPALIVE_REQUEST': {
42+
sendToClient(client, {
43+
type: 'KEEPALIVE_RESPONSE',
44+
})
45+
break
46+
}
47+
48+
case 'INTEGRITY_CHECK_REQUEST': {
49+
sendToClient(client, {
50+
type: 'INTEGRITY_CHECK_RESPONSE',
51+
payload: {
52+
packageVersion: PACKAGE_VERSION,
53+
checksum: INTEGRITY_CHECKSUM,
54+
},
55+
})
56+
break
57+
}
58+
59+
case 'MOCK_ACTIVATE': {
60+
activeClientIds.add(clientId)
61+
62+
sendToClient(client, {
63+
type: 'MOCKING_ENABLED',
64+
payload: {
65+
client: {
66+
id: client.id,
67+
frameType: client.frameType,
68+
},
69+
},
70+
})
71+
break
72+
}
73+
74+
case 'MOCK_DEACTIVATE': {
75+
activeClientIds.delete(clientId)
76+
break
77+
}
78+
79+
case 'CLIENT_CLOSED': {
80+
activeClientIds.delete(clientId)
81+
82+
const remainingClients = allClients.filter((client) => {
83+
return client.id !== clientId
84+
})
85+
86+
// Unregister itself when there are no more clients
87+
if (remainingClients.length === 0) {
88+
self.registration.unregister()
89+
}
90+
91+
break
92+
}
93+
}
94+
})
95+
96+
addEventListener('fetch', function (event) {
97+
// Bypass navigation requests.
98+
if (event.request.mode === 'navigate') {
99+
return
100+
}
101+
102+
// Opening the DevTools triggers the "only-if-cached" request
103+
// that cannot be handled by the worker. Bypass such requests.
104+
if (
105+
event.request.cache === 'only-if-cached' &&
106+
event.request.mode !== 'same-origin'
107+
) {
108+
return
109+
}
110+
111+
// Bypass all requests when there are no active clients.
112+
// Prevents the self-unregistered worked from handling requests
113+
// after it's been deleted (still remains active until the next reload).
114+
if (activeClientIds.size === 0) {
115+
return
116+
}
117+
118+
const requestId = crypto.randomUUID()
119+
event.respondWith(handleRequest(event, requestId))
120+
})
121+
122+
/**
123+
* @param {FetchEvent} event
124+
* @param {string} requestId
125+
*/
126+
async function handleRequest(event, requestId) {
127+
const client = await resolveMainClient(event)
128+
const requestCloneForEvents = event.request.clone()
129+
const response = await getResponse(event, client, requestId)
130+
131+
// Send back the response clone for the "response:*" life-cycle events.
132+
// Ensure MSW is active and ready to handle the message, otherwise
133+
// this message will pend indefinitely.
134+
if (client && activeClientIds.has(client.id)) {
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: {
151+
type: responseClone.type,
152+
status: responseClone.status,
153+
statusText: responseClone.statusText,
154+
headers: Object.fromEntries(responseClone.headers.entries()),
155+
body: responseClone.body,
156+
},
157+
},
158+
},
159+
responseClone.body ? [serializedRequest.body, responseClone.body] : [],
160+
)
161+
}
162+
163+
return response
164+
}
165+
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+
*/
174+
async function resolveMainClient(event) {
175+
const client = await self.clients.get(event.clientId)
176+
177+
if (activeClientIds.has(event.clientId)) {
178+
return client
179+
}
180+
181+
if (client?.frameType === 'top-level') {
182+
return client
183+
}
184+
185+
const allClients = await self.clients.matchAll({
186+
type: 'window',
187+
})
188+
189+
return allClients
190+
.filter((client) => {
191+
// Get only those clients that are currently visible.
192+
return client.visibilityState === 'visible'
193+
})
194+
.find((client) => {
195+
// Find the client ID that's recorded in the
196+
// set of clients that have registered the worker.
197+
return activeClientIds.has(client.id)
198+
})
199+
}
200+
201+
/**
202+
* @param {FetchEvent} event
203+
* @param {Client | undefined} client
204+
* @param {string} requestId
205+
* @returns {Promise<Response>}
206+
*/
207+
async function getResponse(event, client, requestId) {
208+
// Clone the request because it might've been already used
209+
// (i.e. its body has been read and sent to the client).
210+
const requestClone = event.request.clone()
211+
212+
function passthrough() {
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+
)
226+
227+
if (filteredValues.length > 0) {
228+
headers.set('accept', filteredValues.join(', '))
229+
} else {
230+
headers.delete('accept')
231+
}
232+
}
233+
234+
return fetch(requestClone, { headers })
235+
}
236+
237+
// Bypass mocking when the client is not active.
238+
if (!client) {
239+
return passthrough()
240+
}
241+
242+
// Bypass initial page load requests (i.e. static assets).
243+
// The absence of the immediate/parent client in the map of the active clients
244+
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
245+
// and is not ready to handle requests.
246+
if (!activeClientIds.has(client.id)) {
247+
return passthrough()
248+
}
249+
250+
// Notify the client that a request has been intercepted.
251+
const serializedRequest = await serializeRequest(event.request)
252+
const clientMessage = await sendToClient(
253+
client,
254+
{
255+
type: 'REQUEST',
256+
payload: {
257+
id: requestId,
258+
...serializedRequest,
259+
},
260+
},
261+
[serializedRequest.body],
262+
)
263+
264+
switch (clientMessage.type) {
265+
case 'MOCK_RESPONSE': {
266+
return respondWithMock(clientMessage.data)
267+
}
268+
269+
case 'PASSTHROUGH': {
270+
return passthrough()
271+
}
272+
}
273+
274+
return passthrough()
275+
}
276+
277+
/**
278+
* @param {Client} client
279+
* @param {any} message
280+
* @param {Array<Transferable>} transferrables
281+
* @returns {Promise<any>}
282+
*/
283+
function sendToClient(client, message, transferrables = []) {
284+
return new Promise((resolve, reject) => {
285+
const channel = new MessageChannel()
286+
287+
channel.port1.onmessage = (event) => {
288+
if (event.data && event.data.error) {
289+
return reject(event.data.error)
290+
}
291+
292+
resolve(event.data)
293+
}
294+
295+
client.postMessage(message, [
296+
channel.port2,
297+
...transferrables.filter(Boolean),
298+
])
299+
})
300+
}
301+
302+
/**
303+
* @param {Response} response
304+
* @returns {Response}
305+
*/
306+
function respondWithMock(response) {
307+
// Setting response status code to 0 is a no-op.
308+
// However, when responding with a "Response.error()", the produced Response
309+
// instance will have status code set to 0. Since it's not possible to create
310+
// a Response instance with status code 0, handle that use-case separately.
311+
if (response.status === 0) {
312+
return Response.error()
313+
}
314+
315+
const mockedResponse = new Response(response.body, response)
316+
317+
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
318+
value: true,
319+
enumerable: true,
320+
})
321+
322+
return mockedResponse
323+
}
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)