@msw/playwright 0.6.3 → 0.6.5

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.
@@ -1,7 +1,6 @@
1
1
  import { invariant } from "outvariant";
2
2
  import { RequestHandler, SetupApi, WebSocketHandler, handleRequest, isCommonAssetRequest } from "msw";
3
3
  import { CancelableCloseEvent, CancelableMessageEvent } from "@mswjs/interceptors/WebSocket";
4
-
5
4
  //#region src/fixture.ts
6
5
  function defineNetworkFixture(options) {
7
6
  return new SetupPlaywrightApi({
@@ -37,7 +36,7 @@ var SetupPlaywrightApi = class extends SetupApi {
37
36
  * requests through the matching logic below.
38
37
  * @see https://github.com/mswjs/playwright/issues/13
39
38
  */
40
- if (this.options.skipAssetRequests && isCommonAssetRequest(fetchRequest)) return route.fallback();
39
+ if (this.options.skipAssetRequests && isCommonAssetRequest(fetchRequest)) return this.safelyHandleRoute(() => route.fallback());
41
40
  const handlers = this.handlersController.currentHandlers().filter((handler) => {
42
41
  return handler instanceof RequestHandler;
43
42
  });
@@ -51,14 +50,16 @@ var SetupPlaywrightApi = class extends SetupApi {
51
50
  baseUrl
52
51
  } });
53
52
  if (response) {
54
- if (response.status === 0) return route.abort();
55
- return route.fulfill({
56
- status: response.status,
57
- headers: Object.fromEntries(response.headers),
58
- body: response.body ? Buffer.from(await response.arrayBuffer()) : void 0
53
+ if (response.status === 0) return this.safelyHandleRoute(() => route.abort());
54
+ return this.safelyHandleRoute(async () => {
55
+ return route.fulfill({
56
+ status: response.status,
57
+ headers: Object.fromEntries(response.headers),
58
+ body: response.body ? Buffer.from(await response.arrayBuffer()) : void 0
59
+ });
59
60
  });
60
61
  }
61
- return route.fallback();
62
+ return this.safelyHandleRoute(() => route.fallback());
62
63
  });
63
64
  await context.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (route) => {
64
65
  const allWebSocketHandlers = this.handlersController.currentHandlers().filter((handler) => {
@@ -90,6 +91,21 @@ var SetupPlaywrightApi = class extends SetupApi {
90
91
  if (url === "about:blank") return;
91
92
  return decodeURI(new URL(encodeURI(url)).origin);
92
93
  }
94
+ async safelyHandleRoute(callback) {
95
+ try {
96
+ await callback();
97
+ } catch (error) {
98
+ /**
99
+ * @note Ignore "Route is already handled!" errors.
100
+ * Playwright has a bug where requests terminated due to navigation
101
+ * cause your in-flight route handlers to throw. There's no means to
102
+ * detect that scenario as both "route.handled" and "route._handlingPromise" are internal.
103
+ * @see https://github.com/mswjs/playwright/issues/35
104
+ */
105
+ if (error instanceof Error && /route is already handled/i.test(error.message)) return;
106
+ throw error;
107
+ }
108
+ }
93
109
  };
94
110
  var PlaywrightWebSocketClientConnection = class {
95
111
  id;
@@ -142,13 +158,12 @@ var PlaywrightWebSocketClientConnection = class {
142
158
  */
143
159
  const target = {};
144
160
  switch (type) {
145
- case "message": {
161
+ case "message":
146
162
  this.ws.onMessage((data) => {
147
163
  listener.call(target, new CancelableMessageEvent("message", { data }));
148
164
  });
149
165
  break;
150
- }
151
- case "close": {
166
+ case "close":
152
167
  this.ws.onClose((code, reason) => {
153
168
  listener.call(target, new CancelableCloseEvent("close", {
154
169
  code,
@@ -156,7 +171,6 @@ var PlaywrightWebSocketClientConnection = class {
156
171
  }));
157
172
  });
158
173
  break;
159
- }
160
174
  }
161
175
  }
162
176
  removeEventListener(event, listener, options) {
@@ -209,13 +223,12 @@ var PlaywrightWebSocketServerConnection = class {
209
223
  }
210
224
  const target = {};
211
225
  switch (type) {
212
- case "message": {
226
+ case "message":
213
227
  this.#server.onMessage((data) => {
214
228
  listener.call(target, new CancelableMessageEvent("message", { data }));
215
229
  });
216
230
  break;
217
- }
218
- case "close": {
231
+ case "close":
219
232
  this.#server.onClose((code, reason) => {
220
233
  listener.call(target, new CancelableCloseEvent("close", {
221
234
  code,
@@ -223,7 +236,6 @@ var PlaywrightWebSocketServerConnection = class {
223
236
  }));
224
237
  });
225
238
  break;
226
- }
227
239
  }
228
240
  }
229
241
  removeEventListener(type, listener, options) {
@@ -241,6 +253,5 @@ async function unrouteWebSocket(target, url, handler) {
241
253
  if (route.url === url && (handler != null ? route.handler === handler : true)) target._webSocketRoutes.splice(i, 1);
242
254
  }
243
255
  }
244
-
245
256
  //#endregion
246
- export { defineNetworkFixture };
257
+ export { defineNetworkFixture };
package/package.json CHANGED
@@ -1,10 +1,16 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@msw/playwright",
4
- "version": "0.6.3",
4
+ "version": "0.6.5",
5
5
  "description": "Mock Service Worker binding for Playwright",
6
- "main": "./build/index.js",
7
- "types": "./build/index.d.ts",
6
+ "main": "./build/index.mjs",
7
+ "types": "./build/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./build/index.d.mts",
11
+ "default": "./build/index.mjs"
12
+ }
13
+ },
8
14
  "files": [
9
15
  "./src",
10
16
  "./build"
@@ -38,17 +44,17 @@
38
44
  "devDependencies": {
39
45
  "@epic-web/test-server": "^0.1.6",
40
46
  "@ossjs/release": "^0.10.1",
41
- "@playwright/test": "^1.58.1",
47
+ "@playwright/test": "^1.58.2",
42
48
  "@types/node": "^22.15.29",
43
49
  "@types/sinon": "^21.0.0",
44
50
  "msw": "^2.12.10",
45
- "sinon": "^21.0.1",
46
- "tsdown": "^0.12.7",
51
+ "sinon": "^21.0.2",
52
+ "tsdown": "^0.21.0",
47
53
  "typescript": "^5.9.3",
48
54
  "vite": "^7.3.1"
49
55
  },
50
56
  "dependencies": {
51
- "@mswjs/interceptors": "^0.41.2",
57
+ "@mswjs/interceptors": "^0.41.3",
52
58
  "outvariant": "^1.4.3"
53
59
  },
54
60
  "scripts": {
package/src/fixture.ts CHANGED
@@ -99,7 +99,7 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
99
99
  this.options.skipAssetRequests &&
100
100
  isCommonAssetRequest(fetchRequest)
101
101
  ) {
102
- return route.fallback()
102
+ return this.safelyHandleRoute(() => route.fallback())
103
103
  }
104
104
 
105
105
  const handlers = this.handlersController
@@ -134,19 +134,21 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
134
134
 
135
135
  if (response) {
136
136
  if (response.status === 0) {
137
- return route.abort()
137
+ return this.safelyHandleRoute(() => route.abort())
138
138
  }
139
139
 
140
- return route.fulfill({
141
- status: response.status,
142
- headers: Object.fromEntries(response.headers),
143
- body: response.body
144
- ? Buffer.from(await response.arrayBuffer())
145
- : undefined,
140
+ return this.safelyHandleRoute(async () => {
141
+ return route.fulfill({
142
+ status: response.status,
143
+ headers: Object.fromEntries(response.headers),
144
+ body: response.body
145
+ ? Buffer.from(await response.arrayBuffer())
146
+ : undefined,
147
+ })
146
148
  })
147
149
  }
148
150
 
149
- return route.fallback()
151
+ return this.safelyHandleRoute(() => route.fallback())
150
152
  },
151
153
  )
152
154
 
@@ -201,6 +203,30 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
201
203
  // Encode/decode to preserve escape characters.
202
204
  return decodeURI(new URL(encodeURI(url)).origin)
203
205
  }
206
+
207
+ private async safelyHandleRoute(
208
+ callback: () => Promise<void>,
209
+ ): Promise<void> {
210
+ try {
211
+ await callback()
212
+ } catch (error) {
213
+ /**
214
+ * @note Ignore "Route is already handled!" errors.
215
+ * Playwright has a bug where requests terminated due to navigation
216
+ * cause your in-flight route handlers to throw. There's no means to
217
+ * detect that scenario as both "route.handled" and "route._handlingPromise" are internal.
218
+ * @see https://github.com/mswjs/playwright/issues/35
219
+ */
220
+ if (
221
+ error instanceof Error &&
222
+ /route is already handled/i.test(error.message)
223
+ ) {
224
+ return
225
+ }
226
+
227
+ throw error
228
+ }
229
+ }
204
230
  }
205
231
 
206
232
  class PlaywrightWebSocketClientConnection implements WebSocketClientConnectionProtocol {
package/build/index.d.ts DELETED
@@ -1,30 +0,0 @@
1
- import { AnyHandler, LifeCycleEventsMap, SetupApi, UnhandledRequestStrategy } from "msw";
2
- import { BrowserContext } from "@playwright/test";
3
-
4
- //#region src/fixture.d.ts
5
- interface NetworkFixtureOptions {
6
- context: BrowserContext;
7
- handlers?: Array<AnyHandler>;
8
- onUnhandledRequest?: UnhandledRequestStrategy;
9
- /**
10
- * Skip common asset requests (e.g. `*.html`, `*.css`, `*.js`, etc).
11
- * This improves performance for certian projects.
12
- * @default true
13
- *
14
- * @see https://mswjs.io/docs/api/is-common-asset-request
15
- */
16
- skipAssetRequests?: boolean;
17
- }
18
- type NetworkFixture = Omit<SetupApi<LifeCycleEventsMap>, 'dispose'> & {
19
- enable: () => Promise<void>;
20
- disable: () => Promise<void>;
21
- };
22
- declare function defineNetworkFixture(options: NetworkFixtureOptions): NetworkFixture;
23
- /**
24
- * @note Use a match-all RegExp with an optional group as the predicate
25
- * for the `page.route()`/`page.unroute()` calls. Playwright treats given RegExp
26
- * as the handler ID, which allows us to remove only those handlers introduces by us
27
- * without carrying the reference to the handler function around.
28
- */
29
- //#endregion
30
- export { NetworkFixture, NetworkFixtureOptions, defineNetworkFixture };