@msw/playwright 0.6.2 → 0.6.4

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/README.md CHANGED
@@ -41,7 +41,7 @@ interface Fixtures {
41
41
 
42
42
  const test = testBase.extend<Fixtures>({
43
43
  // Initial list of the network handlers.
44
- handlers: [[handlers], { option: true }],
44
+ handlers: [handlers, { option: true }],
45
45
 
46
46
  // A fixture you use to control the network in your tests.
47
47
  network: [
package/build/index.js CHANGED
@@ -24,7 +24,8 @@ var SetupPlaywrightApi = class extends SetupApi {
24
24
  this.options = options;
25
25
  }
26
26
  async enable() {
27
- await this.options.context.route(INTERNAL_MATCH_ALL_REG_EXP, async (route, request) => {
27
+ const { context } = this.options;
28
+ await context.route(INTERNAL_MATCH_ALL_REG_EXP, async (route, request) => {
28
29
  const fetchRequest = new Request(request.url(), {
29
30
  method: request.method(),
30
31
  headers: new Headers(await request.allHeaders()),
@@ -36,7 +37,7 @@ var SetupPlaywrightApi = class extends SetupApi {
36
37
  * requests through the matching logic below.
37
38
  * @see https://github.com/mswjs/playwright/issues/13
38
39
  */
39
- if (this.options.skipAssetRequests && isCommonAssetRequest(fetchRequest)) return route.continue();
40
+ if (this.options.skipAssetRequests && isCommonAssetRequest(fetchRequest)) return this.safelyHandleRoute(() => route.fallback());
40
41
  const handlers = this.handlersController.currentHandlers().filter((handler) => {
41
42
  return handler instanceof RequestHandler;
42
43
  });
@@ -50,16 +51,18 @@ var SetupPlaywrightApi = class extends SetupApi {
50
51
  baseUrl
51
52
  } });
52
53
  if (response) {
53
- if (response.status === 0) return route.abort();
54
- return route.fulfill({
55
- status: response.status,
56
- headers: Object.fromEntries(response.headers),
57
- body: response.body ? Buffer.from(await response.arrayBuffer()) : void 0
54
+ if (response.status === 0) return this.safelyHandleRoute(() => route.abort());
55
+ return this.safelyHandleRoute(async () => {
56
+ return route.fulfill({
57
+ status: response.status,
58
+ headers: Object.fromEntries(response.headers),
59
+ body: response.body ? Buffer.from(await response.arrayBuffer()) : void 0
60
+ });
58
61
  });
59
62
  }
60
- return route.continue();
63
+ return this.safelyHandleRoute(() => route.fallback());
61
64
  });
62
- await this.options.context.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (route) => {
65
+ await context.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (route) => {
63
66
  const allWebSocketHandlers = this.handlersController.currentHandlers().filter((handler) => {
64
67
  return handler instanceof WebSocketHandler;
65
68
  });
@@ -89,6 +92,21 @@ var SetupPlaywrightApi = class extends SetupApi {
89
92
  if (url === "about:blank") return;
90
93
  return decodeURI(new URL(encodeURI(url)).origin);
91
94
  }
95
+ async safelyHandleRoute(callback) {
96
+ try {
97
+ await callback();
98
+ } catch (error) {
99
+ /**
100
+ * @note Ignore "Route is already handled!" errors.
101
+ * Playwright has a bug where requests terminated due to navigation
102
+ * cause your in-flight route handlers to throw. There's no means to
103
+ * detect that scenario as both "route.handled" and "route._handlingPromise" are internal.
104
+ * @see https://github.com/mswjs/playwright/issues/35
105
+ */
106
+ if (error instanceof Error && /route is already handled/i.test(error.message)) return;
107
+ throw error;
108
+ }
109
+ }
92
110
  };
93
111
  var PlaywrightWebSocketClientConnection = class {
94
112
  id;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@msw/playwright",
4
- "version": "0.6.2",
4
+ "version": "0.6.4",
5
5
  "description": "Mock Service Worker binding for Playwright",
6
6
  "main": "./build/index.js",
7
7
  "types": "./build/index.d.ts",
package/src/fixture.ts CHANGED
@@ -77,8 +77,10 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
77
77
  }
78
78
 
79
79
  public async enable(): Promise<void> {
80
+ const { context } = this.options
81
+
80
82
  // Handle HTTP requests.
81
- await this.options.context.route(
83
+ await context.route(
82
84
  INTERNAL_MATCH_ALL_REG_EXP,
83
85
  async (route: Route, request: PlaywrightRequest) => {
84
86
  const fetchRequest = new Request(request.url(), {
@@ -97,7 +99,7 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
97
99
  this.options.skipAssetRequests &&
98
100
  isCommonAssetRequest(fetchRequest)
99
101
  ) {
100
- return route.continue()
102
+ return this.safelyHandleRoute(() => route.fallback())
101
103
  }
102
104
 
103
105
  const handlers = this.handlersController
@@ -132,58 +134,57 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
132
134
 
133
135
  if (response) {
134
136
  if (response.status === 0) {
135
- return route.abort()
137
+ return this.safelyHandleRoute(() => route.abort())
136
138
  }
137
139
 
138
- return route.fulfill({
139
- status: response.status,
140
- headers: Object.fromEntries(response.headers),
141
- body: response.body
142
- ? Buffer.from(await response.arrayBuffer())
143
- : 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
+ })
144
148
  })
145
149
  }
146
150
 
147
- return route.continue()
151
+ return this.safelyHandleRoute(() => route.fallback())
148
152
  },
149
153
  )
150
154
 
151
155
  // Handle WebSocket connections.
152
- await this.options.context.routeWebSocket(
153
- INTERNAL_MATCH_ALL_REG_EXP,
154
- async (route) => {
155
- const allWebSocketHandlers = this.handlersController
156
- .currentHandlers()
157
- .filter((handler) => {
158
- return handler instanceof WebSocketHandler
159
- })
156
+ await context.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (route) => {
157
+ const allWebSocketHandlers = this.handlersController
158
+ .currentHandlers()
159
+ .filter((handler) => {
160
+ return handler instanceof WebSocketHandler
161
+ })
160
162
 
161
- if (allWebSocketHandlers.length === 0) {
162
- route.connectToServer()
163
- return
164
- }
163
+ if (allWebSocketHandlers.length === 0) {
164
+ route.connectToServer()
165
+ return
166
+ }
165
167
 
166
- const client = new PlaywrightWebSocketClientConnection(route)
167
- const server = new PlaywrightWebSocketServerConnection(route)
168
+ const client = new PlaywrightWebSocketClientConnection(route)
169
+ const server = new PlaywrightWebSocketServerConnection(route)
168
170
 
169
- const pages = this.options.context.pages()
170
- const lastPage = pages[pages.length - 1]
171
- const baseUrl = lastPage ? this.getPageUrl(lastPage) : undefined
171
+ const pages = this.options.context.pages()
172
+ const lastPage = pages[pages.length - 1]
173
+ const baseUrl = lastPage ? this.getPageUrl(lastPage) : undefined
172
174
 
173
- for (const handler of allWebSocketHandlers) {
174
- await handler.run(
175
- {
176
- client,
177
- server,
178
- info: { protocols: [] },
179
- },
180
- {
181
- baseUrl,
182
- },
183
- )
184
- }
185
- },
186
- )
175
+ for (const handler of allWebSocketHandlers) {
176
+ await handler.run(
177
+ {
178
+ client,
179
+ server,
180
+ info: { protocols: [] },
181
+ },
182
+ {
183
+ baseUrl,
184
+ },
185
+ )
186
+ }
187
+ })
187
188
  }
188
189
 
189
190
  public async disable(): Promise<void> {
@@ -202,6 +203,30 @@ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
202
203
  // Encode/decode to preserve escape characters.
203
204
  return decodeURI(new URL(encodeURI(url)).origin)
204
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
+ }
205
230
  }
206
231
 
207
232
  class PlaywrightWebSocketClientConnection implements WebSocketClientConnectionProtocol {