@browserless.io/browserless 2.12.0-beta-2 → 2.12.0-beta-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/build/browserless.d.ts +1 -0
- package/build/browserless.js +6 -0
- package/build/browsers/chromium.cdp.d.ts +1 -1
- package/build/browsers/chromium.cdp.js +2 -2
- package/build/browsers/chromium.playwright.d.ts +2 -2
- package/build/browsers/chromium.playwright.js +7 -5
- package/build/browsers/firefox.playwright.d.ts +2 -2
- package/build/browsers/firefox.playwright.js +7 -5
- package/build/browsers/index.d.ts +3 -2
- package/build/browsers/index.js +40 -16
- package/build/browsers/webkit.playwright.d.ts +2 -2
- package/build/browsers/webkit.playwright.js +7 -5
- package/build/config.d.ts +11 -0
- package/build/config.js +16 -0
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chrome/tests/websocket.spec.js +18 -3
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/tests/websocket.spec.js +18 -0
- package/build/routes/firefox/tests/websocket.spec.js +18 -1
- package/build/routes/webkit/tests/websocket.spec.js +18 -0
- package/build/types.d.ts +1 -1
- package/build/utils.d.ts +9 -0
- package/build/utils.js +9 -0
- package/docker/chromium/Dockerfile +2 -1
- package/docker/firefox/Dockerfile +2 -1
- package/docker/multi/Dockerfile +1 -1
- package/docker/webkit/Dockerfile +2 -1
- package/extensions/ublock/_locales/eu/messages.json +4 -4
- package/extensions/ublock/_locales/hi/messages.json +5 -5
- package/extensions/ublock/_locales/kn/messages.json +11 -11
- package/extensions/ublock/_locales/nb/messages.json +2 -2
- package/extensions/ublock/_locales/no/messages.json +2 -2
- package/extensions/ublock/_locales/ro/messages.json +1 -1
- package/extensions/ublock/_locales/sv/messages.json +1 -1
- package/extensions/ublock/_locales/zh_CN/messages.json +2 -2
- package/extensions/ublock/assets/assets.json +3 -8
- package/extensions/ublock/assets/resources/scriptlets.js +128 -31
- package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +4870 -3560
- package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +662 -173
- package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +10 -42
- package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +241 -80
- package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +2093 -1224
- package/extensions/ublock/assets/ublock/badlists.txt +2 -0
- package/extensions/ublock/assets/ublock/badware.min.txt +408 -287
- package/extensions/ublock/assets/ublock/filters.min.txt +947 -645
- package/extensions/ublock/assets/ublock/privacy.min.txt +43 -8
- package/extensions/ublock/assets/ublock/quick-fixes.min.txt +55 -93
- package/extensions/ublock/assets/ublock/unbreak.min.txt +52 -19
- package/extensions/ublock/css/1p-filters.css +2 -0
- package/extensions/ublock/css/codemirror.css +2 -2
- package/extensions/ublock/css/dashboard.css +2 -5
- package/extensions/ublock/css/epicker-ui.css +3 -3
- package/extensions/ublock/css/fa-icons.css +3 -0
- package/extensions/ublock/css/logger-ui-inspector.css +1 -0
- package/extensions/ublock/css/logger-ui.css +44 -32
- package/extensions/ublock/img/fontawesome/fontawesome-defs.svg +1 -0
- package/extensions/ublock/js/3p-filters.js +4 -5
- package/extensions/ublock/js/biditrie.js +16 -11
- package/extensions/ublock/js/cachestorage.js +37 -37
- package/extensions/ublock/js/contentscript-extra.js +0 -2
- package/extensions/ublock/js/contentscript.js +1 -6
- package/extensions/ublock/js/epicker-ui.js +28 -36
- package/extensions/ublock/js/fa-icons.js +1 -0
- package/extensions/ublock/js/hntrie.js +19 -13
- package/extensions/ublock/js/logger-ui-inspector.js +6 -13
- package/extensions/ublock/js/logger-ui.js +264 -264
- package/extensions/ublock/js/s14e-serializer.js +267 -264
- package/extensions/ublock/js/scriptlet-filtering.js +12 -18
- package/extensions/ublock/js/scriptlets/dom-inspector.js +1 -5
- package/extensions/ublock/js/scriptlets/epicker.js +53 -59
- package/extensions/ublock/js/start.js +0 -8
- package/extensions/ublock/js/storage.js +2 -9
- package/extensions/ublock/js/vapi-background.js +19 -20
- package/extensions/ublock/js/vapi-common.js +2 -7
- package/extensions/ublock/js/vapi.js +0 -4
- package/extensions/ublock/js/webext.js +23 -15
- package/extensions/ublock/logger-ui.html +24 -15
- package/extensions/ublock/manifest.json +2 -3
- package/package.json +18 -6
- package/src/browserless.ts +11 -0
- package/src/browsers/chromium.cdp.ts +2 -2
- package/src/browsers/chromium.playwright.ts +8 -4
- package/src/browsers/firefox.playwright.ts +8 -5
- package/src/browsers/index.ts +53 -18
- package/src/browsers/webkit.playwright.ts +8 -4
- package/src/config.ts +20 -0
- package/src/routes/chrome/tests/websocket.spec.ts +25 -4
- package/src/routes/chromium/tests/websocket.spec.ts +25 -0
- package/src/routes/firefox/tests/websocket.spec.ts +25 -1
- package/src/routes/webkit/tests/websocket.spec.ts +25 -0
- package/src/types.ts +1 -1
- package/src/utils.ts +9 -0
- package/static/docs/swagger.json +9 -9
- package/static/docs/swagger.min.json +9 -9
- package/static/function/client.js +95 -136
- package/static/function/index.html +95 -136
|
@@ -43,8 +43,8 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
43
43
|
this.removeAllListeners();
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
public
|
|
47
|
-
return
|
|
46
|
+
public keepUntil() {
|
|
47
|
+
return 0;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
public isRunning = (): boolean => this.running;
|
|
@@ -89,10 +89,11 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
89
89
|
|
|
90
90
|
public launch = async (
|
|
91
91
|
options: BrowserServerOptions = {},
|
|
92
|
+
version?: string,
|
|
92
93
|
): Promise<playwright.BrowserServer> => {
|
|
93
94
|
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
const opts = {
|
|
96
97
|
...options,
|
|
97
98
|
args: [
|
|
98
99
|
`--no-sandbox`,
|
|
@@ -100,8 +101,11 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
100
101
|
this.userDataDir ? `--user-data-dir=${this.userDataDir}` : '',
|
|
101
102
|
],
|
|
102
103
|
executablePath: this.executablePath,
|
|
103
|
-
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const versionedPw = await this.config.loadPwVersion(version!);
|
|
104
107
|
|
|
108
|
+
this.browser = await versionedPw.chromium.launchServer(opts);
|
|
105
109
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
106
110
|
|
|
107
111
|
this.logger.info(
|
|
@@ -42,8 +42,8 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
42
42
|
this.removeAllListeners();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
public
|
|
46
|
-
return
|
|
45
|
+
public keepUntil() {
|
|
46
|
+
return 0;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
public isRunning = (): boolean => this.running;
|
|
@@ -84,18 +84,21 @@ export class FirefoxPlaywright extends EventEmitter {
|
|
|
84
84
|
|
|
85
85
|
public launch = async (
|
|
86
86
|
options: BrowserServerOptions = {},
|
|
87
|
+
version?: string,
|
|
87
88
|
): Promise<playwright.BrowserServer> => {
|
|
88
89
|
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
89
|
-
|
|
90
|
-
this.browser = await playwright.firefox.launchServer({
|
|
90
|
+
const opts = {
|
|
91
91
|
...options,
|
|
92
92
|
args: [
|
|
93
93
|
...(options.args || []),
|
|
94
94
|
this.userDataDir ? `-profile=${this.userDataDir}` : '',
|
|
95
95
|
],
|
|
96
96
|
executablePath: playwright.firefox.executablePath(),
|
|
97
|
-
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const versionedPw = await this.config.loadPwVersion(version!);
|
|
98
100
|
|
|
101
|
+
this.browser = await versionedPw.firefox.launchServer(opts);
|
|
99
102
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
100
103
|
|
|
101
104
|
this.logger.info(
|
package/src/browsers/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
makeExternalURL,
|
|
30
30
|
noop,
|
|
31
31
|
parseBooleanParam,
|
|
32
|
+
pwVersionRegex,
|
|
32
33
|
} from '@browserless.io/browserless';
|
|
33
34
|
import { Page } from 'puppeteer-core';
|
|
34
35
|
import { deleteAsync } from 'del';
|
|
@@ -36,7 +37,7 @@ import path from 'path';
|
|
|
36
37
|
|
|
37
38
|
export class BrowserManager {
|
|
38
39
|
protected browsers: Map<BrowserInstance, BrowserlessSession> = new Map();
|
|
39
|
-
protected timers: Map<string,
|
|
40
|
+
protected timers: Map<string, NodeJS.Timeout> = new Map();
|
|
40
41
|
protected log = new Logger('browser-manager');
|
|
41
42
|
protected chromeBrowsers = [ChromiumCDP, ChromeCDP];
|
|
42
43
|
protected playwrightBrowserNames = [
|
|
@@ -225,7 +226,7 @@ export class BrowserManager {
|
|
|
225
226
|
{
|
|
226
227
|
...session,
|
|
227
228
|
browser: browser.constructor.name,
|
|
228
|
-
browserId:
|
|
229
|
+
browserId: session.id,
|
|
229
230
|
initialConnectURL: new URL(session.initialConnectURL, serverAddress)
|
|
230
231
|
.href,
|
|
231
232
|
killURL: session.id
|
|
@@ -267,26 +268,54 @@ export class BrowserManager {
|
|
|
267
268
|
browser: BrowserInstance,
|
|
268
269
|
session: BrowserlessSession,
|
|
269
270
|
): Promise<void> => {
|
|
271
|
+
const now = Date.now();
|
|
272
|
+
const keepUntil = browser.keepUntil();
|
|
273
|
+
const connected = session.numbConnected;
|
|
274
|
+
const hasKeepUntil = keepUntil > now;
|
|
275
|
+
const keepOpen = connected > 0 || hasKeepUntil;
|
|
270
276
|
const cleanupACtions: Array<() => Promise<void>> = [];
|
|
271
|
-
this.
|
|
277
|
+
const priorTimer = this.timers.get(session.id);
|
|
272
278
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
279
|
+
if (priorTimer) {
|
|
280
|
+
this.log.info(`Deleting prior keep-until timer for "${session.id}"`);
|
|
281
|
+
global.clearTimeout(priorTimer);
|
|
276
282
|
}
|
|
277
283
|
|
|
278
|
-
this.log.info(
|
|
279
|
-
|
|
284
|
+
this.log.info(
|
|
285
|
+
`${session.numbConnected} Client(s) are currently connected, Keep-until: ${keepUntil}`,
|
|
286
|
+
);
|
|
280
287
|
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
|
|
288
|
+
if (hasKeepUntil) {
|
|
289
|
+
const timeout = keepUntil - now;
|
|
290
|
+
this.log.trace(
|
|
291
|
+
`Setting timer ${timeout.toLocaleString()} for "${session.id}"`,
|
|
292
|
+
);
|
|
293
|
+
this.timers.set(
|
|
294
|
+
session.id,
|
|
295
|
+
global.setTimeout(() => {
|
|
296
|
+
const session = this.browsers.get(browser);
|
|
297
|
+
if (session) {
|
|
298
|
+
this.log.trace(`Timer hit for "${session.id}"`),
|
|
299
|
+
this.close(browser, session);
|
|
300
|
+
}
|
|
301
|
+
}, timeout),
|
|
284
302
|
);
|
|
285
|
-
this.browsers.delete(browser);
|
|
286
|
-
cleanupACtions.push(() => this.removeUserDataDir(session.userDataDir));
|
|
287
303
|
}
|
|
288
304
|
|
|
289
|
-
|
|
305
|
+
if (!keepOpen) {
|
|
306
|
+
this.log.info(`Closing browser session`);
|
|
307
|
+
cleanupACtions.push(() => browser.close());
|
|
308
|
+
|
|
309
|
+
if (session.isTempDataDir) {
|
|
310
|
+
this.log.info(
|
|
311
|
+
`Deleting "${session.userDataDir}" user-data-dir and session from memory`,
|
|
312
|
+
);
|
|
313
|
+
this.browsers.delete(browser);
|
|
314
|
+
cleanupACtions.push(() => this.removeUserDataDir(session.userDataDir));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
await Promise.all(cleanupACtions.map((a) => a()));
|
|
318
|
+
}
|
|
290
319
|
};
|
|
291
320
|
|
|
292
321
|
public getAllSessions = async (): Promise<BrowserlessSessionJSON[]> => {
|
|
@@ -436,6 +465,9 @@ export class BrowserManager {
|
|
|
436
465
|
arg.includes('--proxy-server='),
|
|
437
466
|
);
|
|
438
467
|
|
|
468
|
+
/**
|
|
469
|
+
* If it is a playwright request
|
|
470
|
+
*/
|
|
439
471
|
if (
|
|
440
472
|
launchOptions.args &&
|
|
441
473
|
proxyServerArg &&
|
|
@@ -455,8 +487,14 @@ export class BrowserManager {
|
|
|
455
487
|
userDataDir,
|
|
456
488
|
});
|
|
457
489
|
|
|
490
|
+
const match = (req.headers['user-agent'] || '').match(pwVersionRegex);
|
|
491
|
+
const pwVersion = match ? match[1] : 'default';
|
|
492
|
+
|
|
493
|
+
await browser.launch(launchOptions as object, pwVersion);
|
|
494
|
+
await this.hooks.browser({ browser, meta: req.parsed });
|
|
495
|
+
|
|
458
496
|
const session: BrowserlessSession = {
|
|
459
|
-
id:
|
|
497
|
+
id: browser.wsEndpoint()?.split('/').pop() as string,
|
|
460
498
|
initialConnectURL:
|
|
461
499
|
path.join(req.parsed.pathname, req.parsed.search) || '',
|
|
462
500
|
isTempDataDir: !manualUserDataDir,
|
|
@@ -471,9 +509,6 @@ export class BrowserManager {
|
|
|
471
509
|
|
|
472
510
|
this.browsers.set(browser, session);
|
|
473
511
|
|
|
474
|
-
await browser.launch(launchOptions as object);
|
|
475
|
-
await this.hooks.browser({ browser, meta: req.parsed });
|
|
476
|
-
|
|
477
512
|
browser.on('newPage', async (page) => {
|
|
478
513
|
await this.onNewPage(req, page);
|
|
479
514
|
(router.onNewPage || noop)(req.parsed || '', page);
|
|
@@ -42,8 +42,8 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
42
42
|
this.removeAllListeners();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
public
|
|
46
|
-
return
|
|
45
|
+
public keepUntil() {
|
|
46
|
+
return 0;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
public isRunning = (): boolean => this.running;
|
|
@@ -84,18 +84,22 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
84
84
|
|
|
85
85
|
public launch = async (
|
|
86
86
|
options: BrowserServerOptions = {},
|
|
87
|
+
version?: string,
|
|
87
88
|
): Promise<playwright.BrowserServer> => {
|
|
88
89
|
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
const opts = {
|
|
91
92
|
...options,
|
|
92
93
|
args: [
|
|
93
94
|
...(options.args || []),
|
|
94
95
|
this.userDataDir ? `-profile=${this.userDataDir}` : '',
|
|
95
96
|
],
|
|
96
97
|
executablePath: playwright.webkit.executablePath(),
|
|
97
|
-
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const versionedPw = await this.config.loadPwVersion(version!);
|
|
98
101
|
|
|
102
|
+
this.browser = await versionedPw.webkit.launchServer(opts);
|
|
99
103
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
100
104
|
|
|
101
105
|
this.logger.info(
|
package/src/config.ts
CHANGED
|
@@ -4,6 +4,7 @@ import debug from 'debug';
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { mkdir } from 'fs/promises';
|
|
6
6
|
import path from 'path';
|
|
7
|
+
import playwright from 'playwright-core';
|
|
7
8
|
import { tmpdir } from 'os';
|
|
8
9
|
|
|
9
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -165,6 +166,7 @@ export class Config extends EventEmitter {
|
|
|
165
166
|
protected rejectAlertURL = process.env.REJECT_ALERT_URL ?? null;
|
|
166
167
|
protected timeoutAlertURL = process.env.TIMEOUT_ALERT_URL ?? null;
|
|
167
168
|
protected errorAlertURL = process.env.ERROR_ALERT_URL ?? null;
|
|
169
|
+
protected pwVersions: { [key: string]: string } = {};
|
|
168
170
|
|
|
169
171
|
public getRoutes = (): string => this.routes;
|
|
170
172
|
public getHost = (): string => this.host;
|
|
@@ -172,6 +174,7 @@ export class Config extends EventEmitter {
|
|
|
172
174
|
public getIsWin = (): boolean => this.isWin;
|
|
173
175
|
public getToken = (): string | null => this.token;
|
|
174
176
|
public getDebug = (): string => this.debug;
|
|
177
|
+
public getPwVersions = () => this.pwVersions;
|
|
175
178
|
|
|
176
179
|
/**
|
|
177
180
|
* The maximum number of concurrent sessions allowed. Set
|
|
@@ -261,6 +264,23 @@ export class Config extends EventEmitter {
|
|
|
261
264
|
|
|
262
265
|
public getMetricsJSONPath = () => this.metricsJSONPath;
|
|
263
266
|
|
|
267
|
+
public setPwVersions = (versions: { [key: string]: string }) => {
|
|
268
|
+
this.pwVersions = versions;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
public loadPwVersion = async (
|
|
272
|
+
version: string,
|
|
273
|
+
): Promise<typeof playwright> => {
|
|
274
|
+
const versions = this.getPwVersions();
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
return await import(versions[version] || versions['default']);
|
|
278
|
+
} catch (err) {
|
|
279
|
+
debug.log('Error importing Playwright. Using default version', err);
|
|
280
|
+
return playwright;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
264
284
|
public setDataDir = async (newDataDir: string): Promise<string> => {
|
|
265
285
|
if (!(await exists(newDataDir))) {
|
|
266
286
|
throw new Error(
|
|
@@ -13,10 +13,6 @@ import { expect } from 'chai';
|
|
|
13
13
|
import puppeteer from 'puppeteer-core';
|
|
14
14
|
|
|
15
15
|
describe('Chrome WebSocket API', function () {
|
|
16
|
-
// Server shutdown can take a few seconds
|
|
17
|
-
// and so can these tests :/
|
|
18
|
-
this.timeout(10000);
|
|
19
|
-
|
|
20
16
|
let browserless: Browserless;
|
|
21
17
|
|
|
22
18
|
const start = ({
|
|
@@ -461,6 +457,31 @@ describe('Chrome WebSocket API', function () {
|
|
|
461
457
|
expect(results.queued).to.equal(0);
|
|
462
458
|
});
|
|
463
459
|
|
|
460
|
+
it('runs multiple versions of playwright', async () => {
|
|
461
|
+
const config = new Config();
|
|
462
|
+
config.setToken('browserless');
|
|
463
|
+
const metrics = new Metrics();
|
|
464
|
+
await start({ config, metrics });
|
|
465
|
+
|
|
466
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
467
|
+
|
|
468
|
+
for (const version of pwVersions) {
|
|
469
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
470
|
+
const browser = await pw.chromium.connect(
|
|
471
|
+
`ws://localhost:3000/chrome/playwright?token=browserless`,
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
await browser.close();
|
|
475
|
+
await sleep(100);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const results = metrics.get();
|
|
479
|
+
expect(results.timedout).to.equal(0);
|
|
480
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
481
|
+
expect(results.rejected).to.equal(0);
|
|
482
|
+
expect(results.queued).to.equal(0);
|
|
483
|
+
});
|
|
484
|
+
|
|
464
485
|
it('rejects playwright without tokens', async () => {
|
|
465
486
|
const config = new Config();
|
|
466
487
|
config.setToken('browserless');
|
|
@@ -461,6 +461,31 @@ describe('Chromium WebSocket API', function () {
|
|
|
461
461
|
expect(results.queued).to.equal(0);
|
|
462
462
|
});
|
|
463
463
|
|
|
464
|
+
it('runs multiple versions of playwright', async () => {
|
|
465
|
+
const config = new Config();
|
|
466
|
+
config.setToken('browserless');
|
|
467
|
+
const metrics = new Metrics();
|
|
468
|
+
await start({ config, metrics });
|
|
469
|
+
|
|
470
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
471
|
+
|
|
472
|
+
for (const version of pwVersions) {
|
|
473
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
474
|
+
const browser = await pw.chromium.connect(
|
|
475
|
+
`ws://localhost:3000/playwright/chromium?token=browserless`,
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
await browser.close();
|
|
479
|
+
await sleep(100);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const results = metrics.get();
|
|
483
|
+
expect(results.timedout).to.equal(0);
|
|
484
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
485
|
+
expect(results.rejected).to.equal(0);
|
|
486
|
+
expect(results.queued).to.equal(0);
|
|
487
|
+
});
|
|
488
|
+
|
|
464
489
|
it('rejects playwright without tokens', async () => {
|
|
465
490
|
const config = new Config();
|
|
466
491
|
config.setToken('browserless');
|
|
@@ -10,7 +10,6 @@ import { firefox } from 'playwright-core';
|
|
|
10
10
|
describe('Firefox Websocket API', function () {
|
|
11
11
|
// Server shutdown can take a few seconds
|
|
12
12
|
// and so can these tests :/
|
|
13
|
-
this.timeout(5000);
|
|
14
13
|
|
|
15
14
|
let browserless: Browserless;
|
|
16
15
|
|
|
@@ -39,6 +38,31 @@ describe('Firefox Websocket API', function () {
|
|
|
39
38
|
await browser.close();
|
|
40
39
|
});
|
|
41
40
|
|
|
41
|
+
it('runs multiple versions of playwright', async () => {
|
|
42
|
+
const config = new Config();
|
|
43
|
+
config.setToken('browserless');
|
|
44
|
+
const metrics = new Metrics();
|
|
45
|
+
await start({ config, metrics });
|
|
46
|
+
|
|
47
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
48
|
+
|
|
49
|
+
for (const version of pwVersions) {
|
|
50
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
51
|
+
const browser = await pw.firefox.connect(
|
|
52
|
+
`ws://localhost:3000/playwright/firefox?token=browserless`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
await browser.close();
|
|
56
|
+
await sleep(100);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const results = metrics.get();
|
|
60
|
+
expect(results.timedout).to.equal(0);
|
|
61
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
62
|
+
expect(results.rejected).to.equal(0);
|
|
63
|
+
expect(results.queued).to.equal(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
42
66
|
it('rejects playwright requests', async () => {
|
|
43
67
|
const config = new Config();
|
|
44
68
|
config.setToken('browserless');
|
|
@@ -39,6 +39,31 @@ describe('Webkit Websocket API', function () {
|
|
|
39
39
|
await browser.close();
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
it('runs multiple versions of playwright', async () => {
|
|
43
|
+
const config = new Config();
|
|
44
|
+
config.setToken('browserless');
|
|
45
|
+
const metrics = new Metrics();
|
|
46
|
+
await start({ config, metrics });
|
|
47
|
+
|
|
48
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
49
|
+
|
|
50
|
+
for (const version of pwVersions) {
|
|
51
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
52
|
+
const browser = await pw.webkit.connect(
|
|
53
|
+
`ws://localhost:3000/playwright/webkit?token=browserless`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
await browser.close();
|
|
57
|
+
await sleep(100);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const results = metrics.get();
|
|
61
|
+
expect(results.timedout).to.equal(0);
|
|
62
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
63
|
+
expect(results.rejected).to.equal(0);
|
|
64
|
+
expect(results.queued).to.equal(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
42
67
|
it('rejects playwright requests', async () => {
|
|
43
68
|
const config = new Config();
|
|
44
69
|
config.setToken('browserless');
|
package/src/types.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -48,6 +48,15 @@ const getAuthHeaderToken = (header: string) => {
|
|
|
48
48
|
return null;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* RegEx to match the Playwright version from the innitial request header.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const userAgent = "Playwright/1.43.1 (x64; windows 10.0) node/20.11";
|
|
56
|
+
* userAgent.match(pwVersionRegex);
|
|
57
|
+
* // ["Playwright/1.43", "1.43"]
|
|
58
|
+
*/
|
|
59
|
+
export const pwVersionRegex = /Playwright\/(\d+\.\d+)/;
|
|
51
60
|
export const buildDir: string = path.join(path.resolve(), 'build');
|
|
52
61
|
export const tsExtension = '.d.ts';
|
|
53
62
|
export const jsonExtension = '.json';
|
package/static/docs/swagger.json
CHANGED
|
@@ -225,14 +225,14 @@
|
|
|
225
225
|
"length": {
|
|
226
226
|
"type": "number"
|
|
227
227
|
},
|
|
228
|
-
"__@toStringTag@
|
|
228
|
+
"__@toStringTag@11009": {
|
|
229
229
|
"type": "string",
|
|
230
230
|
"const": "Uint8Array"
|
|
231
231
|
}
|
|
232
232
|
},
|
|
233
233
|
"required": [
|
|
234
234
|
"BYTES_PER_ELEMENT",
|
|
235
|
-
"__@toStringTag@
|
|
235
|
+
"__@toStringTag@11009",
|
|
236
236
|
"buffer",
|
|
237
237
|
"byteLength",
|
|
238
238
|
"byteOffset",
|
|
@@ -267,13 +267,13 @@
|
|
|
267
267
|
"byteLength": {
|
|
268
268
|
"type": "number"
|
|
269
269
|
},
|
|
270
|
-
"__@toStringTag@
|
|
270
|
+
"__@toStringTag@11009": {
|
|
271
271
|
"type": "string"
|
|
272
272
|
}
|
|
273
273
|
},
|
|
274
274
|
"additionalProperties": false,
|
|
275
275
|
"required": [
|
|
276
|
-
"__@toStringTag@
|
|
276
|
+
"__@toStringTag@11009",
|
|
277
277
|
"byteLength"
|
|
278
278
|
]
|
|
279
279
|
},
|
|
@@ -283,18 +283,18 @@
|
|
|
283
283
|
"byteLength": {
|
|
284
284
|
"type": "number"
|
|
285
285
|
},
|
|
286
|
-
"__@species@
|
|
286
|
+
"__@species@11110": {
|
|
287
287
|
"$ref": "#/definitions/SharedArrayBuffer"
|
|
288
288
|
},
|
|
289
|
-
"__@toStringTag@
|
|
289
|
+
"__@toStringTag@11009": {
|
|
290
290
|
"type": "string",
|
|
291
291
|
"const": "SharedArrayBuffer"
|
|
292
292
|
}
|
|
293
293
|
},
|
|
294
294
|
"additionalProperties": false,
|
|
295
295
|
"required": [
|
|
296
|
-
"__@species@
|
|
297
|
-
"__@toStringTag@
|
|
296
|
+
"__@species@11110",
|
|
297
|
+
"__@toStringTag@11009",
|
|
298
298
|
"byteLength"
|
|
299
299
|
]
|
|
300
300
|
},
|
|
@@ -1098,7 +1098,7 @@
|
|
|
1098
1098
|
},
|
|
1099
1099
|
"info": {
|
|
1100
1100
|
"title": "Browserless",
|
|
1101
|
-
"version": "2.12.0-beta-
|
|
1101
|
+
"version": "2.12.0-beta-4",
|
|
1102
1102
|
"x-logo": {
|
|
1103
1103
|
"altText": "browserless logo",
|
|
1104
1104
|
"url": "./docs/browserless-logo-inline.svg"
|
|
@@ -225,14 +225,14 @@
|
|
|
225
225
|
"length": {
|
|
226
226
|
"type": "number"
|
|
227
227
|
},
|
|
228
|
-
"__@toStringTag@
|
|
228
|
+
"__@toStringTag@11009": {
|
|
229
229
|
"type": "string",
|
|
230
230
|
"const": "Uint8Array"
|
|
231
231
|
}
|
|
232
232
|
},
|
|
233
233
|
"required": [
|
|
234
234
|
"BYTES_PER_ELEMENT",
|
|
235
|
-
"__@toStringTag@
|
|
235
|
+
"__@toStringTag@11009",
|
|
236
236
|
"buffer",
|
|
237
237
|
"byteLength",
|
|
238
238
|
"byteOffset",
|
|
@@ -267,13 +267,13 @@
|
|
|
267
267
|
"byteLength": {
|
|
268
268
|
"type": "number"
|
|
269
269
|
},
|
|
270
|
-
"__@toStringTag@
|
|
270
|
+
"__@toStringTag@11009": {
|
|
271
271
|
"type": "string"
|
|
272
272
|
}
|
|
273
273
|
},
|
|
274
274
|
"additionalProperties": false,
|
|
275
275
|
"required": [
|
|
276
|
-
"__@toStringTag@
|
|
276
|
+
"__@toStringTag@11009",
|
|
277
277
|
"byteLength"
|
|
278
278
|
]
|
|
279
279
|
},
|
|
@@ -283,18 +283,18 @@
|
|
|
283
283
|
"byteLength": {
|
|
284
284
|
"type": "number"
|
|
285
285
|
},
|
|
286
|
-
"__@species@
|
|
286
|
+
"__@species@11110": {
|
|
287
287
|
"$ref": "#/definitions/SharedArrayBuffer"
|
|
288
288
|
},
|
|
289
|
-
"__@toStringTag@
|
|
289
|
+
"__@toStringTag@11009": {
|
|
290
290
|
"type": "string",
|
|
291
291
|
"const": "SharedArrayBuffer"
|
|
292
292
|
}
|
|
293
293
|
},
|
|
294
294
|
"additionalProperties": false,
|
|
295
295
|
"required": [
|
|
296
|
-
"__@species@
|
|
297
|
-
"__@toStringTag@
|
|
296
|
+
"__@species@11110",
|
|
297
|
+
"__@toStringTag@11009",
|
|
298
298
|
"byteLength"
|
|
299
299
|
]
|
|
300
300
|
},
|
|
@@ -1098,7 +1098,7 @@
|
|
|
1098
1098
|
},
|
|
1099
1099
|
"info": {
|
|
1100
1100
|
"title": "Browserless",
|
|
1101
|
-
"version": "2.12.0-beta-
|
|
1101
|
+
"version": "2.12.0-beta-4",
|
|
1102
1102
|
"x-logo": {
|
|
1103
1103
|
"altText": "browserless logo",
|
|
1104
1104
|
"url": "./docs/browserless-logo-inline.svg"
|