@zorilla/playwright-extra 1.0.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/LICENSE +21 -0
- package/README.md +361 -0
- package/dist/extra.d.ts +54 -0
- package/dist/extra.d.ts.map +1 -0
- package/dist/extra.js +231 -0
- package/dist/extra.js.map +1 -0
- package/dist/helper/loader.d.ts +27 -0
- package/dist/helper/loader.d.ts.map +1 -0
- package/dist/helper/loader.js +77 -0
- package/dist/helper/loader.js.map +1 -0
- package/dist/index.d.ts +2397 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins.d.ts +84 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +363 -0
- package/dist/plugins.js.map +1 -0
- package/dist/puppeteer-compatiblity-shim/index.d.ts +26 -0
- package/dist/puppeteer-compatiblity-shim/index.d.ts.map +1 -0
- package/dist/puppeteer-compatiblity-shim/index.js +193 -0
- package/dist/puppeteer-compatiblity-shim/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/index.d.ts +88 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +38 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 berstend <github@berstend.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# playwright-extra [](https://github.com/zorillajs/zorilla/actions) [](https://www.npmjs.com/package/playwright-extra)
|
|
2
|
+
|
|
3
|
+
> A modular plugin framework for [playwright](https://github.com/microsoft/playwright) to enable cool [plugins](#plugins) through a clean interface.
|
|
4
|
+
|
|
5
|
+
**Part of the [zorilla](https://github.com/zorillajs/zorilla) monorepo** - a maintained fork of puppeteer-extra with modern tooling and ESM support.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 18+ (ESM only)
|
|
10
|
+
- Playwright 1.x
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add playwright playwright-extra
|
|
16
|
+
# - or -
|
|
17
|
+
npm install playwright playwright-extra
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
After installing, make sure to install the Playwright browsers:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm exec playwright install
|
|
24
|
+
# - or -
|
|
25
|
+
npx playwright install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// playwright-extra is a drop-in replacement for playwright,
|
|
32
|
+
// it augments the installed playwright with plugin functionality
|
|
33
|
+
import { chromium } from 'playwright-extra'
|
|
34
|
+
|
|
35
|
+
// Load the stealth plugin and use defaults (all tricks to hide playwright usage)
|
|
36
|
+
// Note: playwright-extra is compatible with most puppeteer-extra plugins
|
|
37
|
+
import StealthPlugin from '@zorilla/puppeteer-extra-plugin-stealth'
|
|
38
|
+
|
|
39
|
+
// Add the plugin to playwright (any number of plugins can be added)
|
|
40
|
+
chromium.use(StealthPlugin())
|
|
41
|
+
|
|
42
|
+
// That's it, the rest is playwright usage as normal 😊
|
|
43
|
+
const browser = await chromium.launch({ headless: true })
|
|
44
|
+
const page = await browser.newPage()
|
|
45
|
+
|
|
46
|
+
console.log('Testing the stealth plugin..')
|
|
47
|
+
await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle' })
|
|
48
|
+
await page.screenshot({ path: 'stealth.png', fullPage: true })
|
|
49
|
+
|
|
50
|
+
console.log('All done, check the screenshot. ✨')
|
|
51
|
+
await browser.close()
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The above example uses the compatible [`stealth`](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra-plugin-stealth) plugin, which needs to be installed as well:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pnpm add @zorilla/puppeteer-extra-plugin-stealth
|
|
58
|
+
# - or -
|
|
59
|
+
npm install @zorilla/puppeteer-extra-plugin-stealth
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If you'd like to see debug output just run your script like so:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# macOS/Linux (Bash)
|
|
66
|
+
DEBUG=playwright-extra*,puppeteer-extra-plugin* node myscript.js
|
|
67
|
+
|
|
68
|
+
# Windows (Powershell)
|
|
69
|
+
$env:DEBUG='playwright-extra*,puppeteer-extra-plugin*'; node myscript.js
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### More examples
|
|
73
|
+
|
|
74
|
+
<details>
|
|
75
|
+
<summary><strong>TypeScript usage</strong></summary><br/>
|
|
76
|
+
|
|
77
|
+
`playwright-extra` and most plugins are written in TS, so you get perfect type support out of the box. :)
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { chromium } from 'playwright-extra'
|
|
81
|
+
import StealthPlugin from '@zorilla/puppeteer-extra-plugin-stealth'
|
|
82
|
+
|
|
83
|
+
chromium.use(StealthPlugin())
|
|
84
|
+
|
|
85
|
+
const browser = await chromium.launch({ headless: true })
|
|
86
|
+
const page = await browser.newPage()
|
|
87
|
+
|
|
88
|
+
console.log('Testing the stealth plugin..')
|
|
89
|
+
await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle' })
|
|
90
|
+
await page.screenshot({ path: 'stealth.png', fullPage: true })
|
|
91
|
+
|
|
92
|
+
console.log('All done, check the screenshot. ✨')
|
|
93
|
+
await browser.close()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
New to TypeScript? Here's a quick setup:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Create new package.json if it's a new project
|
|
100
|
+
pnpm init
|
|
101
|
+
|
|
102
|
+
# Add TypeScript and dependencies
|
|
103
|
+
pnpm add -D typescript @types/node tsx
|
|
104
|
+
|
|
105
|
+
# Add dependencies used in the quick start example
|
|
106
|
+
pnpm add playwright playwright-extra @zorilla/puppeteer-extra-plugin-stealth
|
|
107
|
+
|
|
108
|
+
# Create a TypeScript config
|
|
109
|
+
pnpm tsc --init
|
|
110
|
+
|
|
111
|
+
# Create source folder for the .ts files
|
|
112
|
+
mkdir src
|
|
113
|
+
|
|
114
|
+
# Now place the example code above in `src/index.ts`
|
|
115
|
+
|
|
116
|
+
# Run the TypeScript code directly (no compilation needed)
|
|
117
|
+
pnpm tsx src/index.ts
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
</details>
|
|
121
|
+
|
|
122
|
+
<details>
|
|
123
|
+
<summary><strong>Using different browsers</strong></summary><br/>
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// Any browser supported by playwright can be used with plugins
|
|
127
|
+
import { chromium, firefox, webkit } from 'playwright-extra'
|
|
128
|
+
|
|
129
|
+
chromium.use(plugin)
|
|
130
|
+
firefox.use(plugin)
|
|
131
|
+
webkit.use(plugin)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
</details>
|
|
135
|
+
|
|
136
|
+
<details>
|
|
137
|
+
<summary><strong>Multiple instances with different plugins</strong></summary><br/>
|
|
138
|
+
|
|
139
|
+
Node.js imports are cached, therefore the default `chromium`, `firefox`, `webkit` exports from `playwright-extra` will always return the same playwright instance.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
// Use `addExtra` to create fresh and independent instances
|
|
143
|
+
import playwright from 'playwright'
|
|
144
|
+
import { addExtra } from 'playwright-extra'
|
|
145
|
+
|
|
146
|
+
const chromium1 = addExtra(playwright.chromium)
|
|
147
|
+
const chromium2 = addExtra(playwright.chromium)
|
|
148
|
+
|
|
149
|
+
chromium1.use(pluginA)
|
|
150
|
+
chromium2.use(pluginB)
|
|
151
|
+
// chromium1 and chromium2 are independent instances
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
</details>
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Plugins
|
|
159
|
+
|
|
160
|
+
The following plugins are compatible with playwright-extra:
|
|
161
|
+
|
|
162
|
+
### 🔥 [`@zorilla/puppeteer-extra-plugin-stealth`](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra-plugin-stealth)
|
|
163
|
+
|
|
164
|
+
- Applies various evasion techniques to make detection of automated browsers harder
|
|
165
|
+
- Compatible with Puppeteer & Playwright and chromium-based browsers
|
|
166
|
+
|
|
167
|
+
<details>
|
|
168
|
+
<summary> Example: Using stealth in Playwright with custom options</summary>
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
// The stealth plugin is optimized for chromium based browsers
|
|
172
|
+
import { chromium } from 'playwright-extra'
|
|
173
|
+
import StealthPlugin from '@zorilla/puppeteer-extra-plugin-stealth'
|
|
174
|
+
|
|
175
|
+
chromium.use(StealthPlugin())
|
|
176
|
+
|
|
177
|
+
// Customize options for specific evasion techniques
|
|
178
|
+
chromium.plugins.setDependencyDefaults('stealth/evasions/webgl.vendor', {
|
|
179
|
+
vendor: 'Bob',
|
|
180
|
+
renderer: 'Alice'
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
// That's it, the rest is playwright usage as normal 😊
|
|
184
|
+
const browser = await chromium.launch({ headless: true })
|
|
185
|
+
const page = await browser.newPage()
|
|
186
|
+
|
|
187
|
+
console.log('Testing the webgl spoofing feature of the stealth plugin..')
|
|
188
|
+
await page.goto('https://webglreport.com', { waitUntil: 'networkidle' })
|
|
189
|
+
await page.screenshot({ path: 'webgl.png', fullPage: true })
|
|
190
|
+
|
|
191
|
+
console.log('All done, check the screenshot. ✨')
|
|
192
|
+
await browser.close()
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
</details>
|
|
196
|
+
|
|
197
|
+
### 🏴 [`puppeteer-extra-plugin-recaptcha`](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra-plugin-recaptcha)
|
|
198
|
+
|
|
199
|
+
- Solves reCAPTCHAs and hCaptchas automatically, using a single line of code: `page.solveRecaptchas()`
|
|
200
|
+
- Compatible with Puppeteer & Playwright and all browsers (chromium, firefox, webkit)
|
|
201
|
+
|
|
202
|
+
<details>
|
|
203
|
+
<summary> Example: Solving captchas in Playwright & Firefox</summary>
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
// Any browser (chromium, webkit, firefox) can be used
|
|
207
|
+
import { firefox } from 'playwright-extra'
|
|
208
|
+
import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha'
|
|
209
|
+
|
|
210
|
+
firefox.use(
|
|
211
|
+
RecaptchaPlugin({
|
|
212
|
+
provider: {
|
|
213
|
+
id: '2captcha',
|
|
214
|
+
token: process.env.TWOCAPTCHA_TOKEN || 'YOUR_API_KEY'
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
// Works in headless as well
|
|
220
|
+
const browser = await firefox.launch({ headless: false })
|
|
221
|
+
const context = await browser.newContext()
|
|
222
|
+
const page = await context.newPage()
|
|
223
|
+
|
|
224
|
+
await page.goto('https://www.google.com/recaptcha/api2/demo', {
|
|
225
|
+
waitUntil: 'networkidle'
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
console.log('Solving captchas..')
|
|
229
|
+
await page.solveRecaptchas()
|
|
230
|
+
|
|
231
|
+
await Promise.all([
|
|
232
|
+
page.waitForNavigation({ waitUntil: 'networkidle' }),
|
|
233
|
+
page.click('#recaptcha-demo-submit')
|
|
234
|
+
])
|
|
235
|
+
|
|
236
|
+
const content = await page.content()
|
|
237
|
+
const isSuccess = content.includes('Verification Success')
|
|
238
|
+
console.log('Done', { isSuccess })
|
|
239
|
+
await browser.close()
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
</details>
|
|
243
|
+
|
|
244
|
+
### 📡 [`@zorilla/plugin-proxy-router`](https://github.com/zorillajs/zorilla/tree/main/packages/plugin-proxy-router)
|
|
245
|
+
|
|
246
|
+
- Use multiple proxies dynamically with flexible per-host routing
|
|
247
|
+
- Compatible with Puppeteer & Playwright and all browsers (chromium, firefox, webkit)
|
|
248
|
+
|
|
249
|
+
### 🔌 [`@zorilla/puppeteer-extra-plugin-anonymize-ua`](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra-plugin-anonymize-ua)
|
|
250
|
+
|
|
251
|
+
- Anonymizes the user-agent on all pages
|
|
252
|
+
- Compatible with Puppeteer & Playwright
|
|
253
|
+
|
|
254
|
+
**Additional Resources**
|
|
255
|
+
|
|
256
|
+
- For adblocking, consider using [@cliqz/adblocker-playwright](https://www.npmjs.com/package/@cliqz/adblocker-playwright) or [blocking resources natively](https://playwright.dev/docs/network#handle-requests)
|
|
257
|
+
- To write your own plugins, check out the [`@zorilla/puppeteer-extra-plugin`](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra-plugin) base class
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Development
|
|
262
|
+
|
|
263
|
+
This package is part of the [zorilla monorepo](https://github.com/zorillajs/zorilla) and uses:
|
|
264
|
+
- **TypeScript** for type safety (ESM only, no CommonJS support)
|
|
265
|
+
- **Playwright Test** for testing across chromium, firefox, and webkit
|
|
266
|
+
- **c8** for coverage reporting
|
|
267
|
+
- **Biome** for linting and formatting
|
|
268
|
+
|
|
269
|
+
### Building and Testing
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Install dependencies (from monorepo root)
|
|
273
|
+
pnpm install
|
|
274
|
+
|
|
275
|
+
# Build the package
|
|
276
|
+
pnpm build
|
|
277
|
+
|
|
278
|
+
# Run tests (requires Playwright browsers to be installed)
|
|
279
|
+
pnpm test
|
|
280
|
+
|
|
281
|
+
# Run tests with coverage
|
|
282
|
+
pnpm test:coverage
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Code Quality
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# Check code formatting and linting
|
|
289
|
+
npx biome check .
|
|
290
|
+
|
|
291
|
+
# Auto-fix formatting issues
|
|
292
|
+
npx biome check --write .
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Browser Installation
|
|
296
|
+
|
|
297
|
+
Tests require Playwright browsers. Install them with:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
pnpm exec playwright install
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## API
|
|
306
|
+
|
|
307
|
+
### Default Export
|
|
308
|
+
|
|
309
|
+
The package exports augmented browser launchers that work as drop-in replacements for playwright:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { chromium, firefox, webkit } from 'playwright-extra'
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### `addExtra(launcher)`
|
|
316
|
+
|
|
317
|
+
Create a fresh playwright-extra instance with its own plugin registry:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
import { addExtra } from 'playwright-extra'
|
|
321
|
+
import playwright from 'playwright'
|
|
322
|
+
|
|
323
|
+
const chromium = addExtra(playwright.chromium)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### `launcher.use(plugin)`
|
|
327
|
+
|
|
328
|
+
Register a plugin with the browser launcher:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
chromium.use(StealthPlugin())
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### `launcher.plugins`
|
|
335
|
+
|
|
336
|
+
Access the plugin registry to configure plugins:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
// Set default options for a plugin dependency
|
|
340
|
+
chromium.plugins.setDependencyDefaults('stealth/evasions/webgl.vendor', {
|
|
341
|
+
vendor: 'Custom',
|
|
342
|
+
renderer: 'Custom'
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
// List registered plugins
|
|
346
|
+
console.log(chromium.plugins.names)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Contributors
|
|
352
|
+
|
|
353
|
+
<a href="https://github.com/zorillajs/zorilla/graphs/contributors">
|
|
354
|
+
<img src="https://contributors-img.firebaseapp.com/image?repo=zorillajs/zorilla" />
|
|
355
|
+
</a>
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
Copyright © 2018 - 2025, [berstend](https://github.com/berstend). Released under the MIT License.
|
package/dist/extra.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type * as pw from 'playwright-core';
|
|
2
|
+
import { PluginList } from './plugins.js';
|
|
3
|
+
import type { CompatiblePlugin } from './types/index.js';
|
|
4
|
+
type PlaywrightBrowserLauncher = pw.BrowserType;
|
|
5
|
+
/**
|
|
6
|
+
* The Playwright browser launcher APIs we're augmenting
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
interface AugmentedLauncherAPIs extends Pick<PlaywrightBrowserLauncher, 'launch' | 'launchPersistentContext' | 'connect' | 'connectOverCDP'> {
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Modular plugin framework to teach `playwright` new tricks.
|
|
13
|
+
*/
|
|
14
|
+
export declare class PlaywrightExtraClass implements AugmentedLauncherAPIs {
|
|
15
|
+
private _launcher?;
|
|
16
|
+
/** Plugin manager */
|
|
17
|
+
readonly plugins: PluginList;
|
|
18
|
+
constructor(_launcher?: Partial<PlaywrightBrowserLauncher> | undefined);
|
|
19
|
+
/**
|
|
20
|
+
* The **main interface** to register plugins.
|
|
21
|
+
*
|
|
22
|
+
* Can be called multiple times to enable multiple plugins.
|
|
23
|
+
*
|
|
24
|
+
* Plugins derived from `PuppeteerExtraPlugin` will be used with a compatiblity layer.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* chromium.use(plugin1).use(plugin2)
|
|
28
|
+
* firefox.use(plugin1).use(plugin2)
|
|
29
|
+
*
|
|
30
|
+
* @see [PuppeteerExtraPlugin]
|
|
31
|
+
*
|
|
32
|
+
* @return The same `PlaywrightExtra` instance (for optional chaining)
|
|
33
|
+
*/
|
|
34
|
+
use(plugin: CompatiblePlugin): this;
|
|
35
|
+
launch(...args: Parameters<PlaywrightBrowserLauncher['launch']>): ReturnType<PlaywrightBrowserLauncher['launch']>;
|
|
36
|
+
launchPersistentContext(...args: Parameters<PlaywrightBrowserLauncher['launchPersistentContext']>): ReturnType<PlaywrightBrowserLauncher['launchPersistentContext']>;
|
|
37
|
+
connect(wsEndpointOrOptions: string | (pw.ConnectOptions & {
|
|
38
|
+
wsEndpoint?: string;
|
|
39
|
+
}), wsOptions?: pw.ConnectOptions): ReturnType<PlaywrightBrowserLauncher['connect']>;
|
|
40
|
+
connectOverCDP(wsEndpointOrOptions: string | (pw.ConnectOverCDPOptions & {
|
|
41
|
+
endpointURL?: string;
|
|
42
|
+
}), wsOptions?: pw.ConnectOverCDPOptions): ReturnType<PlaywrightBrowserLauncher['connectOverCDP']>;
|
|
43
|
+
protected _bindBrowserContextEvents(context: pw.BrowserContext, contextOptions?: pw.BrowserContextOptions): Promise<void>;
|
|
44
|
+
protected _bindBrowserEvents(browser: pw.Browser): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* PlaywrightExtra class with additional launcher methods.
|
|
48
|
+
*
|
|
49
|
+
* Augments the class with an instance proxy to pass on methods that are not augmented to the original target.
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
export declare const PlaywrightExtra: typeof PlaywrightExtraClass;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=extra.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extra.d.ts","sourceRoot":"","sources":["../src/extra.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAU,MAAM,kBAAkB,CAAC;AAEjE,KAAK,yBAAyB,GAAG,EAAE,CAAC,WAAW,CAAC;AAEhD;;;GAGG;AACH,UAAU,qBACR,SAAQ,IAAI,CACV,yBAAyB,EACzB,QAAQ,GAAG,yBAAyB,GAAG,SAAS,GAAG,gBAAgB,CACpE;CAAG;AAEN;;GAEG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAIpD,OAAO,CAAC,SAAS,CAAC;IAH9B,qBAAqB;IACrB,SAAgB,OAAO,EAAE,UAAU,CAAC;gBAEhB,SAAS,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,YAAA;IAIlE;;;;;;;;;;;;;;OAcG;IACI,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IA4B7B,MAAM,CACjB,GAAG,IAAI,EAAE,UAAU,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,GACvD,UAAU,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IA8BrC,uBAAuB,CAClC,GAAG,IAAI,EAAE,UAAU,CAAC,yBAAyB,CAAC,yBAAyB,CAAC,CAAC,GACxE,UAAU,CAAC,yBAAyB,CAAC,yBAAyB,CAAC,CAAC;IAuB7D,OAAO,CACX,mBAAmB,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,cAAc,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAC3E,SAAS,GAAE,EAAE,CAAC,cAAmB,GAChC,UAAU,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC;IA2C7C,cAAc,CAClB,mBAAmB,EACf,MAAM,GACN,CAAC,EAAE,CAAC,qBAAqB,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EACzD,SAAS,GAAE,EAAE,CAAC,qBAA0B,GACvC,UAAU,CAAC,yBAAyB,CAAC,gBAAgB,CAAC,CAAC;cA2C1C,yBAAyB,CACvC,OAAO,EAAE,EAAE,CAAC,cAAc,EAC1B,cAAc,CAAC,EAAE,EAAE,CAAC,qBAAqB;cA4B3B,kBAAkB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO;CAsBvD;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,6BAc1B,CAAC"}
|
package/dist/extra.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import Debug from 'debug';
|
|
2
|
+
const debug = Debug('playwright-extra');
|
|
3
|
+
import { playwrightLoader } from './helper/loader.js';
|
|
4
|
+
import { PluginList } from './plugins.js';
|
|
5
|
+
/**
|
|
6
|
+
* Modular plugin framework to teach `playwright` new tricks.
|
|
7
|
+
*/
|
|
8
|
+
export class PlaywrightExtraClass {
|
|
9
|
+
_launcher;
|
|
10
|
+
/** Plugin manager */
|
|
11
|
+
plugins;
|
|
12
|
+
constructor(_launcher) {
|
|
13
|
+
this._launcher = _launcher;
|
|
14
|
+
this.plugins = new PluginList();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The **main interface** to register plugins.
|
|
18
|
+
*
|
|
19
|
+
* Can be called multiple times to enable multiple plugins.
|
|
20
|
+
*
|
|
21
|
+
* Plugins derived from `PuppeteerExtraPlugin` will be used with a compatiblity layer.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* chromium.use(plugin1).use(plugin2)
|
|
25
|
+
* firefox.use(plugin1).use(plugin2)
|
|
26
|
+
*
|
|
27
|
+
* @see [PuppeteerExtraPlugin]
|
|
28
|
+
*
|
|
29
|
+
* @return The same `PlaywrightExtra` instance (for optional chaining)
|
|
30
|
+
*/
|
|
31
|
+
use(plugin) {
|
|
32
|
+
const isValid = plugin && 'name' in plugin;
|
|
33
|
+
if (!isValid) {
|
|
34
|
+
throw new Error('A plugin must be provided to .use()');
|
|
35
|
+
}
|
|
36
|
+
if (this.plugins.add(plugin)) {
|
|
37
|
+
debug('Plugin registered', plugin.name);
|
|
38
|
+
}
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* In order to support a default export which will require vanilla playwright automatically,
|
|
43
|
+
* as well as `addExtra` to patch a provided launcher, we need to so some gymnastics here.
|
|
44
|
+
*
|
|
45
|
+
* Otherwise this would throw immediately, even when only using the `addExtra` export with an arbitrary compatible launcher.
|
|
46
|
+
*
|
|
47
|
+
* The solution is to make the vanilla launcher optional and only throw once we try to effectively use and can't find it.
|
|
48
|
+
*
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
get launcher() {
|
|
52
|
+
if (!this._launcher) {
|
|
53
|
+
throw playwrightLoader.requireError;
|
|
54
|
+
}
|
|
55
|
+
return this._launcher;
|
|
56
|
+
}
|
|
57
|
+
async launch(...args) {
|
|
58
|
+
if (!this.launcher.launch) {
|
|
59
|
+
throw new Error('Launcher does not support "launch"');
|
|
60
|
+
}
|
|
61
|
+
let [options] = args;
|
|
62
|
+
options = { args: [], ...(options || {}) }; // Initialize args array
|
|
63
|
+
debug('launch', options);
|
|
64
|
+
this.plugins.prepare();
|
|
65
|
+
// Give plugins the chance to modify the options before continuing
|
|
66
|
+
options =
|
|
67
|
+
(await this.plugins.dispatchBlocking('beforeLaunch', options)) || options;
|
|
68
|
+
debug('launch with options', options);
|
|
69
|
+
if ('userDataDir' in options) {
|
|
70
|
+
debug("A plugin defined userDataDir during .launch, which isn't supported by playwright - ignoring");
|
|
71
|
+
const { userDataDir: _, ...optionsWithoutUserDataDir } = options;
|
|
72
|
+
options = optionsWithoutUserDataDir;
|
|
73
|
+
}
|
|
74
|
+
const browser = await this.launcher.launch(options);
|
|
75
|
+
await this.plugins.dispatchBlocking('onBrowser', browser);
|
|
76
|
+
await this._bindBrowserEvents(browser);
|
|
77
|
+
await this.plugins.dispatchBlocking('afterLaunch', browser);
|
|
78
|
+
return browser;
|
|
79
|
+
}
|
|
80
|
+
async launchPersistentContext(...args) {
|
|
81
|
+
if (!this.launcher.launchPersistentContext) {
|
|
82
|
+
throw new Error('Launcher does not support "launchPersistentContext"');
|
|
83
|
+
}
|
|
84
|
+
let [userDataDir, options] = args;
|
|
85
|
+
options = { args: [], ...(options || {}) }; // Initialize args array
|
|
86
|
+
debug('launchPersistentContext', options);
|
|
87
|
+
this.plugins.prepare();
|
|
88
|
+
// Give plugins the chance to modify the options before continuing
|
|
89
|
+
options =
|
|
90
|
+
(await this.plugins.dispatchBlocking('beforeLaunch', options)) || options;
|
|
91
|
+
const context = await this.launcher.launchPersistentContext(userDataDir, options);
|
|
92
|
+
await this.plugins.dispatchBlocking('afterLaunch', context);
|
|
93
|
+
this._bindBrowserContextEvents(context);
|
|
94
|
+
return context;
|
|
95
|
+
}
|
|
96
|
+
async connect(wsEndpointOrOptions, wsOptions = {}) {
|
|
97
|
+
if (!this.launcher.connect) {
|
|
98
|
+
throw new Error('Launcher does not support "connect"');
|
|
99
|
+
}
|
|
100
|
+
this.plugins.prepare();
|
|
101
|
+
// Playwright currently supports two function signatures for .connect
|
|
102
|
+
let options = {};
|
|
103
|
+
let wsEndpointAsString = false;
|
|
104
|
+
if (typeof wsEndpointOrOptions === 'object') {
|
|
105
|
+
options = { ...wsEndpointOrOptions, ...wsOptions };
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
wsEndpointAsString = true;
|
|
109
|
+
options = { wsEndpoint: wsEndpointOrOptions, ...wsOptions };
|
|
110
|
+
}
|
|
111
|
+
debug('connect', options);
|
|
112
|
+
// Give plugins the chance to modify the options before launch/connect
|
|
113
|
+
options =
|
|
114
|
+
(await this.plugins.dispatchBlocking('beforeConnect', options)) ||
|
|
115
|
+
options;
|
|
116
|
+
// Follow call signature of end user
|
|
117
|
+
const args = [];
|
|
118
|
+
const wsEndpoint = options.wsEndpoint;
|
|
119
|
+
if (wsEndpointAsString) {
|
|
120
|
+
delete options.wsEndpoint;
|
|
121
|
+
args.push(wsEndpoint, options);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
args.push(options);
|
|
125
|
+
}
|
|
126
|
+
const connectFn = this.launcher.connect;
|
|
127
|
+
const browser = await connectFn.call(this.launcher, ...args);
|
|
128
|
+
await this.plugins.dispatchBlocking('onBrowser', browser);
|
|
129
|
+
await this._bindBrowserEvents(browser);
|
|
130
|
+
await this.plugins.dispatchBlocking('afterConnect', browser);
|
|
131
|
+
return browser;
|
|
132
|
+
}
|
|
133
|
+
async connectOverCDP(wsEndpointOrOptions, wsOptions = {}) {
|
|
134
|
+
if (!this.launcher.connectOverCDP) {
|
|
135
|
+
throw new Error(`Launcher does not implement 'connectOverCDP'`);
|
|
136
|
+
}
|
|
137
|
+
this.plugins.prepare();
|
|
138
|
+
// Playwright currently supports two function signatures for .connectOverCDP
|
|
139
|
+
let options = {};
|
|
140
|
+
let wsEndpointAsString = false;
|
|
141
|
+
if (typeof wsEndpointOrOptions === 'object') {
|
|
142
|
+
options = { ...wsEndpointOrOptions, ...wsOptions };
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
wsEndpointAsString = true;
|
|
146
|
+
options = { endpointURL: wsEndpointOrOptions, ...wsOptions };
|
|
147
|
+
}
|
|
148
|
+
debug('connectOverCDP', options);
|
|
149
|
+
// Give plugins the chance to modify the options before launch/connect
|
|
150
|
+
options =
|
|
151
|
+
(await this.plugins.dispatchBlocking('beforeConnect', options)) ||
|
|
152
|
+
options;
|
|
153
|
+
// Follow call signature of end user
|
|
154
|
+
const args = [];
|
|
155
|
+
const endpointURL = options.endpointURL;
|
|
156
|
+
if (wsEndpointAsString) {
|
|
157
|
+
delete options.endpointURL;
|
|
158
|
+
args.push(endpointURL, options);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
args.push(options);
|
|
162
|
+
}
|
|
163
|
+
const connectOverCDPFn = this.launcher.connectOverCDP;
|
|
164
|
+
const browser = await connectOverCDPFn.call(this.launcher, ...args);
|
|
165
|
+
await this.plugins.dispatchBlocking('onBrowser', browser);
|
|
166
|
+
await this._bindBrowserEvents(browser);
|
|
167
|
+
await this.plugins.dispatchBlocking('afterConnect', browser);
|
|
168
|
+
return browser;
|
|
169
|
+
}
|
|
170
|
+
async _bindBrowserContextEvents(context, contextOptions) {
|
|
171
|
+
debug('_bindBrowserContextEvents');
|
|
172
|
+
this.plugins.dispatch('onContextCreated', context, contextOptions);
|
|
173
|
+
// Make sure things like `addInitScript` show an effect on the very first page as well
|
|
174
|
+
context.newPage = ((originalMethod, ctx) => {
|
|
175
|
+
return async () => {
|
|
176
|
+
const page = await originalMethod.call(ctx);
|
|
177
|
+
await page.goto('about:blank');
|
|
178
|
+
return page;
|
|
179
|
+
};
|
|
180
|
+
})(context.newPage, context);
|
|
181
|
+
context.on('close', () => {
|
|
182
|
+
// When using `launchPersistentContext` context closing is the same as browser closing
|
|
183
|
+
if (!context.browser()) {
|
|
184
|
+
this.plugins.dispatch('onDisconnected');
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
context.on('page', page => {
|
|
188
|
+
this.plugins.dispatch('onPageCreated', page);
|
|
189
|
+
page.on('close', () => {
|
|
190
|
+
this.plugins.dispatch('onPageClose', page);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
async _bindBrowserEvents(browser) {
|
|
195
|
+
debug('_bindPlaywrightBrowserEvents');
|
|
196
|
+
browser.on('disconnected', () => {
|
|
197
|
+
this.plugins.dispatch('onDisconnected', browser);
|
|
198
|
+
});
|
|
199
|
+
// Note: `browser.newPage` will implicitly call `browser.newContext` as well
|
|
200
|
+
browser.newContext = ((originalMethod, ctx) => {
|
|
201
|
+
return async (options = {}) => {
|
|
202
|
+
const contextOptions = (await this.plugins.dispatchBlocking('beforeContext', options, browser)) || options;
|
|
203
|
+
const context = await originalMethod.call(ctx, contextOptions);
|
|
204
|
+
this._bindBrowserContextEvents(context, contextOptions);
|
|
205
|
+
return context;
|
|
206
|
+
};
|
|
207
|
+
})(browser.newContext, browser);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* PlaywrightExtra class with additional launcher methods.
|
|
212
|
+
*
|
|
213
|
+
* Augments the class with an instance proxy to pass on methods that are not augmented to the original target.
|
|
214
|
+
*
|
|
215
|
+
*/
|
|
216
|
+
export const PlaywrightExtra = new Proxy(PlaywrightExtraClass, {
|
|
217
|
+
construct(classTarget, args) {
|
|
218
|
+
debug(`create instance of ${classTarget.name}`);
|
|
219
|
+
const result = Reflect.construct(classTarget, args);
|
|
220
|
+
return new Proxy(result, {
|
|
221
|
+
get(target, prop) {
|
|
222
|
+
if (prop in target) {
|
|
223
|
+
return Reflect.get(target, prop);
|
|
224
|
+
}
|
|
225
|
+
debug('proxying property to original launcher: ', prop);
|
|
226
|
+
return Reflect.get(target.launcher, prop);
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
//# sourceMappingURL=extra.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extra.js","sourceRoot":"","sources":["../src/extra.ts"],"names":[],"mappings":"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"}
|