@browserless.io/browserless 2.12.0-beta-2 → 2.12.0-beta-3
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.playwright.d.ts +1 -1
- package/build/browsers/chromium.playwright.js +5 -3
- package/build/browsers/firefox.playwright.d.ts +1 -1
- package/build/browsers/firefox.playwright.js +5 -3
- package/build/browsers/index.js +7 -2
- package/build/browsers/webkit.playwright.d.ts +1 -1
- package/build/browsers/webkit.playwright.js +4 -2
- 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/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/package.json +17 -5
- package/src/browserless.ts +11 -0
- package/src/browsers/chromium.playwright.ts +6 -2
- package/src/browsers/firefox.playwright.ts +7 -3
- package/src/browsers/index.ts +8 -1
- package/src/browsers/webkit.playwright.ts +5 -1
- 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 +27 -1
- package/src/routes/webkit/tests/websocket.spec.ts +26 -0
- 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
|
@@ -441,14 +441,14 @@
|
|
|
441
441
|
"length": {
|
|
442
442
|
"type": "number"
|
|
443
443
|
},
|
|
444
|
-
"__@toStringTag@
|
|
444
|
+
"__@toStringTag@219427": {
|
|
445
445
|
"type": "string",
|
|
446
446
|
"const": "Uint8Array"
|
|
447
447
|
}
|
|
448
448
|
},
|
|
449
449
|
"required": [
|
|
450
450
|
"BYTES_PER_ELEMENT",
|
|
451
|
-
"__@toStringTag@
|
|
451
|
+
"__@toStringTag@219427",
|
|
452
452
|
"buffer",
|
|
453
453
|
"byteLength",
|
|
454
454
|
"byteOffset",
|
|
@@ -483,13 +483,13 @@
|
|
|
483
483
|
"byteLength": {
|
|
484
484
|
"type": "number"
|
|
485
485
|
},
|
|
486
|
-
"__@toStringTag@
|
|
486
|
+
"__@toStringTag@219427": {
|
|
487
487
|
"type": "string"
|
|
488
488
|
}
|
|
489
489
|
},
|
|
490
490
|
"additionalProperties": false,
|
|
491
491
|
"required": [
|
|
492
|
-
"__@toStringTag@
|
|
492
|
+
"__@toStringTag@219427",
|
|
493
493
|
"byteLength"
|
|
494
494
|
]
|
|
495
495
|
},
|
|
@@ -499,18 +499,18 @@
|
|
|
499
499
|
"byteLength": {
|
|
500
500
|
"type": "number"
|
|
501
501
|
},
|
|
502
|
-
"__@species@
|
|
502
|
+
"__@species@219528": {
|
|
503
503
|
"$ref": "#/definitions/SharedArrayBuffer"
|
|
504
504
|
},
|
|
505
|
-
"__@toStringTag@
|
|
505
|
+
"__@toStringTag@219427": {
|
|
506
506
|
"type": "string",
|
|
507
507
|
"const": "SharedArrayBuffer"
|
|
508
508
|
}
|
|
509
509
|
},
|
|
510
510
|
"additionalProperties": false,
|
|
511
511
|
"required": [
|
|
512
|
-
"__@species@
|
|
513
|
-
"__@toStringTag@
|
|
512
|
+
"__@species@219528",
|
|
513
|
+
"__@toStringTag@219427",
|
|
514
514
|
"byteLength"
|
|
515
515
|
]
|
|
516
516
|
},
|
|
@@ -484,14 +484,14 @@
|
|
|
484
484
|
"length": {
|
|
485
485
|
"type": "number"
|
|
486
486
|
},
|
|
487
|
-
"__@toStringTag@
|
|
487
|
+
"__@toStringTag@241842": {
|
|
488
488
|
"type": "string",
|
|
489
489
|
"const": "Uint8Array"
|
|
490
490
|
}
|
|
491
491
|
},
|
|
492
492
|
"required": [
|
|
493
493
|
"BYTES_PER_ELEMENT",
|
|
494
|
-
"__@toStringTag@
|
|
494
|
+
"__@toStringTag@241842",
|
|
495
495
|
"buffer",
|
|
496
496
|
"byteLength",
|
|
497
497
|
"byteOffset",
|
|
@@ -526,13 +526,13 @@
|
|
|
526
526
|
"byteLength": {
|
|
527
527
|
"type": "number"
|
|
528
528
|
},
|
|
529
|
-
"__@toStringTag@
|
|
529
|
+
"__@toStringTag@241842": {
|
|
530
530
|
"type": "string"
|
|
531
531
|
}
|
|
532
532
|
},
|
|
533
533
|
"additionalProperties": false,
|
|
534
534
|
"required": [
|
|
535
|
-
"__@toStringTag@
|
|
535
|
+
"__@toStringTag@241842",
|
|
536
536
|
"byteLength"
|
|
537
537
|
]
|
|
538
538
|
},
|
|
@@ -542,18 +542,18 @@
|
|
|
542
542
|
"byteLength": {
|
|
543
543
|
"type": "number"
|
|
544
544
|
},
|
|
545
|
-
"__@species@
|
|
545
|
+
"__@species@241943": {
|
|
546
546
|
"$ref": "#/definitions/SharedArrayBuffer"
|
|
547
547
|
},
|
|
548
|
-
"__@toStringTag@
|
|
548
|
+
"__@toStringTag@241842": {
|
|
549
549
|
"type": "string",
|
|
550
550
|
"const": "SharedArrayBuffer"
|
|
551
551
|
}
|
|
552
552
|
},
|
|
553
553
|
"additionalProperties": false,
|
|
554
554
|
"required": [
|
|
555
|
-
"__@species@
|
|
556
|
-
"__@toStringTag@
|
|
555
|
+
"__@species@241943",
|
|
556
|
+
"__@toStringTag@241842",
|
|
557
557
|
"byteLength"
|
|
558
558
|
]
|
|
559
559
|
},
|
|
@@ -345,6 +345,24 @@ describe('Chromium WebSocket API', function () {
|
|
|
345
345
|
expect(results.rejected).to.equal(0);
|
|
346
346
|
expect(results.queued).to.equal(0);
|
|
347
347
|
});
|
|
348
|
+
it('runs multiple versions of playwright', async () => {
|
|
349
|
+
const config = new Config();
|
|
350
|
+
config.setToken('browserless');
|
|
351
|
+
const metrics = new Metrics();
|
|
352
|
+
await start({ config, metrics });
|
|
353
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
354
|
+
for (const version of pwVersions) {
|
|
355
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
356
|
+
const browser = await pw.chromium.connect(`ws://localhost:3000/playwright/chromium?token=browserless`);
|
|
357
|
+
await browser.close();
|
|
358
|
+
await sleep(100);
|
|
359
|
+
}
|
|
360
|
+
const results = metrics.get();
|
|
361
|
+
expect(results.timedout).to.equal(0);
|
|
362
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
363
|
+
expect(results.rejected).to.equal(0);
|
|
364
|
+
expect(results.queued).to.equal(0);
|
|
365
|
+
});
|
|
348
366
|
it('rejects playwright without tokens', async () => {
|
|
349
367
|
const config = new Config();
|
|
350
368
|
config.setToken('browserless');
|
|
@@ -4,7 +4,6 @@ import { firefox } from 'playwright-core';
|
|
|
4
4
|
describe('Firefox Websocket API', function () {
|
|
5
5
|
// Server shutdown can take a few seconds
|
|
6
6
|
// and so can these tests :/
|
|
7
|
-
this.timeout(5000);
|
|
8
7
|
let browserless;
|
|
9
8
|
const start = ({ config = new Config(), metrics = new Metrics(), } = {}) => {
|
|
10
9
|
browserless = new Browserless({ config, metrics });
|
|
@@ -21,6 +20,24 @@ describe('Firefox Websocket API', function () {
|
|
|
21
20
|
const browser = await firefox.connect(`ws://localhost:3000/playwright/firefox?token=browserless`);
|
|
22
21
|
await browser.close();
|
|
23
22
|
});
|
|
23
|
+
it('runs multiple versions of playwright', async () => {
|
|
24
|
+
const config = new Config();
|
|
25
|
+
config.setToken('browserless');
|
|
26
|
+
const metrics = new Metrics();
|
|
27
|
+
await start({ config, metrics });
|
|
28
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
29
|
+
for (const version of pwVersions) {
|
|
30
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
31
|
+
const browser = await pw.firefox.connect(`ws://localhost:3000/playwright/firefox?token=browserless`);
|
|
32
|
+
await browser.close();
|
|
33
|
+
await sleep(100);
|
|
34
|
+
}
|
|
35
|
+
const results = metrics.get();
|
|
36
|
+
expect(results.timedout).to.equal(0);
|
|
37
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
38
|
+
expect(results.rejected).to.equal(0);
|
|
39
|
+
expect(results.queued).to.equal(0);
|
|
40
|
+
});
|
|
24
41
|
it('rejects playwright requests', async () => {
|
|
25
42
|
const config = new Config();
|
|
26
43
|
config.setToken('browserless');
|
|
@@ -21,6 +21,24 @@ describe('Webkit Websocket API', function () {
|
|
|
21
21
|
const browser = await webkit.connect(`ws://localhost:3000/playwright/webkit?token=browserless`);
|
|
22
22
|
await browser.close();
|
|
23
23
|
});
|
|
24
|
+
it('runs multiple versions of playwright', async () => {
|
|
25
|
+
const config = new Config();
|
|
26
|
+
config.setToken('browserless');
|
|
27
|
+
const metrics = new Metrics();
|
|
28
|
+
await start({ config, metrics });
|
|
29
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
30
|
+
for (const version of pwVersions) {
|
|
31
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
32
|
+
const browser = await pw.webkit.connect(`ws://localhost:3000/playwright/webkit?token=browserless`);
|
|
33
|
+
await browser.close();
|
|
34
|
+
await sleep(100);
|
|
35
|
+
}
|
|
36
|
+
const results = metrics.get();
|
|
37
|
+
expect(results.timedout).to.equal(0);
|
|
38
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
39
|
+
expect(results.rejected).to.equal(0);
|
|
40
|
+
expect(results.queued).to.equal(0);
|
|
41
|
+
});
|
|
24
42
|
it('rejects playwright requests', async () => {
|
|
25
43
|
const config = new Config();
|
|
26
44
|
config.setToken('browserless');
|
package/build/utils.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ import { Duplex } from 'stream';
|
|
|
7
7
|
import { Page } from 'puppeteer-core';
|
|
8
8
|
import { ServerResponse } from 'http';
|
|
9
9
|
import debug from 'debug';
|
|
10
|
+
/**
|
|
11
|
+
* RegEx to match the Playwright version from the innitial request header.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const userAgent = "Playwright/1.43.1 (x64; windows 10.0) node/20.11";
|
|
15
|
+
* userAgent.match(pwVersionRegex);
|
|
16
|
+
* // ["Playwright/1.43", "1.43"]
|
|
17
|
+
*/
|
|
18
|
+
export declare const pwVersionRegex: RegExp;
|
|
10
19
|
export declare const buildDir: string;
|
|
11
20
|
export declare const tsExtension = ".d.ts";
|
|
12
21
|
export declare const jsonExtension = ".json";
|
package/build/utils.js
CHANGED
|
@@ -21,6 +21,15 @@ const getAuthHeaderToken = (header) => {
|
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* RegEx to match the Playwright version from the innitial request header.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const userAgent = "Playwright/1.43.1 (x64; windows 10.0) node/20.11";
|
|
29
|
+
* userAgent.match(pwVersionRegex);
|
|
30
|
+
* // ["Playwright/1.43", "1.43"]
|
|
31
|
+
*/
|
|
32
|
+
export const pwVersionRegex = /Playwright\/(\d+\.\d+)/;
|
|
24
33
|
export const buildDir = path.join(path.resolve(), 'build');
|
|
25
34
|
export const tsExtension = '.d.ts';
|
|
26
35
|
export const jsonExtension = '.json';
|
|
@@ -26,7 +26,8 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
|
|
|
26
26
|
fonts-ubuntu \
|
|
27
27
|
fonts-wqy-zenhei
|
|
28
28
|
|
|
29
|
-
RUN
|
|
29
|
+
RUN npx --yes playwright install chromium &&\
|
|
30
|
+
npx --yes playwright install-deps chromium &&\
|
|
30
31
|
npm run build &&\
|
|
31
32
|
npm run build:function &&\
|
|
32
33
|
npm prune production &&\
|
|
@@ -26,7 +26,8 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
|
|
|
26
26
|
fonts-ubuntu \
|
|
27
27
|
fonts-wqy-zenhei
|
|
28
28
|
|
|
29
|
-
RUN
|
|
29
|
+
RUN npx --yes playwright install firefox &&\
|
|
30
|
+
npx --yes playwright install-deps firefox &&\
|
|
30
31
|
npm run build &&\
|
|
31
32
|
npm prune production &&\
|
|
32
33
|
chown -R blessuser:blessuser $APP_DIR &&\
|
package/docker/multi/Dockerfile
CHANGED
|
@@ -34,7 +34,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
|
|
34
34
|
rm -rf ./src/routes/chrome; \
|
|
35
35
|
fi
|
|
36
36
|
|
|
37
|
-
RUN
|
|
37
|
+
RUN npx --yes playwright install --with-deps chromium firefox webkit &&\
|
|
38
38
|
npm run build &&\
|
|
39
39
|
npm run build:function &&\
|
|
40
40
|
npm prune production &&\
|
package/docker/webkit/Dockerfile
CHANGED
|
@@ -27,7 +27,8 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
|
|
|
27
27
|
fonts-ubuntu \
|
|
28
28
|
fonts-wqy-zenhei
|
|
29
29
|
|
|
30
|
-
RUN
|
|
30
|
+
RUN npx --yes playwright install webkit &&\
|
|
31
|
+
npx --yes playwright install-deps webkit &&\
|
|
31
32
|
npm run build &&\
|
|
32
33
|
npm prune production &&\
|
|
33
34
|
chown -R blessuser:blessuser $APP_DIR &&\
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browserless.io/browserless",
|
|
3
|
-
"version": "2.12.0-beta-
|
|
3
|
+
"version": "2.12.0-beta-3",
|
|
4
4
|
"license": "SSPL",
|
|
5
5
|
"description": "The browserless platform",
|
|
6
6
|
"author": "browserless.io",
|
|
@@ -58,8 +58,12 @@
|
|
|
58
58
|
"http-proxy": "^1.18.1",
|
|
59
59
|
"lighthouse": "^12.0.0",
|
|
60
60
|
"micromatch": "^4.0.4",
|
|
61
|
-
"playwright-
|
|
62
|
-
"
|
|
61
|
+
"playwright-1.40": "npm:playwright-core@1.40.1",
|
|
62
|
+
"playwright-1.41": "npm:playwright-core@1.41.2",
|
|
63
|
+
"playwright-1.42": "npm:playwright-core@1.42.1",
|
|
64
|
+
"playwright-1.43": "npm:playwright-core@1.43.1",
|
|
65
|
+
"playwright-core": "^1.44.0",
|
|
66
|
+
"puppeteer-core": "^22.9.0",
|
|
63
67
|
"puppeteer-extra": "^3.3.6",
|
|
64
68
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
65
69
|
"queue": "^7.0.0",
|
|
@@ -81,7 +85,7 @@
|
|
|
81
85
|
"chai": "^5.1.1",
|
|
82
86
|
"cross-env": "^7.0.3",
|
|
83
87
|
"env-cmd": "^10.1.0",
|
|
84
|
-
"esbuild": "^0.21.
|
|
88
|
+
"esbuild": "^0.21.3",
|
|
85
89
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
86
90
|
"eslint": "^8.57.0",
|
|
87
91
|
"eslint-plugin-typescript-sort-keys": "^3.2.0",
|
|
@@ -91,11 +95,19 @@
|
|
|
91
95
|
"mocha": "^10.4.0",
|
|
92
96
|
"move-file": "^3.1.0",
|
|
93
97
|
"prettier": "^3.2.5",
|
|
94
|
-
"sinon": "^
|
|
98
|
+
"sinon": "^18.0.0",
|
|
95
99
|
"ts-node": "^10.9.2",
|
|
96
100
|
"typescript": "^5.4.5",
|
|
97
101
|
"typescript-json-schema": "^0.63.0"
|
|
98
102
|
},
|
|
103
|
+
"playwrightVersions": {
|
|
104
|
+
"default": "playwright-core",
|
|
105
|
+
"1.44": "playwright-core",
|
|
106
|
+
"1.43": "playwright-1.43",
|
|
107
|
+
"1.42": "playwright-1.42",
|
|
108
|
+
"1.41": "playwright-1.41",
|
|
109
|
+
"1.40": "playwright-1.40"
|
|
110
|
+
},
|
|
99
111
|
"eslintConfig": {
|
|
100
112
|
"root": true,
|
|
101
113
|
"parser": "@typescript-eslint/parser",
|
package/src/browserless.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
1
2
|
import * as path from 'path';
|
|
3
|
+
|
|
2
4
|
import {
|
|
3
5
|
Logger as BlessLogger,
|
|
4
6
|
BrowserHTTPRoute,
|
|
@@ -117,6 +119,14 @@ export class Browserless extends EventEmitter {
|
|
|
117
119
|
new Router(this.config, this.browserManager, this.limiter, this.Logger);
|
|
118
120
|
}
|
|
119
121
|
|
|
122
|
+
protected loadPwVersions = async (): Promise<void> => {
|
|
123
|
+
const { playwrightVersions } = JSON.parse(
|
|
124
|
+
(await fs.readFile('package.json')).toString(),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
this.config.setPwVersions(playwrightVersions);
|
|
128
|
+
};
|
|
129
|
+
|
|
120
130
|
protected saveMetrics = async (): Promise<void> => {
|
|
121
131
|
const metricsPath = this.config.getMetricsJSONPath();
|
|
122
132
|
const { cpu, memory } = await this.monitoring.getMachineStats();
|
|
@@ -382,6 +392,7 @@ export class Browserless extends EventEmitter {
|
|
|
382
392
|
this.Logger,
|
|
383
393
|
);
|
|
384
394
|
|
|
395
|
+
await this.loadPwVersions();
|
|
385
396
|
await this.server.start();
|
|
386
397
|
this.logger.info(`Starting metrics collection.`);
|
|
387
398
|
this.metricsSaveIntervalID = setInterval(
|
|
@@ -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(
|
|
@@ -84,18 +84,22 @@ 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
|
-
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
89
89
|
|
|
90
|
-
this.
|
|
90
|
+
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
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.firefox.executablePath(),
|
|
97
|
-
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const versionedPw = await this.config.loadPwVersion(version!);
|
|
98
101
|
|
|
102
|
+
this.browser = await versionedPw.firefox.launchServer(opts);
|
|
99
103
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
100
104
|
|
|
101
105
|
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';
|
|
@@ -436,6 +437,9 @@ export class BrowserManager {
|
|
|
436
437
|
arg.includes('--proxy-server='),
|
|
437
438
|
);
|
|
438
439
|
|
|
440
|
+
/**
|
|
441
|
+
* If it is a playwright request
|
|
442
|
+
*/
|
|
439
443
|
if (
|
|
440
444
|
launchOptions.args &&
|
|
441
445
|
proxyServerArg &&
|
|
@@ -471,7 +475,10 @@ export class BrowserManager {
|
|
|
471
475
|
|
|
472
476
|
this.browsers.set(browser, session);
|
|
473
477
|
|
|
474
|
-
|
|
478
|
+
const match = (req.headers['user-agent'] || '').match(pwVersionRegex);
|
|
479
|
+
const pwVersion = match ? match[1] : 'default';
|
|
480
|
+
|
|
481
|
+
await browser.launch(launchOptions as object, pwVersion);
|
|
475
482
|
await this.hooks.browser({ browser, meta: req.parsed });
|
|
476
483
|
|
|
477
484
|
browser.on('newPage', async (page) => {
|
|
@@ -84,10 +84,11 @@ 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 || []),
|
|
@@ -96,6 +97,9 @@ export class WebkitPlaywright extends EventEmitter {
|
|
|
96
97
|
executablePath: playwright.webkit.executablePath(),
|
|
97
98
|
});
|
|
98
99
|
|
|
100
|
+
const versionedPw = await this.config.loadPwVersion(version!);
|
|
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,33 @@ describe('Firefox Websocket API', function () {
|
|
|
39
38
|
await browser.close();
|
|
40
39
|
});
|
|
41
40
|
|
|
41
|
+
|
|
42
|
+
it('runs multiple versions of playwright', async () => {
|
|
43
|
+
|
|
44
|
+
const config = new Config();
|
|
45
|
+
config.setToken('browserless');
|
|
46
|
+
const metrics = new Metrics();
|
|
47
|
+
await start({ config, metrics });
|
|
48
|
+
|
|
49
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
50
|
+
|
|
51
|
+
for (const version of pwVersions) {
|
|
52
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
53
|
+
const browser = await pw.firefox.connect(
|
|
54
|
+
`ws://localhost:3000/playwright/firefox?token=browserless`,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await browser.close();
|
|
58
|
+
await sleep(100);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const results = metrics.get();
|
|
62
|
+
expect(results.timedout).to.equal(0);
|
|
63
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
64
|
+
expect(results.rejected).to.equal(0);
|
|
65
|
+
expect(results.queued).to.equal(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
42
68
|
it('rejects playwright requests', async () => {
|
|
43
69
|
const config = new Config();
|
|
44
70
|
config.setToken('browserless');
|
|
@@ -39,6 +39,32 @@ describe('Webkit Websocket API', function () {
|
|
|
39
39
|
await browser.close();
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
|
|
43
|
+
it('runs multiple versions of playwright', async () => {
|
|
44
|
+
const config = new Config();
|
|
45
|
+
config.setToken('browserless');
|
|
46
|
+
const metrics = new Metrics();
|
|
47
|
+
await start({ config, metrics });
|
|
48
|
+
|
|
49
|
+
const pwVersions = Object.keys(config.getPwVersions());
|
|
50
|
+
|
|
51
|
+
for (const version of pwVersions) {
|
|
52
|
+
const pw = await import(config.getPwVersions()[version]);
|
|
53
|
+
const browser = await pw.webkit.connect(
|
|
54
|
+
`ws://localhost:3000/playwright/webkit?token=browserless`,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await browser.close();
|
|
58
|
+
await sleep(100);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const results = metrics.get();
|
|
62
|
+
expect(results.timedout).to.equal(0);
|
|
63
|
+
expect(results.successful).to.equal(pwVersions.length);
|
|
64
|
+
expect(results.rejected).to.equal(0);
|
|
65
|
+
expect(results.queued).to.equal(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
42
68
|
it('rejects playwright requests', async () => {
|
|
43
69
|
const config = new Config();
|
|
44
70
|
config.setToken('browserless');
|