@msw/playwright 0.5.0 → 0.6.1
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 +21 -6
- package/build/index.d.ts +11 -45
- package/build/index.js +21 -45
- package/package.json +3 -3
- package/src/fixture.ts +43 -67
- package/src/index.ts +2 -2
package/README.md
CHANGED
|
@@ -30,18 +30,33 @@ npm i msw @msw/playwright
|
|
|
30
30
|
```ts
|
|
31
31
|
// playwright.setup.ts
|
|
32
32
|
import { test as testBase } from '@playwright/test'
|
|
33
|
-
import {
|
|
33
|
+
import { type AnyHandler } from 'msw'
|
|
34
|
+
import { defineNetworkFixture, type NetworkFixture } from '@msw/playwright'
|
|
34
35
|
import { handlers } from '../mocks/handlers.js'
|
|
35
36
|
|
|
36
37
|
interface Fixtures {
|
|
38
|
+
handlers: Array<AnyHandler>
|
|
37
39
|
network: NetworkFixture
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const test = testBase.extend<Fixtures>({
|
|
43
|
+
// Initial list of the network handlers.
|
|
44
|
+
handlers: [[], { option: true }],
|
|
45
|
+
|
|
46
|
+
// A fixture you use to control the network in your tests.
|
|
47
|
+
network: [
|
|
48
|
+
async ({ context, handlers }, use) => {
|
|
49
|
+
const network = defineNetworkFixture({
|
|
50
|
+
context,
|
|
51
|
+
handlers,
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
await network.enable()
|
|
55
|
+
await use(network)
|
|
56
|
+
await network.disable()
|
|
57
|
+
},
|
|
58
|
+
{ auto: true },
|
|
59
|
+
],
|
|
45
60
|
})
|
|
46
61
|
```
|
|
47
62
|
|
package/build/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BrowserContext
|
|
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
|
|
6
|
-
|
|
5
|
+
interface NetworkFixtureOptions {
|
|
6
|
+
context: BrowserContext;
|
|
7
|
+
handlers?: Array<AnyHandler>;
|
|
7
8
|
onUnhandledRequest?: UnhandledRequestStrategy;
|
|
8
9
|
/**
|
|
9
10
|
* Skip common asset requests (e.g. `*.html`, `*.css`, `*.js`, etc).
|
|
@@ -14,51 +15,16 @@ interface CreateNetworkFixtureArgs {
|
|
|
14
15
|
*/
|
|
15
16
|
skipAssetRequests?: boolean;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* **Usage**
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { test as testBase } from '@playwright/test'
|
|
25
|
-
* import { createNetworkFixture, type WorkerFixture } from '@msw/playwright'
|
|
26
|
-
*
|
|
27
|
-
* interface Fixtures {
|
|
28
|
-
* network: WorkerFixture
|
|
29
|
-
* }
|
|
30
|
-
*
|
|
31
|
-
* export const test = testBase.extend<Fixtures>({
|
|
32
|
-
* network: createNetworkFixture()
|
|
33
|
-
* })
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
declare function createNetworkFixture(args?: CreateNetworkFixtureArgs): [TestFixture<NetworkFixture, PlaywrightTestArgs & PlaywrightWorkerArgs>, {
|
|
37
|
-
auto: boolean;
|
|
38
|
-
}];
|
|
18
|
+
type NetworkFixture = Omit<SetupApi<LifeCycleEventsMap>, 'dispose'> & {
|
|
19
|
+
enable: () => Promise<void>;
|
|
20
|
+
disable: () => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
declare function defineNetworkFixture(options: NetworkFixtureOptions): NetworkFixture;
|
|
39
23
|
/**
|
|
40
24
|
* @note Use a match-all RegExp with an optional group as the predicate
|
|
41
25
|
* for the `page.route()`/`page.unroute()` calls. Playwright treats given RegExp
|
|
42
26
|
* as the handler ID, which allows us to remove only those handlers introduces by us
|
|
43
27
|
* without carrying the reference to the handler function around.
|
|
44
28
|
*/
|
|
45
|
-
|
|
46
|
-
declare class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
|
|
47
|
-
protected args: {
|
|
48
|
-
context: BrowserContext;
|
|
49
|
-
skipAssetRequests: boolean;
|
|
50
|
-
initialHandlers: Array<RequestHandler | WebSocketHandler>;
|
|
51
|
-
onUnhandledRequest?: UnhandledRequestStrategy;
|
|
52
|
-
};
|
|
53
|
-
constructor(args: {
|
|
54
|
-
context: BrowserContext;
|
|
55
|
-
skipAssetRequests: boolean;
|
|
56
|
-
initialHandlers: Array<RequestHandler | WebSocketHandler>;
|
|
57
|
-
onUnhandledRequest?: UnhandledRequestStrategy;
|
|
58
|
-
});
|
|
59
|
-
start(): Promise<void>;
|
|
60
|
-
stop(): Promise<void>;
|
|
61
|
-
private getPageUrl;
|
|
62
|
-
}
|
|
63
29
|
//#endregion
|
|
64
|
-
export {
|
|
30
|
+
export { NetworkFixture, NetworkFixtureOptions, defineNetworkFixture };
|
package/build/index.js
CHANGED
|
@@ -3,37 +3,13 @@ import { RequestHandler, SetupApi, WebSocketHandler, handleRequest, isCommonAsse
|
|
|
3
3
|
import { CancelableCloseEvent, CancelableMessageEvent } from "@mswjs/interceptors/WebSocket";
|
|
4
4
|
|
|
5
5
|
//#region src/fixture.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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 ({ context }, use) => {
|
|
27
|
-
const worker = new NetworkFixture({
|
|
28
|
-
context,
|
|
29
|
-
skipAssetRequests: args?.skipAssetRequests ?? true,
|
|
30
|
-
initialHandlers: args?.initialHandlers || [],
|
|
31
|
-
onUnhandledRequest: args?.onUnhandledRequest
|
|
32
|
-
});
|
|
33
|
-
await worker.start();
|
|
34
|
-
await use(worker);
|
|
35
|
-
await worker.stop();
|
|
36
|
-
}, { 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
|
+
});
|
|
37
13
|
}
|
|
38
14
|
/**
|
|
39
15
|
* @note Use a match-all RegExp with an optional group as the predicate
|
|
@@ -42,13 +18,13 @@ function createNetworkFixture(args) {
|
|
|
42
18
|
* without carrying the reference to the handler function around.
|
|
43
19
|
*/
|
|
44
20
|
const INTERNAL_MATCH_ALL_REG_EXP = /.+(__MSW_PLAYWRIGHT_PREDICATE__)?/;
|
|
45
|
-
var
|
|
46
|
-
constructor(
|
|
47
|
-
super(...
|
|
48
|
-
this.
|
|
21
|
+
var SetupPlaywrightApi = class extends SetupApi {
|
|
22
|
+
constructor(options) {
|
|
23
|
+
super(...options.initialHandlers);
|
|
24
|
+
this.options = options;
|
|
49
25
|
}
|
|
50
|
-
async
|
|
51
|
-
await this.
|
|
26
|
+
async enable() {
|
|
27
|
+
await this.options.context.route(INTERNAL_MATCH_ALL_REG_EXP, async (route, request) => {
|
|
52
28
|
const fetchRequest = new Request(request.url(), {
|
|
53
29
|
method: request.method(),
|
|
54
30
|
headers: new Headers(await request.allHeaders()),
|
|
@@ -60,7 +36,7 @@ var NetworkFixture = class extends SetupApi {
|
|
|
60
36
|
* requests through the matching logic below.
|
|
61
37
|
* @see https://github.com/mswjs/playwright/issues/13
|
|
62
38
|
*/
|
|
63
|
-
if (this.
|
|
39
|
+
if (this.options.skipAssetRequests && isCommonAssetRequest(fetchRequest)) return route.continue();
|
|
64
40
|
const handlers = this.handlersController.currentHandlers().filter((handler) => {
|
|
65
41
|
return handler instanceof RequestHandler;
|
|
66
42
|
});
|
|
@@ -69,7 +45,7 @@ var NetworkFixture = class extends SetupApi {
|
|
|
69
45
|
* @note Use `handleRequest` instead of `getResponse` so we can pass
|
|
70
46
|
* the `onUnhandledRequest` option as-is and benefit from MSW's default behaviors.
|
|
71
47
|
*/
|
|
72
|
-
const response = await handleRequest(fetchRequest, crypto.randomUUID(), handlers, { onUnhandledRequest: this.
|
|
48
|
+
const response = await handleRequest(fetchRequest, crypto.randomUUID(), handlers, { onUnhandledRequest: this.options.onUnhandledRequest || "bypass" }, this.emitter, { resolutionContext: {
|
|
73
49
|
quiet: true,
|
|
74
50
|
baseUrl
|
|
75
51
|
} });
|
|
@@ -83,7 +59,7 @@ var NetworkFixture = class extends SetupApi {
|
|
|
83
59
|
}
|
|
84
60
|
return route.continue();
|
|
85
61
|
});
|
|
86
|
-
await this.
|
|
62
|
+
await this.options.context.routeWebSocket(INTERNAL_MATCH_ALL_REG_EXP, async (route) => {
|
|
87
63
|
const allWebSocketHandlers = this.handlersController.currentHandlers().filter((handler) => {
|
|
88
64
|
return handler instanceof WebSocketHandler;
|
|
89
65
|
});
|
|
@@ -93,7 +69,7 @@ var NetworkFixture = class extends SetupApi {
|
|
|
93
69
|
}
|
|
94
70
|
const client = new PlaywrightWebSocketClientConnection(route);
|
|
95
71
|
const server = new PlaywrightWebSocketServerConnection(route);
|
|
96
|
-
const pages = this.
|
|
72
|
+
const pages = this.options.context.pages();
|
|
97
73
|
const lastPage = pages[pages.length - 1];
|
|
98
74
|
const baseUrl = lastPage ? this.getPageUrl(lastPage) : void 0;
|
|
99
75
|
for (const handler of allWebSocketHandlers) await handler.run({
|
|
@@ -103,10 +79,10 @@ var NetworkFixture = class extends SetupApi {
|
|
|
103
79
|
}, { baseUrl });
|
|
104
80
|
});
|
|
105
81
|
}
|
|
106
|
-
async
|
|
82
|
+
async disable() {
|
|
107
83
|
super.dispose();
|
|
108
|
-
await this.
|
|
109
|
-
await unrouteWebSocket(this.
|
|
84
|
+
await this.options.context.unroute(INTERNAL_MATCH_ALL_REG_EXP);
|
|
85
|
+
await unrouteWebSocket(this.options.context, INTERNAL_MATCH_ALL_REG_EXP);
|
|
110
86
|
}
|
|
111
87
|
getPageUrl(page) {
|
|
112
88
|
const url = page.url();
|
|
@@ -266,4 +242,4 @@ async function unrouteWebSocket(target, url, handler) {
|
|
|
266
242
|
}
|
|
267
243
|
|
|
268
244
|
//#endregion
|
|
269
|
-
export {
|
|
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
|
+
"version": "0.6.1",
|
|
5
5
|
"description": "Mock Service Worker binding for Playwright",
|
|
6
6
|
"main": "./build/index.js",
|
|
7
7
|
"types": "./build/index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"node": ">=20.0.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"msw": "^2.12.
|
|
36
|
+
"msw": "^2.12.10"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@epic-web/test-server": "^0.1.6",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@playwright/test": "^1.58.1",
|
|
42
42
|
"@types/node": "^22.15.29",
|
|
43
43
|
"@types/sinon": "^21.0.0",
|
|
44
|
-
"msw": "^2.12.
|
|
44
|
+
"msw": "^2.12.10",
|
|
45
45
|
"sinon": "^21.0.1",
|
|
46
46
|
"tsdown": "^0.12.7",
|
|
47
47
|
"typescript": "^5.9.3",
|
package/src/fixture.ts
CHANGED
|
@@ -2,21 +2,18 @@ import { invariant } from 'outvariant'
|
|
|
2
2
|
import type {
|
|
3
3
|
BrowserContext,
|
|
4
4
|
Page,
|
|
5
|
-
PlaywrightTestArgs,
|
|
6
|
-
PlaywrightWorkerArgs,
|
|
7
5
|
Request as PlaywrightRequest,
|
|
8
6
|
Route,
|
|
9
|
-
TestFixture,
|
|
10
7
|
WebSocketRoute,
|
|
11
8
|
} from '@playwright/test'
|
|
9
|
+
import { WebSocketHandler } from 'msw'
|
|
12
10
|
import {
|
|
13
|
-
type LifeCycleEventsMap,
|
|
14
|
-
type UnhandledRequestStrategy,
|
|
15
11
|
SetupApi,
|
|
16
|
-
RequestHandler,
|
|
17
|
-
WebSocketHandler,
|
|
18
12
|
handleRequest,
|
|
19
13
|
isCommonAssetRequest,
|
|
14
|
+
type AnyHandler,
|
|
15
|
+
type LifeCycleEventsMap,
|
|
16
|
+
type UnhandledRequestStrategy,
|
|
20
17
|
} from 'msw'
|
|
21
18
|
import {
|
|
22
19
|
type WebSocketClientEventMap,
|
|
@@ -27,9 +24,11 @@ import {
|
|
|
27
24
|
WebSocketClientConnectionProtocol,
|
|
28
25
|
WebSocketServerConnectionProtocol,
|
|
29
26
|
} from '@mswjs/interceptors/WebSocket'
|
|
27
|
+
import { RequestHandler } from 'msw'
|
|
30
28
|
|
|
31
|
-
export interface
|
|
32
|
-
|
|
29
|
+
export interface NetworkFixtureOptions {
|
|
30
|
+
context: BrowserContext
|
|
31
|
+
handlers?: Array<AnyHandler>
|
|
33
32
|
onUnhandledRequest?: UnhandledRequestStrategy
|
|
34
33
|
/**
|
|
35
34
|
* Skip common asset requests (e.g. `*.html`, `*.css`, `*.js`, etc).
|
|
@@ -41,46 +40,27 @@ export interface CreateNetworkFixtureArgs {
|
|
|
41
40
|
skipAssetRequests?: boolean
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* network: createNetworkFixture()
|
|
60
|
-
* })
|
|
61
|
-
* ```
|
|
62
|
-
*/
|
|
63
|
-
export function createNetworkFixture(
|
|
64
|
-
args?: CreateNetworkFixtureArgs,
|
|
65
|
-
): [
|
|
66
|
-
TestFixture<NetworkFixture, PlaywrightTestArgs & PlaywrightWorkerArgs>,
|
|
67
|
-
{ auto: boolean },
|
|
68
|
-
] {
|
|
69
|
-
return [
|
|
70
|
-
async ({ context }, use) => {
|
|
71
|
-
const worker = new NetworkFixture({
|
|
72
|
-
context,
|
|
73
|
-
skipAssetRequests: args?.skipAssetRequests ?? true,
|
|
74
|
-
initialHandlers: args?.initialHandlers || [],
|
|
75
|
-
onUnhandledRequest: args?.onUnhandledRequest,
|
|
76
|
-
})
|
|
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
|
+
}
|
|
77
58
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
]
|
|
59
|
+
interface SetupPlaywrightOptions {
|
|
60
|
+
context: BrowserContext
|
|
61
|
+
initialHandlers: Array<AnyHandler>
|
|
62
|
+
onUnhandledRequest?: UnhandledRequestStrategy
|
|
63
|
+
skipAssetRequests?: boolean
|
|
84
64
|
}
|
|
85
65
|
|
|
86
66
|
/**
|
|
@@ -91,21 +71,14 @@ export function createNetworkFixture(
|
|
|
91
71
|
*/
|
|
92
72
|
export const INTERNAL_MATCH_ALL_REG_EXP = /.+(__MSW_PLAYWRIGHT_PREDICATE__)?/
|
|
93
73
|
|
|
94
|
-
|
|
95
|
-
constructor(
|
|
96
|
-
|
|
97
|
-
context: BrowserContext
|
|
98
|
-
skipAssetRequests: boolean
|
|
99
|
-
initialHandlers: Array<RequestHandler | WebSocketHandler>
|
|
100
|
-
onUnhandledRequest?: UnhandledRequestStrategy
|
|
101
|
-
},
|
|
102
|
-
) {
|
|
103
|
-
super(...args.initialHandlers)
|
|
74
|
+
class SetupPlaywrightApi extends SetupApi<LifeCycleEventsMap> {
|
|
75
|
+
constructor(private readonly options: SetupPlaywrightOptions) {
|
|
76
|
+
super(...options.initialHandlers)
|
|
104
77
|
}
|
|
105
78
|
|
|
106
|
-
public async
|
|
79
|
+
public async enable(): Promise<void> {
|
|
107
80
|
// Handle HTTP requests.
|
|
108
|
-
await this.
|
|
81
|
+
await this.options.context.route(
|
|
109
82
|
INTERNAL_MATCH_ALL_REG_EXP,
|
|
110
83
|
async (route: Route, request: PlaywrightRequest) => {
|
|
111
84
|
const fetchRequest = new Request(request.url(), {
|
|
@@ -120,7 +93,10 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
|
|
|
120
93
|
* requests through the matching logic below.
|
|
121
94
|
* @see https://github.com/mswjs/playwright/issues/13
|
|
122
95
|
*/
|
|
123
|
-
if (
|
|
96
|
+
if (
|
|
97
|
+
this.options.skipAssetRequests &&
|
|
98
|
+
isCommonAssetRequest(fetchRequest)
|
|
99
|
+
) {
|
|
124
100
|
return route.continue()
|
|
125
101
|
}
|
|
126
102
|
|
|
@@ -143,7 +119,7 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
|
|
|
143
119
|
crypto.randomUUID(),
|
|
144
120
|
handlers,
|
|
145
121
|
{
|
|
146
|
-
onUnhandledRequest: this.
|
|
122
|
+
onUnhandledRequest: this.options.onUnhandledRequest || 'bypass',
|
|
147
123
|
},
|
|
148
124
|
this.emitter,
|
|
149
125
|
{
|
|
@@ -173,7 +149,7 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
|
|
|
173
149
|
)
|
|
174
150
|
|
|
175
151
|
// Handle WebSocket connections.
|
|
176
|
-
await this.
|
|
152
|
+
await this.options.context.routeWebSocket(
|
|
177
153
|
INTERNAL_MATCH_ALL_REG_EXP,
|
|
178
154
|
async (route) => {
|
|
179
155
|
const allWebSocketHandlers = this.handlersController
|
|
@@ -190,7 +166,7 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
|
|
|
190
166
|
const client = new PlaywrightWebSocketClientConnection(route)
|
|
191
167
|
const server = new PlaywrightWebSocketServerConnection(route)
|
|
192
168
|
|
|
193
|
-
const pages = this.
|
|
169
|
+
const pages = this.options.context.pages()
|
|
194
170
|
const lastPage = pages[pages.length - 1]
|
|
195
171
|
const baseUrl = lastPage ? this.getPageUrl(lastPage) : undefined
|
|
196
172
|
|
|
@@ -210,10 +186,10 @@ export class NetworkFixture extends SetupApi<LifeCycleEventsMap> {
|
|
|
210
186
|
)
|
|
211
187
|
}
|
|
212
188
|
|
|
213
|
-
public async
|
|
189
|
+
public async disable(): Promise<void> {
|
|
214
190
|
super.dispose()
|
|
215
|
-
await this.
|
|
216
|
-
await unrouteWebSocket(this.
|
|
191
|
+
await this.options.context.unroute(INTERNAL_MATCH_ALL_REG_EXP)
|
|
192
|
+
await unrouteWebSocket(this.options.context, INTERNAL_MATCH_ALL_REG_EXP)
|
|
217
193
|
}
|
|
218
194
|
|
|
219
195
|
private getPageUrl(page: Page): string | undefined {
|
package/src/index.ts
CHANGED