@msw/playwright 0.4.5 → 0.6.0

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
@@ -37,11 +37,24 @@ interface Fixtures {
37
37
  network: NetworkFixture
38
38
  }
39
39
 
40
- export const test = testBase.extend<Fixtures>({
41
- // Create a fixture that will control the network in your tests.
42
- network: createNetworkFixture({
43
- initialHandlers: handlers,
44
- }),
40
+ const test = testBase.extend<Fixtures>({
41
+ // Initial list of the network handlers.
42
+ handlers: [[], { option: true }],
43
+
44
+ // A fixture you use to control the network in your tests.
45
+ network: [
46
+ async ({ context, handlers }, use) => {
47
+ const network = defineNetworkFixture({
48
+ context,
49
+ handlers,
50
+ })
51
+
52
+ await network.enable()
53
+ await use(network)
54
+ await network.disable()
55
+ },
56
+ { auto: true },
57
+ ],
45
58
  })
46
59
  ```
47
60
 
@@ -66,6 +79,10 @@ test('displays the user dashboard', async ({ network, page }) => {
66
79
  })
67
80
  ```
68
81
 
82
+ ## Limitations
83
+
84
+ - Since `context.routeWebSocket()` provides no means of knowing which page triggered a WebSocket connection, relative WebSocket URLs in `ws.link(url)` will be resolved against the _latest_ created page in the browser context.
85
+
69
86
  ## Comparison
70
87
 
71
88
  ### `playwright-msw`
package/build/index.d.ts CHANGED
@@ -1,54 +1,30 @@
1
- import { LifeCycleEventsMap, RequestHandler, SetupApi, UnhandledRequestStrategy, WebSocketHandler } from "msw";
2
- import { Page, PlaywrightTestArgs, PlaywrightWorkerArgs, TestFixture } from "@playwright/test";
1
+ import { AnyHandler, LifeCycleEventsMap, SetupApi, UnhandledRequestStrategy } from "msw";
2
+ import { BrowserContext } from "@playwright/test";
3
3
 
4
4
  //#region src/fixture.d.ts
5
- interface CreateNetworkFixtureArgs {
6
- initialHandlers?: Array<RequestHandler | WebSocketHandler>;
5
+ interface NetworkFixtureOptions {
6
+ context: BrowserContext;
7
+ handlers?: Array<AnyHandler>;
7
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;
8
17
  }
9
- /**
10
- * Creates a fixture that controls the network in your tests.
11
- *
12
- * @note The returned fixture already has the `auto` option set to `true`.
13
- *
14
- * **Usage**
15
- * ```ts
16
- * import { test as testBase } from '@playwright/test'
17
- * import { createNetworkFixture, type WorkerFixture } from '@msw/playwright'
18
- *
19
- * interface Fixtures {
20
- * network: WorkerFixture
21
- * }
22
- *
23
- * export const test = testBase.extend<Fixtures>({
24
- * network: createNetworkFixture()
25
- * })
26
- * ```
27
- */
28
- declare function createNetworkFixture(args?: CreateNetworkFixtureArgs): [TestFixture<NetworkFixture, PlaywrightTestArgs & PlaywrightWorkerArgs>, {
29
- auto: boolean;
30
- }];
18
+ type NetworkFixture = Omit<SetupApi<LifeCycleEventsMap>, 'dispose'> & {
19
+ enable: () => Promise<void>;
20
+ disable: () => Promise<void>;
21
+ };
22
+ declare function defineNetworkFixture(options: NetworkFixtureOptions): NetworkFixture;
31
23
  /**
32
24
  * @note Use a match-all RegExp with an optional group as the predicate
33
25
  * for the `page.route()`/`page.unroute()` calls. Playwright treats given RegExp
34
26
  * as the handler ID, which allows us to remove only those handlers introduces by us
35
27
  * without carrying the reference to the handler function around.
36
28
  */
37
-
38
- declare class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
39
- protected args: {
40
- page: Page;
41
- initialHandlers: Array<RequestHandler | WebSocketHandler>;
42
- onUnhandledRequest?: UnhandledRequestStrategy;
43
- };
44
- constructor(args: {
45
- page: Page;
46
- initialHandlers: Array<RequestHandler | WebSocketHandler>;
47
- onUnhandledRequest?: UnhandledRequestStrategy;
48
- });
49
- start(): Promise<void>;
50
- stop(): Promise<void>;
51
- private getPageUrl;
52
- }
53
29
  //#endregion
54
- export { CreateNetworkFixtureArgs, NetworkFixture, createNetworkFixture };
30
+ export { NetworkFixture, NetworkFixtureOptions, defineNetworkFixture };
package/build/index.js CHANGED
@@ -1,38 +1,15 @@
1
1
  import { invariant } from "outvariant";
2
- import { RequestHandler, SetupApi, WebSocketHandler, handleRequest } from "msw";
2
+ import { RequestHandler, SetupApi, WebSocketHandler, handleRequest, isCommonAssetRequest } from "msw";
3
3
  import { CancelableCloseEvent, CancelableMessageEvent } from "@mswjs/interceptors/WebSocket";
4
4
 
5
5
  //#region src/fixture.ts
6
- /**
7
- * Creates a fixture that controls the network in your tests.
8
- *
9
- * @note The returned fixture already has the `auto` option set to `true`.
10
- *
11
- * **Usage**
12
- * ```ts
13
- * import { test as testBase } from '@playwright/test'
14
- * import { createNetworkFixture, type WorkerFixture } from '@msw/playwright'
15
- *
16
- * interface Fixtures {
17
- * network: WorkerFixture
18
- * }
19
- *
20
- * export const test = testBase.extend<Fixtures>({
21
- * network: createNetworkFixture()
22
- * })
23
- * ```
24
- */
25
- function createNetworkFixture(args) {
26
- return [async ({ page }, use) => {
27
- const worker = new NetworkFixture({
28
- page,
29
- initialHandlers: args?.initialHandlers || [],
30
- onUnhandledRequest: args?.onUnhandledRequest
31
- });
32
- await worker.start();
33
- await use(worker);
34
- await worker.stop();
35
- }, { auto: true }];
6
+ function defineNetworkFixture(options) {
7
+ return new SetupPlaywrightApi({
8
+ context: options.context,
9
+ initialHandlers: options.handlers || [],
10
+ onUnhandledRequest: options.onUnhandledRequest,
11
+ skipAssetRequests: options.skipAssetRequests ?? true
12
+ });
36
13
  }
37
14
  /**
38
15
  * @note Use a match-all RegExp with an optional group as the predicate
@@ -41,68 +18,76 @@ function createNetworkFixture(args) {
41
18
  * without carrying the reference to the handler function around.
42
19
  */
43
20
  const INTERNAL_MATCH_ALL_REG_EXP = /.+(__MSW_PLAYWRIGHT_PREDICATE__)?/;
44
- var NetworkFixture = class extends SetupApi {
45
- constructor(args) {
46
- super(...args.initialHandlers);
47
- this.args = args;
21
+ var SetupPlaywrightApi = class extends SetupApi {
22
+ constructor(options) {
23
+ super(...options.initialHandlers);
24
+ this.options = options;
48
25
  }
49
- async start() {
50
- await this.args.page.route(INTERNAL_MATCH_ALL_REG_EXP, async (route, request) => {
26
+ async enable() {
27
+ await this.options.context.route(INTERNAL_MATCH_ALL_REG_EXP, async (route, request) => {
51
28
  const fetchRequest = new Request(request.url(), {
52
29
  method: request.method(),
53
30
  headers: new Headers(await request.allHeaders()),
54
31
  body: request.postDataBuffer()
55
32
  });
33
+ /**
34
+ * @note Skip common asset requests (default).
35
+ * Playwright seems to experience performance degradation when routing all
36
+ * requests through the matching logic below.
37
+ * @see https://github.com/mswjs/playwright/issues/13
38
+ */
39
+ if (this.options.skipAssetRequests && isCommonAssetRequest(fetchRequest)) return route.continue();
56
40
  const handlers = this.handlersController.currentHandlers().filter((handler) => {
57
41
  return handler instanceof RequestHandler;
58
42
  });
43
+ const baseUrl = request.headers().referer ? new URL(request.headers().referer).origin : void 0;
59
44
  /**
60
45
  * @note Use `handleRequest` instead of `getResponse` so we can pass
61
46
  * the `onUnhandledRequest` option as-is and benefit from MSW's default behaviors.
62
47
  */
63
- const response = await handleRequest(fetchRequest, crypto.randomUUID(), handlers, { onUnhandledRequest: this.args.onUnhandledRequest || "bypass" }, this.emitter, { resolutionContext: {
48
+ const response = await handleRequest(fetchRequest, crypto.randomUUID(), handlers, { onUnhandledRequest: this.options.onUnhandledRequest || "bypass" }, this.emitter, { resolutionContext: {
64
49
  quiet: true,
65
- baseUrl: this.getPageUrl()
50
+ baseUrl
66
51
  } });
67
52
  if (response) {
68
- if (response.status === 0) {
69
- route.abort();
70
- return;
71
- }
72
- route.fulfill({
53
+ if (response.status === 0) return route.abort();
54
+ return route.fulfill({
73
55
  status: response.status,
74
56
  headers: Object.fromEntries(response.headers),
75
57
  body: response.body ? Buffer.from(await response.arrayBuffer()) : void 0
76
58
  });
77
- return;
78
59
  }
79
- route.continue();
60
+ return route.continue();
80
61
  });
81
- await this.args.page.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (ws) => {
62
+ await this.options.context.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (route) => {
82
63
  const allWebSocketHandlers = this.handlersController.currentHandlers().filter((handler) => {
83
64
  return handler instanceof WebSocketHandler;
84
65
  });
85
66
  if (allWebSocketHandlers.length === 0) {
86
- ws.connectToServer();
67
+ route.connectToServer();
87
68
  return;
88
69
  }
89
- const client = new PlaywrightWebSocketClientConnection(ws);
90
- const server = new PlaywrightWebSocketServerConnection(ws);
70
+ const client = new PlaywrightWebSocketClientConnection(route);
71
+ const server = new PlaywrightWebSocketServerConnection(route);
72
+ const pages = this.options.context.pages();
73
+ const lastPage = pages[pages.length - 1];
74
+ const baseUrl = lastPage ? this.getPageUrl(lastPage) : void 0;
91
75
  for (const handler of allWebSocketHandlers) await handler.run({
92
76
  client,
93
77
  server,
94
78
  info: { protocols: [] }
95
- }, { baseUrl: this.getPageUrl() });
79
+ }, { baseUrl });
96
80
  });
97
81
  }
98
- async stop() {
82
+ async disable() {
99
83
  super.dispose();
100
- await this.args.page.unroute(INTERNAL_MATCH_ALL_REG_EXP);
101
- await unrouteWebSocket(this.args.page, INTERNAL_MATCH_ALL_REG_EXP);
84
+ await this.options.context.unroute(INTERNAL_MATCH_ALL_REG_EXP);
85
+ await unrouteWebSocket(this.options.context, INTERNAL_MATCH_ALL_REG_EXP);
102
86
  }
103
- getPageUrl() {
104
- const url = this.args.page.url();
105
- return url !== "about:blank" ? url : void 0;
87
+ getPageUrl(page) {
88
+ const url = page.url();
89
+ if (url === "about:blank") return;
90
+ return decodeURI(new URL(encodeURI(url)).origin);
106
91
  }
107
92
  };
108
93
  var PlaywrightWebSocketClientConnection = class {
@@ -248,13 +233,13 @@ var PlaywrightWebSocketServerConnection = class {
248
233
  * Custom implementation of the missing `page.unrouteWebSocket()` to remove
249
234
  * WebSocket route handlers from the page. Loosely inspired by `page.unroute()`.
250
235
  */
251
- async function unrouteWebSocket(page, url, handler) {
252
- if (!("_webSocketRoutes" in page && Array.isArray(page._webSocketRoutes))) return;
253
- for (let i = page._webSocketRoutes.length - 1; i >= 0; i--) {
254
- const route = page._webSocketRoutes[i];
255
- if (route.url === url && (handler != null ? route.handler === handler : true)) page._webSocketRoutes.splice(i, 1);
236
+ async function unrouteWebSocket(target, url, handler) {
237
+ if (!("_webSocketRoutes" in target && Array.isArray(target._webSocketRoutes))) return;
238
+ for (let i = target._webSocketRoutes.length - 1; i >= 0; i--) {
239
+ const route = target._webSocketRoutes[i];
240
+ if (route.url === url && (handler != null ? route.handler === handler : true)) target._webSocketRoutes.splice(i, 1);
256
241
  }
257
242
  }
258
243
 
259
244
  //#endregion
260
- export { createNetworkFixture };
245
+ export { defineNetworkFixture };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@msw/playwright",
4
- "version": "0.4.5",
4
+ "version": "0.6.0",
5
5
  "description": "Mock Service Worker binding for Playwright",
6
6
  "main": "./build/index.js",
7
7
  "types": "./build/index.d.ts",
@@ -33,22 +33,22 @@
33
33
  "node": ">=20.0.0"
34
34
  },
35
35
  "peerDependencies": {
36
- "msw": "^2.10.3"
36
+ "msw": "^2.12.10"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@epic-web/test-server": "^0.1.6",
40
40
  "@ossjs/release": "^0.10.1",
41
- "@playwright/test": "^1.57.0",
41
+ "@playwright/test": "^1.58.1",
42
42
  "@types/node": "^22.15.29",
43
43
  "@types/sinon": "^21.0.0",
44
- "msw": "^2.12.7",
44
+ "msw": "^2.12.10",
45
45
  "sinon": "^21.0.1",
46
46
  "tsdown": "^0.12.7",
47
47
  "typescript": "^5.9.3",
48
48
  "vite": "^7.3.1"
49
49
  },
50
50
  "dependencies": {
51
- "@mswjs/interceptors": "^0.40.0",
51
+ "@mswjs/interceptors": "^0.41.2",
52
52
  "outvariant": "^1.4.3"
53
53
  },
54
54
  "scripts": {
package/src/fixture.ts CHANGED
@@ -1,20 +1,19 @@
1
1
  import { invariant } from 'outvariant'
2
2
  import type {
3
+ BrowserContext,
3
4
  Page,
4
- PlaywrightTestArgs,
5
- PlaywrightWorkerArgs,
6
- Request,
5
+ Request as PlaywrightRequest,
7
6
  Route,
8
- TestFixture,
9
7
  WebSocketRoute,
10
8
  } from '@playwright/test'
9
+ import { WebSocketHandler } from 'msw'
11
10
  import {
12
- type LifeCycleEventsMap,
13
- type UnhandledRequestStrategy,
14
11
  SetupApi,
15
- RequestHandler,
16
- WebSocketHandler,
17
12
  handleRequest,
13
+ isCommonAssetRequest,
14
+ type AnyHandler,
15
+ type LifeCycleEventsMap,
16
+ type UnhandledRequestStrategy,
18
17
  } from 'msw'
19
18
  import {
20
19
  type WebSocketClientEventMap,
@@ -25,51 +24,43 @@ import {
25
24
  WebSocketClientConnectionProtocol,
26
25
  WebSocketServerConnectionProtocol,
27
26
  } from '@mswjs/interceptors/WebSocket'
27
+ import { RequestHandler } from 'msw'
28
28
 
29
- export interface CreateNetworkFixtureArgs {
30
- initialHandlers?: Array<RequestHandler | WebSocketHandler>
29
+ export interface NetworkFixtureOptions {
30
+ context: BrowserContext
31
+ handlers?: Array<AnyHandler>
31
32
  onUnhandledRequest?: UnhandledRequestStrategy
33
+ /**
34
+ * Skip common asset requests (e.g. `*.html`, `*.css`, `*.js`, etc).
35
+ * This improves performance for certian projects.
36
+ * @default true
37
+ *
38
+ * @see https://mswjs.io/docs/api/is-common-asset-request
39
+ */
40
+ skipAssetRequests?: boolean
32
41
  }
33
42
 
34
- /**
35
- * Creates a fixture that controls the network in your tests.
36
- *
37
- * @note The returned fixture already has the `auto` option set to `true`.
38
- *
39
- * **Usage**
40
- * ```ts
41
- * import { test as testBase } from '@playwright/test'
42
- * import { createNetworkFixture, type WorkerFixture } from '@msw/playwright'
43
- *
44
- * interface Fixtures {
45
- * network: WorkerFixture
46
- * }
47
- *
48
- * export const test = testBase.extend<Fixtures>({
49
- * network: createNetworkFixture()
50
- * })
51
- * ```
52
- */
53
- export function createNetworkFixture(
54
- args?: CreateNetworkFixtureArgs,
55
- ): [
56
- TestFixture<NetworkFixture, PlaywrightTestArgs & PlaywrightWorkerArgs>,
57
- { auto: boolean },
58
- ] {
59
- return [
60
- async ({ page }, use) => {
61
- const worker = new NetworkFixture({
62
- page,
63
- initialHandlers: args?.initialHandlers || [],
64
- onUnhandledRequest: args?.onUnhandledRequest,
65
- })
43
+ export type NetworkFixture = Omit<SetupApi<LifeCycleEventsMap>, 'dispose'> & {
44
+ enable: () => Promise<void>
45
+ disable: () => Promise<void>
46
+ }
47
+
48
+ export function defineNetworkFixture(
49
+ options: NetworkFixtureOptions,
50
+ ): NetworkFixture {
51
+ return new SetupPlaywrightApi({
52
+ context: options.context,
53
+ initialHandlers: options.handlers || [],
54
+ onUnhandledRequest: options.onUnhandledRequest,
55
+ skipAssetRequests: options.skipAssetRequests ?? true,
56
+ })
57
+ }
66
58
 
67
- await worker.start()
68
- await use(worker)
69
- await worker.stop()
70
- },
71
- { auto: true },
72
- ]
59
+ interface SetupPlaywrightOptions {
60
+ context: BrowserContext
61
+ initialHandlers: Array<AnyHandler>
62
+ onUnhandledRequest?: UnhandledRequestStrategy
63
+ skipAssetRequests?: boolean
73
64
  }
74
65
 
75
66
  /**
@@ -80,34 +71,45 @@ export function createNetworkFixture(
80
71
  */
81
72
  export const INTERNAL_MATCH_ALL_REG_EXP = /.+(__MSW_PLAYWRIGHT_PREDICATE__)?/
82
73
 
83
- export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
84
- constructor(
85
- protected args: {
86
- page: Page
87
- initialHandlers: Array<RequestHandler | WebSocketHandler>
88
- onUnhandledRequest?: UnhandledRequestStrategy
89
- },
90
- ) {
91
- super(...args.initialHandlers)
74
+ class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
75
+ constructor(private readonly options: SetupPlaywrightOptions) {
76
+ super(...options.initialHandlers)
92
77
  }
93
78
 
94
- public async start(): Promise<void> {
79
+ public async enable(): Promise<void> {
95
80
  // Handle HTTP requests.
96
- await this.args.page.route(
81
+ await this.options.context.route(
97
82
  INTERNAL_MATCH_ALL_REG_EXP,
98
- async (route: Route, request: Request) => {
83
+ async (route: Route, request: PlaywrightRequest) => {
99
84
  const fetchRequest = new Request(request.url(), {
100
85
  method: request.method(),
101
86
  headers: new Headers(await request.allHeaders()),
102
- body: request.postDataBuffer(),
87
+ body: request.postDataBuffer() as ArrayBuffer | null,
103
88
  })
104
89
 
90
+ /**
91
+ * @note Skip common asset requests (default).
92
+ * Playwright seems to experience performance degradation when routing all
93
+ * requests through the matching logic below.
94
+ * @see https://github.com/mswjs/playwright/issues/13
95
+ */
96
+ if (
97
+ this.options.skipAssetRequests &&
98
+ isCommonAssetRequest(fetchRequest)
99
+ ) {
100
+ return route.continue()
101
+ }
102
+
105
103
  const handlers = this.handlersController
106
104
  .currentHandlers()
107
105
  .filter((handler) => {
108
106
  return handler instanceof RequestHandler
109
107
  })
110
108
 
109
+ const baseUrl = request.headers().referer
110
+ ? new URL(request.headers().referer).origin
111
+ : undefined
112
+
111
113
  /**
112
114
  * @note Use `handleRequest` instead of `getResponse` so we can pass
113
115
  * the `onUnhandledRequest` option as-is and benefit from MSW's default behaviors.
@@ -117,41 +119,39 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
117
119
  crypto.randomUUID(),
118
120
  handlers,
119
121
  {
120
- onUnhandledRequest: this.args.onUnhandledRequest || 'bypass',
122
+ onUnhandledRequest: this.options.onUnhandledRequest || 'bypass',
121
123
  },
122
124
  this.emitter,
123
125
  {
124
126
  resolutionContext: {
125
127
  quiet: true,
126
- baseUrl: this.getPageUrl(),
128
+ baseUrl,
127
129
  },
128
130
  },
129
131
  )
130
132
 
131
133
  if (response) {
132
134
  if (response.status === 0) {
133
- route.abort()
134
- return
135
+ return route.abort()
135
136
  }
136
137
 
137
- route.fulfill({
138
+ return route.fulfill({
138
139
  status: response.status,
139
140
  headers: Object.fromEntries(response.headers),
140
141
  body: response.body
141
142
  ? Buffer.from(await response.arrayBuffer())
142
143
  : undefined,
143
144
  })
144
- return
145
145
  }
146
146
 
147
- route.continue()
147
+ return route.continue()
148
148
  },
149
149
  )
150
150
 
151
151
  // Handle WebSocket connections.
152
- await this.args.page.routeWebSocket(
152
+ await this.options.context.routeWebSocket(
153
153
  INTERNAL_MATCH_ALL_REG_EXP,
154
- async (ws) => {
154
+ async (route) => {
155
155
  const allWebSocketHandlers = this.handlersController
156
156
  .currentHandlers()
157
157
  .filter((handler) => {
@@ -159,12 +159,16 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
159
159
  })
160
160
 
161
161
  if (allWebSocketHandlers.length === 0) {
162
- ws.connectToServer()
162
+ route.connectToServer()
163
163
  return
164
164
  }
165
165
 
166
- const client = new PlaywrightWebSocketClientConnection(ws)
167
- const server = new PlaywrightWebSocketServerConnection(ws)
166
+ const client = new PlaywrightWebSocketClientConnection(route)
167
+ const server = new PlaywrightWebSocketServerConnection(route)
168
+
169
+ const pages = this.options.context.pages()
170
+ const lastPage = pages[pages.length - 1]
171
+ const baseUrl = lastPage ? this.getPageUrl(lastPage) : undefined
168
172
 
169
173
  for (const handler of allWebSocketHandlers) {
170
174
  await handler.run(
@@ -174,7 +178,7 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
174
178
  info: { protocols: [] },
175
179
  },
176
180
  {
177
- baseUrl: this.getPageUrl(),
181
+ baseUrl,
178
182
  },
179
183
  )
180
184
  }
@@ -182,21 +186,25 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
182
186
  )
183
187
  }
184
188
 
185
- public async stop(): Promise<void> {
189
+ public async disable(): Promise<void> {
186
190
  super.dispose()
187
- await this.args.page.unroute(INTERNAL_MATCH_ALL_REG_EXP)
188
- await unrouteWebSocket(this.args.page, INTERNAL_MATCH_ALL_REG_EXP)
191
+ await this.options.context.unroute(INTERNAL_MATCH_ALL_REG_EXP)
192
+ await unrouteWebSocket(this.options.context, INTERNAL_MATCH_ALL_REG_EXP)
189
193
  }
190
194
 
191
- private getPageUrl(): string | undefined {
192
- const url = this.args.page.url()
193
- return url !== 'about:blank' ? url : undefined
195
+ private getPageUrl(page: Page): string | undefined {
196
+ const url = page.url()
197
+
198
+ if (url === 'about:blank') {
199
+ return
200
+ }
201
+
202
+ // Encode/decode to preserve escape characters.
203
+ return decodeURI(new URL(encodeURI(url)).origin)
194
204
  }
195
205
  }
196
206
 
197
- class PlaywrightWebSocketClientConnection
198
- implements WebSocketClientConnectionProtocol
199
- {
207
+ class PlaywrightWebSocketClientConnection implements WebSocketClientConnectionProtocol {
200
208
  public id: string
201
209
  public url: URL
202
210
 
@@ -298,9 +306,7 @@ class PlaywrightWebSocketClientConnection
298
306
  }
299
307
  }
300
308
 
301
- class PlaywrightWebSocketServerConnection
302
- implements WebSocketServerConnectionProtocol
303
- {
309
+ class PlaywrightWebSocketServerConnection implements WebSocketServerConnectionProtocol {
304
310
  #server?: WebSocketRoute
305
311
  #bufferedEvents: Array<
306
312
  Parameters<WebSocketServerConnectionProtocol['addEventListener']>
@@ -411,22 +417,24 @@ interface InternalWebSocketRoute {
411
417
  * WebSocket route handlers from the page. Loosely inspired by `page.unroute()`.
412
418
  */
413
419
  async function unrouteWebSocket(
414
- page: Page,
420
+ target: BrowserContext,
415
421
  url: InternalWebSocketRoute['url'],
416
422
  handler?: InternalWebSocketRoute['handler'],
417
423
  ): Promise<void> {
418
- if (!('_webSocketRoutes' in page && Array.isArray(page._webSocketRoutes))) {
424
+ if (
425
+ !('_webSocketRoutes' in target && Array.isArray(target._webSocketRoutes))
426
+ ) {
419
427
  return
420
428
  }
421
429
 
422
- for (let i = page._webSocketRoutes.length - 1; i >= 0; i--) {
423
- const route = page._webSocketRoutes[i] as InternalWebSocketRoute
430
+ for (let i = target._webSocketRoutes.length - 1; i >= 0; i--) {
431
+ const route = target._webSocketRoutes[i] as InternalWebSocketRoute
424
432
 
425
433
  if (
426
434
  route.url === url &&
427
435
  (handler != null ? route.handler === handler : true)
428
436
  ) {
429
- page._webSocketRoutes.splice(i, 1)
437
+ target._webSocketRoutes.splice(i, 1)
430
438
  }
431
439
  }
432
440
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export {
2
- type CreateNetworkFixtureArgs,
2
+ defineNetworkFixture,
3
3
  type NetworkFixture,
4
- createNetworkFixture,
4
+ type NetworkFixtureOptions,
5
5
  } from './fixture.js'