@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.
Files changed (45) hide show
  1. package/build/browserless.d.ts +1 -0
  2. package/build/browserless.js +6 -0
  3. package/build/browsers/chromium.playwright.d.ts +1 -1
  4. package/build/browsers/chromium.playwright.js +5 -3
  5. package/build/browsers/firefox.playwright.d.ts +1 -1
  6. package/build/browsers/firefox.playwright.js +5 -3
  7. package/build/browsers/index.js +7 -2
  8. package/build/browsers/webkit.playwright.d.ts +1 -1
  9. package/build/browsers/webkit.playwright.js +4 -2
  10. package/build/config.d.ts +11 -0
  11. package/build/config.js +16 -0
  12. package/build/routes/chrome/http/content.post.body.json +8 -8
  13. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  14. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  15. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  16. package/build/routes/chrome/tests/websocket.spec.js +18 -3
  17. package/build/routes/chromium/http/content.post.body.json +8 -8
  18. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  19. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  20. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  21. package/build/routes/chromium/tests/websocket.spec.js +18 -0
  22. package/build/routes/firefox/tests/websocket.spec.js +18 -1
  23. package/build/routes/webkit/tests/websocket.spec.js +18 -0
  24. package/build/utils.d.ts +9 -0
  25. package/build/utils.js +9 -0
  26. package/docker/chromium/Dockerfile +2 -1
  27. package/docker/firefox/Dockerfile +2 -1
  28. package/docker/multi/Dockerfile +1 -1
  29. package/docker/webkit/Dockerfile +2 -1
  30. package/package.json +17 -5
  31. package/src/browserless.ts +11 -0
  32. package/src/browsers/chromium.playwright.ts +6 -2
  33. package/src/browsers/firefox.playwright.ts +7 -3
  34. package/src/browsers/index.ts +8 -1
  35. package/src/browsers/webkit.playwright.ts +5 -1
  36. package/src/config.ts +20 -0
  37. package/src/routes/chrome/tests/websocket.spec.ts +25 -4
  38. package/src/routes/chromium/tests/websocket.spec.ts +25 -0
  39. package/src/routes/firefox/tests/websocket.spec.ts +27 -1
  40. package/src/routes/webkit/tests/websocket.spec.ts +26 -0
  41. package/src/utils.ts +9 -0
  42. package/static/docs/swagger.json +9 -9
  43. package/static/docs/swagger.min.json +9 -9
  44. package/static/function/client.js +95 -136
  45. package/static/function/index.html +95 -136
@@ -441,14 +441,14 @@
441
441
  "length": {
442
442
  "type": "number"
443
443
  },
444
- "__@toStringTag@240522": {
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@240522",
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@240522": {
486
+ "__@toStringTag@219427": {
487
487
  "type": "string"
488
488
  }
489
489
  },
490
490
  "additionalProperties": false,
491
491
  "required": [
492
- "__@toStringTag@240522",
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@240623": {
502
+ "__@species@219528": {
503
503
  "$ref": "#/definitions/SharedArrayBuffer"
504
504
  },
505
- "__@toStringTag@240522": {
505
+ "__@toStringTag@219427": {
506
506
  "type": "string",
507
507
  "const": "SharedArrayBuffer"
508
508
  }
509
509
  },
510
510
  "additionalProperties": false,
511
511
  "required": [
512
- "__@species@240623",
513
- "__@toStringTag@240522",
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@229416": {
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@229416",
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@229416": {
529
+ "__@toStringTag@241842": {
530
530
  "type": "string"
531
531
  }
532
532
  },
533
533
  "additionalProperties": false,
534
534
  "required": [
535
- "__@toStringTag@229416",
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@229517": {
545
+ "__@species@241943": {
546
546
  "$ref": "#/definitions/SharedArrayBuffer"
547
547
  },
548
- "__@toStringTag@229416": {
548
+ "__@toStringTag@241842": {
549
549
  "type": "string",
550
550
  "const": "SharedArrayBuffer"
551
551
  }
552
552
  },
553
553
  "additionalProperties": false,
554
554
  "required": [
555
- "__@species@229517",
556
- "__@toStringTag@229416",
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 ./node_modules/.bin/playwright-core install --with-deps chromium &&\
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 ./node_modules/.bin/playwright-core install --with-deps firefox &&\
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 &&\
@@ -34,7 +34,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
34
34
  rm -rf ./src/routes/chrome; \
35
35
  fi
36
36
 
37
- RUN ./node_modules/.bin/playwright-core install --with-deps chromium firefox webkit &&\
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 &&\
@@ -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 ./node_modules/.bin/playwright-core install --with-deps webkit &&\
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-2",
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-core": "^1.43.0",
62
- "puppeteer-core": "^22.8.1",
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.2",
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": "^17.0.2",
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",
@@ -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
- this.browser = await playwright.chromium.launchServer({
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.browser = await playwright.firefox.launchServer({
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(
@@ -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
- await browser.launch(launchOptions as object);
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
- this.browser = await playwright.webkit.launchServer({
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');