@eyeo/get-browser-binary 0.9.0 → 0.10.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/.gitlab-ci.yml CHANGED
@@ -51,15 +51,13 @@ test:browsers:windows:
51
51
  - choco upgrade -y nodejs --version 16.10.0
52
52
  - npm install
53
53
  script:
54
+ # Running Edge tests only on the preinstalled version
55
+ # https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/29
56
+ - npm test -- --grep "edge.*latest"
57
+ - npm test -- --grep "chromium"
54
58
  # Running only a subset of Firefox tests to avoid low OS resources error
55
59
  # https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/2
56
60
  - npm test -- --grep "firefox.*installs"
57
- # Running npm v8 on powershell has issues when the grep value contains the
58
- # pipe (|) literal. Storing that string as a verbatim string (single quotes)
59
- # and then sorrounding it with four double quotes does the trick.
60
- # https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/29
61
- - $full_tests = '(chromium|edge.*latest)'
62
- - npm test -- --grep """"$full_tests""""
63
61
  tags:
64
62
  - shared-windows
65
63
  - windows
package/RELEASE_NOTES.md CHANGED
@@ -1,3 +1,13 @@
1
+ # 0.10.0
2
+
3
+ - Added handling of the new headless mode in Chromium (#45)
4
+ - Fixed an issue that prevented Chromium to be installed on macOS ARM processors
5
+ (!59)
6
+ - Changed documentation nullable parameters to optional parameters (#41)
7
+ - Increased the npm geckodriver version to 3.1.0 (!57)
8
+ - Fixed an issue with Windows Edge and msedgedriver, which occasionally failed
9
+ when building the driver (!56)
10
+
1
11
  # 0.9.0
2
12
 
3
13
  - Fixed a Chromium install issue by increasing the value of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eyeo/get-browser-binary",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Install browser binaries and matching webdrivers",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,17 +30,17 @@
30
30
  "dependencies": {
31
31
  "dmg": "^0.1.0",
32
32
  "extract-zip": "^2.0.1",
33
- "geckodriver": "^3.0.2",
34
- "got": "^11.8.2",
35
- "jimp": "^0.16.2",
36
- "selenium-webdriver": "^4.7.1"
33
+ "geckodriver": "3.1.0",
34
+ "got": "^12.5.3",
35
+ "jimp": "^0.22.4",
36
+ "selenium-webdriver": "^4.8.0"
37
37
  },
38
38
  "devDependencies": {
39
- "eslint": "^8.17.0",
39
+ "eslint": "^8.33.0",
40
40
  "eslint-config-eyeo": "^3.2.0",
41
- "expect": "^25.5.0",
42
- "jsdoc": "^3.6.10",
43
- "mocha": "^10.0.0"
41
+ "expect": "^29.4.2",
42
+ "jsdoc": "^4.0.0",
43
+ "mocha": "^10.2.0"
44
44
  },
45
45
  "scripts": {
46
46
  "docs": "jsdoc --readme README.md --destination docs src/*.js",
package/src/browsers.js CHANGED
@@ -25,7 +25,6 @@ import webdriver from "selenium-webdriver";
25
25
  import chrome from "selenium-webdriver/chrome.js";
26
26
  import firefox from "selenium-webdriver/firefox.js";
27
27
  import edge from "selenium-webdriver/edge.js";
28
- import command from "selenium-webdriver/lib/command.js";
29
28
  import extractZip from "extract-zip";
30
29
 
31
30
  import {download, extractTar, extractDmg, killDriverProcess, wait}
@@ -50,12 +49,19 @@ const BROWSER_DOWNLOAD_ERROR = "Browser download failed";
50
49
  const BROWSER_NOT_INSTALLED_ERROR = "Browser is not installed";
51
50
  const ELEMENT_NOT_FOUND_ERROR = "HTML element not found";
52
51
 
52
+ function getMajorVersion(versionNumber) {
53
+ let majorVersion = parseInt(versionNumber && versionNumber.split(".")[0], 10);
54
+ if (isNaN(majorVersion))
55
+ throw new Error(`${UNSUPPORTED_VERSION_ERROR}: ${versionNumber}`);
56
+
57
+ return majorVersion;
58
+ }
59
+
53
60
  function checkVersion(version, minVersion, channels = []) {
54
61
  if (channels.includes(version))
55
62
  return;
56
63
 
57
- let mainVersion = parseInt(version && version.split(".")[0], 10);
58
- if (isNaN(mainVersion) || mainVersion < minVersion)
64
+ if (getMajorVersion(version) < minVersion)
59
65
  throw new Error(`${UNSUPPORTED_VERSION_ERROR}: ${version}`);
60
66
  }
61
67
 
@@ -72,19 +78,17 @@ function checkPlatform() {
72
78
  class Browser {
73
79
  /**
74
80
  * @typedef {Object} BrowserBinary
75
- * @property {string} binary - The path to the browser binary.
76
- * @property {string} versionNumber - The version number of the browser
77
- * binary.
81
+ * @property {string} binary The path to the browser binary.
82
+ * @property {string} versionNumber The version number of the browser binary.
78
83
  */
79
84
 
80
85
  /**
81
86
  * Installs the browser. The installation process is detailed on the
82
87
  * subclasses.
83
- * @param {string} version - Either full version number or channel/release.
84
- * Please find examples on the subclasses.
85
- * @param {number?} downloadTimeout - Allowed time in ms for the download of
86
- * install files to complete. When set to 0 there is no time limit. Defaults
87
- * to 0.
88
+ * @param {string} [version=latest] Either full version number or
89
+ * channel/release. Please find examples on the subclasses.
90
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
91
+ * install files to complete. When set to 0 there is no time limit.
88
92
  * @return {BrowserBinary}
89
93
  * @throws {Error} Unsupported browser version, Unsupported platform, Browser
90
94
  * download failed.
@@ -95,7 +99,7 @@ class Browser {
95
99
 
96
100
  /**
97
101
  * Gets the installed version returned by the browser binary.
98
- * @param {string} binary - The path to the browser binary.
102
+ * @param {string} binary The path to the browser binary.
99
103
  * @return {string} Installed browser version.
100
104
  */
101
105
  static async getInstalledVersion(binary) {
@@ -119,27 +123,28 @@ class Browser {
119
123
 
120
124
  /**
121
125
  * @typedef {Object} driverOptions
122
- * @property {boolean} headless=true - Run the browser in headless mode,
123
- * or not.
124
- * @property {Array.<string>} [extensionPaths=[]] - Loads extensions to the
126
+ * @property {boolean} [headless=true] Run the browser in headless mode,
127
+ * or not. In Chromium >= 111, the
128
+ * {@link https://developer.chrome.com/articles/new-headless/ new headless mode}
129
+ * is used.
130
+ * @property {Array.<string>} [extensionPaths=[]] Loads extensions to the
125
131
  * browser.
126
- * @property {boolean} incognito=false - Runs the browser in incognito mode,
132
+ * @property {boolean} [incognito=false] Runs the browser in incognito mode,
127
133
  * or not.
128
- * @property {boolean} insecure=false - Forces the browser to accept insecure
134
+ * @property {boolean} [insecure=false] Forces the browser to accept insecure
129
135
  * certificates, or not.
130
- * @property {Array.<string>} [extraArgs=[]] - Additional arguments to start
136
+ * @property {Array.<string>} [extraArgs=[]] Additional arguments to start
131
137
  * the browser with.
132
138
  */
133
139
 
134
140
  /**
135
141
  * Installs the webdriver matching the browser version and runs the
136
142
  * browser. If needed, the browser binary is also installed.
137
- * @param {string} version - Either full version number or channel/release.
138
- * Please find examples on the subclasses.
139
- * @param {driverOptions?} options - Options to start the browser with.
140
- * @param {number?} downloadTimeout - Allowed time in ms for the download of
143
+ * @param {string} [version=latest] Either full version number or
144
+ * channel/release. Please find examples on the subclasses.
145
+ * @param {driverOptions} [options={}] Options to start the browser with.
146
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
141
147
  * browser install files to complete. When set to 0 there is no time limit.
142
- * Defaults to 0.
143
148
  * @return {webdriver}
144
149
  * @throws {Error} Unsupported browser version, Unsupported platform, Browser
145
150
  * download failed, Driver download failed, Unable to start driver.
@@ -151,8 +156,8 @@ class Browser {
151
156
  /**
152
157
  * By default, extensions are disabled in incognito mode. This function
153
158
  * enables the extension when loaded in incognito.
154
- * @param {webdriver} driver - The driver controlling the browser.
155
- * @param {string} extensionTitle - Title of the extebsion to be enabled.
159
+ * @param {webdriver} driver The driver controlling the browser.
160
+ * @param {string} extensionTitle Title of the extension to be enabled.
156
161
  * @return {webdriver}
157
162
  * @throws {Error} Unsupported browser version, Extension not found, HTML
158
163
  * element not found.
@@ -185,7 +190,7 @@ class Chromium extends Browser {
185
190
  "win32-x64": "win64",
186
191
  "linux-x64": "linux",
187
192
  "darwin-x64": "mac",
188
- "dawrin-arm64": "mac_arm64"
193
+ "darwin-arm64": "mac_arm64"
189
194
  }[platformArch];
190
195
  let data = await got(`https://omahaproxy.appspot.com/all.json?os=${os}`).json();
191
196
  let release = data[0].versions.find(ver => ver.channel == channel);
@@ -212,11 +217,10 @@ class Chromium extends Browser {
212
217
  /**
213
218
  * Installs the browser. The Chromium executable gets extracted in the
214
219
  * {@link snapshotsBaseDir} folder, ready to go.
215
- * @param {string} version - Either "latest", "beta", "dev" or a full version
216
- * number (i.e. "77.0.3865.0"). Defaults to "latest".
217
- * @param {number?} downloadTimeout - Allowed time in ms for the download of
218
- * install files to complete. When set to 0 there is no time limit. Defaults
219
- * to 0.
220
+ * @param {string} [version=latest] Either "latest", "beta", "dev" or a full
221
+ * version number (i.e. "77.0.3865.0").
222
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
223
+ * install files to complete. When set to 0 there is no time limit.
220
224
  * @return {BrowserBinary}
221
225
  * @throws {Error} Unsupported browser version, Unsupported platform, Browser
222
226
  * download failed.
@@ -237,7 +241,7 @@ class Chromium extends Browser {
237
241
  "win32-x64": ["Win_x64", "chrome-win.zip"],
238
242
  "linux-x64": ["Linux_x64", "chrome-linux.zip"],
239
243
  "darwin-x64": ["Mac", "chrome-mac.zip"],
240
- "dawrin-arm64": ["Mac_Arm", "chrome-mac.zip"]
244
+ "darwin-arm64": ["Mac_Arm", "chrome-mac.zip"]
241
245
  }[platformArch];
242
246
  let archive;
243
247
  let browserDir;
@@ -333,8 +337,14 @@ class Chromium extends Browser {
333
337
  let options = new chrome.Options().addArguments("no-sandbox", ...extraArgs);
334
338
  if (extensionPaths.length > 0)
335
339
  options.addArguments(`load-extension=${extensionPaths.join(",")}`);
336
- if (headless)
337
- options.headless();
340
+ if (headless) {
341
+ // New headless mode introduced in Chrome 111
342
+ // https://developer.chrome.com/articles/new-headless/
343
+ if (getMajorVersion(versionNumber) >= 111)
344
+ options.addArguments("headless=new");
345
+ else
346
+ options.headless();
347
+ }
338
348
  if (insecure)
339
349
  options.addArguments("ignore-certificate-errors");
340
350
  if (incognito)
@@ -423,11 +433,10 @@ class Firefox extends Browser {
423
433
  /**
424
434
  * Installs the browser. The Firefox executable gets extracted in the
425
435
  * {@link snapshotsBaseDir} folder, ready to go.
426
- * @param {string} version - Either "latest", "beta" or a full version
427
- * number (i.e. "68.0"). Defaults to "latest".
428
- * @param {number?} downloadTimeout - Allowed time in ms for the download of
429
- * install files to complete. When set to 0 there is no time limit. Defaults
430
- * to 0.
436
+ * @param {string} [version=latest] Either "latest", "beta" or a full version
437
+ * number (i.e. "68.0").
438
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
439
+ * install files to complete. When set to 0 there is no time limit.
431
440
  * @return {BrowserBinary}
432
441
  * @throws {Error} Unsupported browser version, Unsupported platform, Browser
433
442
  * download failed.
@@ -512,11 +521,8 @@ class Firefox extends Browser {
512
521
  }, 30000, `${DRIVER_START_ERROR}: geckodriver`, 1000);
513
522
 
514
523
  for (let extensionPath of extensionPaths) {
515
- await driver.execute(
516
- new command.Command("install addon")
517
- .setParameter("path", extensionPath)
518
- .setParameter("temporary", true)
519
- );
524
+ let temporary = true; // Parameter not documented on the webdriver docs
525
+ await driver.installAddon(extensionPath, temporary);
520
526
  }
521
527
  return driver;
522
528
  }
@@ -565,8 +571,7 @@ class Edge extends Browser {
565
571
  versionNumbers.push(matches[2]);
566
572
 
567
573
  let compareVersions = (v1, v2) =>
568
- parseInt(v1.split(".")[0], 10) < parseInt(v2.split(".")[0], 10) ?
569
- 1 : -1;
574
+ getMajorVersion(v1) < getMajorVersion(v2) ? 1 : -1;
570
575
  versionNumber = versionNumbers.sort(compareVersions)[0];
571
576
  }
572
577
  else {
@@ -613,11 +618,10 @@ class Edge extends Browser {
613
618
  * Installs the browser. On Linux, Edge is installed as a system package,
614
619
  * which requires root permissions. On MacOS, Edge is installed as a user
615
620
  * app (not as a system app). Installing Edge on Windows is not supported.
616
- * @param {string} version - Either "latest", "beta", "dev" or a full version
617
- * number (i.e. "95.0.1020.40"). Defaults to "latest".
618
- * @param {number?} downloadTimeout - Allowed time in ms for the download of
619
- * install files to complete. When set to 0 there is no time limit. Defaults
620
- * to 0.
621
+ * @param {string} [version=latest] Either "latest", "beta", "dev" or a full
622
+ * version number (i.e. "95.0.1020.40").
623
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
624
+ * install files to complete. When set to 0 there is no time limit.
621
625
  * @return {BrowserBinary}
622
626
  * @throws {Error} Unsupported browser version, Unsupported platform, Browser
623
627
  * download failed.
@@ -760,7 +764,22 @@ class Edge extends Browser {
760
764
  builder.setEdgeOptions(options);
761
765
  builder.setEdgeService(serviceBuilder);
762
766
 
763
- return builder.build();
767
+ let driver;
768
+ // On Windows CI, occasionally a SessionNotCreatedError is thrown, likely
769
+ // due to low OS resources, that's why building the driver is retried
770
+ await wait(async() => {
771
+ try {
772
+ driver = await builder.build();
773
+ return true;
774
+ }
775
+ catch (err) {
776
+ if (err.name != "SessionNotCreatedError")
777
+ throw err;
778
+ await killDriverProcess("msedgedriver");
779
+ }
780
+ }, 30000, `${DRIVER_START_ERROR}: msedgedriver`, 1000);
781
+
782
+ return driver;
764
783
  }
765
784
 
766
785
  /** @see Browser.enableExtensionInIncognito */
@@ -787,11 +806,10 @@ class Edge extends Browser {
787
806
 
788
807
  /**
789
808
  * @type {Object}
790
- * @property {Chromium} chromium - Browser and webdriver functionality for
809
+ * @property {Chromium} chromium Browser and webdriver functionality for
791
810
  * Chromium.
792
- * @property {Firefox} firefox - Browser and webdriver functionality for
793
- * Firefox.
794
- * @property {Edge} edge - Browser and webdriver functionality for Edge.
811
+ * @property {Firefox} firefox Browser and webdriver functionality for Firefox.
812
+ * @property {Edge} edge Browser and webdriver functionality for Edge.
795
813
  */
796
814
  export const BROWSERS = {
797
815
  chromium: Chromium,
package/src/utils.js CHANGED
@@ -28,10 +28,10 @@ import Jimp from "jimp";
28
28
 
29
29
  /**
30
30
  * Downloads url resources.
31
- * @param {string} url - The url of the resource to be downloaded.
32
- * @param {string} destFile - The destination file path.
33
- * @param {number?} timeout - Allowed time in ms for the download to complete.
34
- * When set to 0 there is no time limit. Defaults to 0.
31
+ * @param {string} url The url of the resource to be downloaded.
32
+ * @param {string} destFile The destination file path.
33
+ * @param {number} [timeout=0] Allowed time in ms for the download to complete.
34
+ * When set to 0 there is no time limit.
35
35
  * @throws {TypeError} Invalid URL, Download timeout.
36
36
  */
37
37
  export async function download(url, destFile, timeout = 0) {
@@ -164,9 +164,9 @@ export function wait(condition, timeout = 0, message, pollTimeout = 100) {
164
164
 
165
165
  /**
166
166
  * Takes a screenshot of the full page by scrolling from top to bottom.
167
- * @param {webdriver} driver - The driver controlling the browser.
168
- * @property {boolean} hideScrollbars=true - Hides any scrollbars before
169
- * taking the screenshot, or not.
167
+ * @param {webdriver} driver The driver controlling the browser.
168
+ * @param {boolean} [hideScrollbars=true] Hides any scrollbars before taking
169
+ * the screenshot, or not.
170
170
  * @return {Jimp} A Jimp image object containing the screenshot.
171
171
  * @example
172
172
  * // Getting a base-64 encoded PNG from the returned Jimp image
package/test/browsers.js CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import fs from "fs";
19
- import expect from "expect";
19
+ import {expect} from "expect";
20
20
  import path from "path";
21
21
 
22
22
  import {BROWSERS, snapshotsBaseDir, takeFullPageScreenshot} from "../index.js";
@@ -242,7 +242,9 @@ for (let browser of Object.keys(BROWSERS)) {
242
242
  });
243
243
 
244
244
  it("loads an extension", async() => {
245
- let headless = browser == "firefox";
245
+ // Chromium's old headless mode doesn't support loading extensions
246
+ let headless = browser == "firefox" || (browser == "chromium" &&
247
+ ["latest", "beta", "dev"].includes(version));
246
248
  let {extensionPaths} = getExtension(browser, version);
247
249
 
248
250
  driver = await BROWSERS[browser].getDriver(
package/test/utils.js CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import fs from "fs";
19
- import expect from "expect";
19
+ import {expect} from "expect";
20
20
  import path from "path";
21
21
 
22
22
  import {snapshotsBaseDir, download} from "../index.js";