@eyeo/get-browser-binary 0.10.0 → 0.12.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/README.md CHANGED
@@ -35,7 +35,8 @@ the right side.
35
35
  - Edge >= 95
36
36
 
37
37
  Note: Installing Edge is not supported on Windows. It is assumed to be installed
38
- because it is the default browser on that platform.
38
+ because it is the default browser on that platform. On macOS, only the latest
39
+ Edge version is supported.
39
40
 
40
41
  ## Development
41
42
 
@@ -84,7 +85,9 @@ npm test -- --timeout <ms>
84
85
 
85
86
  ### Running tests on Docker
86
87
 
87
- Useful to reproduce the CI environment of the `test:browsers:linux` job:
88
+ Useful to reproduce the CI environment of the `test:browsers:linux` job.
89
+
90
+ #### Intel/AMD architecture
88
91
 
89
92
  ```shell
90
93
  docker build -f test/docker/Dockerfile -t browsers .
@@ -106,6 +109,24 @@ variable to `true`. Example:
106
109
  TEST_KEEP_SNAPSHOTS=true npm test
107
110
  ```
108
111
 
112
+ #### ARM architecture (M1/M2 Apple Silicon)
113
+
114
+ Chromium (ARM native):
115
+
116
+ ```shell
117
+ docker build -f test/docker/arm64.Dockerfile -t browsers-arm .
118
+ docker run --shm-size=512m -e TEST_ARGS="--grep chromium.*latest" -it browsers-arm
119
+ ```
120
+
121
+ Firefox (AMD emulation):
122
+
123
+ ```shell
124
+ docker build -f test/docker/Dockerfile -t browsers-amd .
125
+ docker run --platform linux/amd64 --shm-size=512m -e TEST_ARGS="--grep firefox.*latest" -it browsers-amd
126
+ ```
127
+
128
+ Edge: Not supported
129
+
109
130
  ## Building the documentation
110
131
 
111
132
  ```shell
package/RELEASE_NOTES.md CHANGED
@@ -1,3 +1,31 @@
1
+ # 0.12.0
2
+
3
+ - Adds a new field `customBrowserBinary` to `getDriver()` options parameter that
4
+ accepts the path of a custom (pre-installed) browser binary. When used, that is
5
+ the browser that will run (#56)
6
+ - Fixes Edge install URLs for mac. Unfortunately, the new URLs provided by Edge
7
+ offer a limited number of old versions only. For that reason `latest`
8
+ becomes the only accepted value for Edge on mac (!64). Please see #56 as a
9
+ possible workaround
10
+ - Fixes an issue with Chromium 115 that prevented loading extensions in
11
+ incognito mode (#52)
12
+ - Logs URL info on previously uncaught http errors (!67)
13
+
14
+ ### Testing
15
+
16
+ - Fixes recent failures when running Edge tests (#48)
17
+
18
+ # 0.11.0
19
+
20
+ - Fixes an issue on arm64 edgedriver links that prevented the driver to run on
21
+ M1/M2 machines (!62)
22
+
23
+ ### Testing
24
+
25
+ - Enables running docker tests on arm64 platforms on Chromium (partially) and
26
+ Firefox (!61)
27
+ - Changes `TEST_URL` to a specific testpages url (!62)
28
+
1
29
  # 0.10.0
2
30
 
3
31
  - Added handling of the new headless mode in Chromium (#45)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eyeo/get-browser-binary",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Install browser binaries and matching webdrivers",
5
5
  "repository": {
6
6
  "type": "git",
package/src/browsers.js CHANGED
@@ -47,6 +47,7 @@ const DRIVER_START_ERROR = "Unable to start driver";
47
47
  const EXTENSION_NOT_FOUND_ERROR = "Extension not found";
48
48
  const BROWSER_DOWNLOAD_ERROR = "Browser download failed";
49
49
  const BROWSER_NOT_INSTALLED_ERROR = "Browser is not installed";
50
+ const BROWSER_VERSION_CHECK_ERROR = "Checking the browser version failed";
50
51
  const ELEMENT_NOT_FOUND_ERROR = "HTML element not found";
51
52
 
52
53
  function getMajorVersion(versionNumber) {
@@ -104,16 +105,20 @@ class Browser {
104
105
  */
105
106
  static async getInstalledVersion(binary) {
106
107
  let stdout;
107
- if (platform == "win32") {
108
- ({stdout} = await promisify(exec)(
109
- `(Get-ItemProperty ${binary}).VersionInfo.ProductVersion`,
110
- {shell: "powershell.exe"})
111
- );
112
- }
113
- else {
114
- ({stdout} = await promisify(execFile)(binary, ["--version"]));
108
+ try {
109
+ if (platform == "win32") {
110
+ ({stdout} = await promisify(exec)(
111
+ `(Get-ItemProperty ${binary}).VersionInfo.ProductVersion`,
112
+ {shell: "powershell.exe"})
113
+ );
114
+ }
115
+ else {
116
+ ({stdout} = await promisify(execFile)(binary, ["--version"]));
117
+ }
118
+ return stdout.trim();
115
119
  }
116
- return stdout.trim();
120
+ catch (e) {}
121
+ return "";
117
122
  }
118
123
 
119
124
  /**
@@ -135,6 +140,9 @@ class Browser {
135
140
  * certificates, or not.
136
141
  * @property {Array.<string>} [extraArgs=[]] Additional arguments to start
137
142
  * the browser with.
143
+ * @property {string} [customBrowserBinary] Path to the browser binary to be
144
+ * used, instead of the browser installed by installBrowser(). This option
145
+ * overrides the version parameter in getDriver().
138
146
  */
139
147
 
140
148
  /**
@@ -177,6 +185,7 @@ class Browser {
177
185
  */
178
186
  class Chromium extends Browser {
179
187
  static #CHANNELS = ["latest", "beta", "dev"];
188
+ static #MAX_VERSION_DECREMENTS = 200;
180
189
 
181
190
  static async #getVersionForChannel(channel) {
182
191
  if (!Chromium.#CHANNELS.includes(channel))
@@ -192,7 +201,14 @@ class Chromium extends Browser {
192
201
  "darwin-x64": "mac",
193
202
  "darwin-arm64": "mac_arm64"
194
203
  }[platformArch];
195
- let data = await got(`https://omahaproxy.appspot.com/all.json?os=${os}`).json();
204
+ let url = `https://omahaproxy.appspot.com/all.json?os=${os}`;
205
+ let data;
206
+ try {
207
+ data = await got(url).json();
208
+ }
209
+ catch (err) {
210
+ throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
211
+ }
196
212
  let release = data[0].versions.find(ver => ver.channel == channel);
197
213
  let {current_version: version} = release;
198
214
 
@@ -214,6 +230,27 @@ class Chromium extends Browser {
214
230
  }[platform];
215
231
  }
216
232
 
233
+ static async #getBase(chromiumVersion) {
234
+ let url = `https://omahaproxy.appspot.com/deps.json?version=${chromiumVersion}`;
235
+ let chromiumBase;
236
+ try {
237
+ ({chromium_base_position: chromiumBase} = await got(url).json());
238
+ }
239
+ catch (err) {
240
+ throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
241
+ }
242
+ return parseInt(chromiumBase, 10);
243
+ }
244
+
245
+ static async #getInstalledBrowserInfo(binary) {
246
+ let installedVersion = await Chromium.getInstalledVersion(binary);
247
+ // Linux example: "Chromium 112.0.5615.49 built on Debian 11.6"
248
+ // Windows example: "114.0.5735.0"
249
+ let versionNumber = installedVersion.split(" ")[1] || installedVersion;
250
+ let base = await Chromium.#getBase(versionNumber);
251
+ return {binary, versionNumber, base};
252
+ }
253
+
217
254
  /**
218
255
  * Installs the browser. The Chromium executable gets extracted in the
219
256
  * {@link snapshotsBaseDir} folder, ready to go.
@@ -227,14 +264,19 @@ class Chromium extends Browser {
227
264
  */
228
265
  static async installBrowser(version = "latest", downloadTimeout = 0) {
229
266
  const MIN_VERSION = 75;
230
- const MAX_VERSION_DECREMENTS = 200;
267
+
268
+ let binary;
269
+ let versionNumber;
270
+ let base;
271
+
272
+ // https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/46
273
+ if (platformArch == "linux-arm64")
274
+ return await Chromium.#getInstalledBrowserInfo("/usr/bin/chromium");
231
275
 
232
276
  checkVersion(version, MIN_VERSION, Chromium.#CHANNELS);
233
- let versionNumber = await Chromium.#getVersionForChannel(version);
277
+ versionNumber = await Chromium.#getVersionForChannel(version);
234
278
 
235
- let {chromium_base_position: chromiumBase} =
236
- await got(`https://omahaproxy.appspot.com/deps.json?version=${versionNumber}`).json();
237
- let base = parseInt(chromiumBase, 10);
279
+ base = await Chromium.#getBase(versionNumber);
238
280
  let startBase = base;
239
281
  let [platformDir, fileName] = {
240
282
  "win32-ia32": ["Win", "chrome-win.zip"],
@@ -246,7 +288,6 @@ class Chromium extends Browser {
246
288
  let archive;
247
289
  let browserDir;
248
290
  let snapshotsDir = path.join(snapshotsBaseDir, "chromium");
249
- let binary;
250
291
 
251
292
  while (true) {
252
293
  browserDir = path.join(snapshotsDir, `chromium-${platformArch}-${base}`);
@@ -276,7 +317,7 @@ class Chromium extends Browser {
276
317
  // Chromium advises decrementing the branch_base_position when no
277
318
  // matching build was found. See https://www.chromium.org/getting-involved/download-chromium
278
319
  base--;
279
- if (base <= startBase - MAX_VERSION_DECREMENTS)
320
+ if (base <= startBase - Chromium.#MAX_VERSION_DECREMENTS)
280
321
  throw new Error(`${BROWSER_DOWNLOAD_ERROR}: Chromium base ${startBase}`);
281
322
  }
282
323
  else {
@@ -289,36 +330,65 @@ class Chromium extends Browser {
289
330
  return {binary, versionNumber, base};
290
331
  }
291
332
 
292
- static async #installDriver(base, versionNumber) {
333
+ static async #installDriver(startBase) {
293
334
  let [dir, zip, driverBinary] = {
294
335
  "win32-ia32": ["Win", "chromedriver_win32.zip", "chromedriver.exe"],
295
336
  "win32-x64": ["Win_x64", "chromedriver_win32.zip", "chromedriver.exe"],
296
337
  "linux-x64": ["Linux_x64", "chromedriver_linux64.zip", "chromedriver"],
338
+ "linux-arm64": ["", "", "chromedriver"],
297
339
  "darwin-x64": ["Mac", "chromedriver_mac64.zip", "chromedriver"],
298
340
  "darwin-arm64": ["Mac_Arm", "chromedriver_mac64.zip", "chromedriver"]
299
341
  }[platformArch];
300
342
 
301
343
  let cacheDir = path.join(snapshotsBaseDir, "chromium", "cache",
302
- versionNumber);
303
- let archive = path.join(cacheDir, `${base}-${zip}`);
304
-
344
+ "chromedriver");
345
+ let archive = path.join(cacheDir, `${startBase}-${zip}`);
305
346
  try {
306
347
  await fs.promises.access(archive);
307
348
  await extractZip(archive, {dir: cacheDir});
308
349
  }
309
350
  catch (e) { // zip file is either not cached or corrupted
310
- let url = `https://commondatastorage.googleapis.com/chromium-browser-snapshots/${dir}/${base}/${zip}`;
311
- try {
312
- await download(url, archive);
351
+ if (platformArch == "linux-arm64") {
352
+ // https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/46
353
+ // It's unclear how electron releases match Chromium versions. Once that
354
+ // is figured out, the link below will depend on the Chromium version.
355
+ // https://stackoverflow.com/questions/38732822/compile-chromedriver-on-arm
356
+ let url = "https://github.com/electron/electron/releases/download/v24.1.2/chromedriver-v24.1.2-linux-arm64.zip";
357
+ try {
358
+ await download(url, archive);
359
+ }
360
+ catch (err) {
361
+ throw new Error(`${DRIVER_DOWNLOAD_ERROR}: ${url}\n${err}`);
362
+ }
313
363
  }
314
- catch (err) {
315
- throw new Error(`${DRIVER_DOWNLOAD_ERROR}: ${url}\n${err}`);
364
+ else {
365
+ let base = startBase;
366
+ while (true) {
367
+ let url = `https://commondatastorage.googleapis.com/chromium-browser-snapshots/${dir}/${base}/${zip}`;
368
+ try {
369
+ await download(url, archive);
370
+ break;
371
+ }
372
+ catch (err) {
373
+ if (err.name == "HTTPError") {
374
+ base--;
375
+ archive = path.join(cacheDir, `${base}-${zip}`);
376
+ if (base <= startBase - Chromium.#MAX_VERSION_DECREMENTS)
377
+ throw new Error(`${DRIVER_DOWNLOAD_ERROR}: Chromium base ${startBase}`);
378
+ }
379
+ else {
380
+ throw new Error(`${DRIVER_DOWNLOAD_ERROR}: ${url}\n${err}`);
381
+ }
382
+ }
383
+ }
316
384
  }
317
385
  await extractZip(archive, {dir: cacheDir});
318
386
  }
319
387
 
320
388
  await killDriverProcess("chromedriver");
321
389
  let driverPath = path.join(cacheDir, zip.split(".")[0], driverBinary);
390
+ if (platformArch == "linux-arm64")
391
+ driverPath = path.join(cacheDir, driverBinary);
322
392
  await fs.promises.rm(driverPath, {force: true});
323
393
  await extractZip(archive, {dir: cacheDir});
324
394
 
@@ -328,11 +398,12 @@ class Chromium extends Browser {
328
398
  /** @see Browser.getDriver */
329
399
  static async getDriver(version = "latest", {
330
400
  headless = true, extensionPaths = [], incognito = false, insecure = false,
331
- extraArgs = []
401
+ extraArgs = [], customBrowserBinary
332
402
  } = {}, downloadTimeout = 0) {
333
- let {binary, versionNumber, base} =
403
+ let {binary, versionNumber, base} = customBrowserBinary ?
404
+ await Chromium.#getInstalledBrowserInfo(customBrowserBinary) :
334
405
  await Chromium.installBrowser(version, downloadTimeout);
335
- let driverPath = await Chromium.#installDriver(base, versionNumber);
406
+ let driverPath = await Chromium.#installDriver(base);
336
407
  let serviceBuilder = new chrome.ServiceBuilder(driverPath);
337
408
  let options = new chrome.Options().addArguments("no-sandbox", ...extraArgs);
338
409
  if (extensionPaths.length > 0)
@@ -361,6 +432,15 @@ class Chromium extends Browser {
361
432
 
362
433
  /** @see Browser.enableExtensionInIncognito */
363
434
  static async enableExtensionInIncognito(driver, extensionTitle) {
435
+ let handle = await driver.getWindowHandle();
436
+
437
+ let version = getMajorVersion(
438
+ (await driver.getCapabilities()).getBrowserVersion());
439
+ if (version >= 115)
440
+ // On Chromium 115 opening chrome://extensions on the default tab causes
441
+ // WebDriverError: disconnected. Switching to a new window as a workaround
442
+ await driver.switchTo().newWindow("window");
443
+
364
444
  await driver.navigate().to("chrome://extensions");
365
445
  await driver.executeScript((...args) => {
366
446
  let enable = () => document.querySelector("extensions-manager").shadowRoot
@@ -388,6 +468,11 @@ class Chromium extends Browser {
388
468
  setTimeout(() => resolve(enable()), 100);
389
469
  });
390
470
  }, extensionTitle, EXTENSION_NOT_FOUND_ERROR);
471
+ if (version >= 115)
472
+ // Closing the previously opened new window
473
+ await driver.close();
474
+
475
+ await driver.switchTo().window(handle);
391
476
  }
392
477
  }
393
478
 
@@ -403,7 +488,14 @@ class Firefox extends Browser {
403
488
  if (!Firefox.#CHANNELS.includes(channel))
404
489
  return channel;
405
490
 
406
- let data = await got("https://product-details.mozilla.org/1.0/firefox_versions.json").json();
491
+ let url = "https://product-details.mozilla.org/1.0/firefox_versions.json";
492
+ let data;
493
+ try {
494
+ data = await got(url).json();
495
+ }
496
+ catch (err) {
497
+ throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
498
+ }
407
499
  return channel == "beta" ?
408
500
  data.LATEST_FIREFOX_DEVEL_VERSION : data.LATEST_FIREFOX_VERSION;
409
501
  }
@@ -487,9 +579,11 @@ class Firefox extends Browser {
487
579
  /** @see Browser.getDriver */
488
580
  static async getDriver(version = "latest", {
489
581
  headless = true, extensionPaths = [], incognito = false, insecure = false,
490
- extraArgs = []
582
+ extraArgs = [], customBrowserBinary
491
583
  } = {}, downloadTimeout = 0) {
492
- let {binary} = await Firefox.installBrowser(version, downloadTimeout);
584
+ let binary;
585
+ if (!customBrowserBinary)
586
+ ({binary} = await Firefox.installBrowser(version, downloadTimeout));
493
587
 
494
588
  let options = new firefox.Options();
495
589
  if (headless)
@@ -500,7 +594,7 @@ class Firefox extends Browser {
500
594
  options.set("acceptInsecureCerts", true);
501
595
  if (extraArgs.length > 0)
502
596
  options.addArguments(...extraArgs);
503
- options.setBinary(binary);
597
+ options.setBinary(customBrowserBinary || binary);
504
598
 
505
599
  let driver;
506
600
  // The OS may be low on resources, that's why building the driver is retried
@@ -561,7 +655,14 @@ class Edge extends Browser {
561
655
  if (Edge.#CHANNELS.includes(version) && version != "latest")
562
656
  channel = version;
563
657
 
564
- let {body} = await got(`https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/`);
658
+ let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/`;
659
+ let body;
660
+ try {
661
+ ({body} = await got(url));
662
+ }
663
+ catch (err) {
664
+ throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
665
+ }
565
666
  let versionNumber;
566
667
  if (Edge.#CHANNELS.includes(version)) {
567
668
  let regex = /href="microsoft-edge-(stable|beta|dev)_(.*?)-1_/gm;
@@ -591,11 +692,7 @@ class Edge extends Browser {
591
692
  return {versionNumber, channel};
592
693
  }
593
694
 
594
- static #getDarwinAppName(channel) {
595
- let extra = channel == "stable" ?
596
- "" : " " + channel.charAt(0).toUpperCase() + channel.slice(1);
597
- return `Microsoft Edge${extra}`;
598
- }
695
+ static #darwinApp = "Microsoft Edge";
599
696
 
600
697
  static #getBinaryPath(channel = "stable") {
601
698
  switch (platform) {
@@ -607,8 +704,7 @@ class Edge extends Browser {
607
704
  return channel == "stable" ?
608
705
  "microsoft-edge" : `microsoft-edge-${channel}`;
609
706
  case "darwin":
610
- let appName = Edge.#getDarwinAppName(channel);
611
- return `${process.env.HOME}/Applications/${appName}.app/Contents/MacOS/${appName}`;
707
+ return `${process.env.HOME}/Applications/${Edge.#darwinApp}.app/Contents/MacOS/${Edge.#darwinApp}`;
612
708
  default:
613
709
  checkPlatform();
614
710
  }
@@ -632,25 +728,17 @@ class Edge extends Browser {
632
728
  // https://support.microsoft.com/en-us/microsoft-edge/why-can-t-i-uninstall-microsoft-edge-ee150b3b-7d7a-9984-6d83-eb36683d526d
633
729
  throw new Error(`${UNSUPPORTED_PLATFORM_ERROR}: ${platform}`);
634
730
 
731
+ if (platform == "darwin" && version != "latest")
732
+ // Only latest Edge is supported on macOS
733
+ throw new Error(`${UNSUPPORTED_VERSION_ERROR}: ${version}. Only "latest" is supported`);
734
+
635
735
  const MIN_VERSION = 95;
636
736
  checkVersion(version, MIN_VERSION, Edge.#CHANNELS);
637
737
  let {versionNumber, channel} = await Edge.#getVersionForChannel(version);
638
738
 
639
- let darwinName = {
640
- stable: "MicrosoftEdge",
641
- beta: "MicrosoftEdgeBeta",
642
- dev: "MicrosoftEdgeDev"
643
- }[channel];
644
739
  let filename = {
645
740
  linux: `microsoft-edge-${channel}_${versionNumber}-1_amd64.deb`,
646
- darwin: `${darwinName}-${versionNumber}.pkg`
647
- }[platform];
648
- let darwinArch = process.arch == "arm64" ?
649
- "03adf619-38c6-4249-95ff-4a01c0ffc962" :
650
- "C1297A47-86C4-4C1F-97FA-950631F94777";
651
- let url = {
652
- linux: `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`,
653
- darwin: `https://officecdnmac.microsoft.com/pr/${darwinArch}/MacAutoupdate/${filename}`
741
+ darwin: `MicrosoftEdge-${versionNumber}.pkg`
654
742
  }[platform];
655
743
 
656
744
  let snapshotsDir = path.join(snapshotsBaseDir, "edge");
@@ -662,7 +750,20 @@ class Edge extends Browser {
662
750
  }
663
751
  catch (e) {}
664
752
 
753
+ let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`;
665
754
  try {
755
+ if (platform == "darwin") {
756
+ let caskUrl = "https://formulae.brew.sh/api/cask/microsoft-edge.json";
757
+ let caskJson;
758
+ try {
759
+ caskJson = await got(caskUrl).json();
760
+ }
761
+ catch (err) {
762
+ throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${caskUrl}\n${err}`);
763
+ }
764
+ ({url} = process.arch == "arm64" ?
765
+ caskJson.variations.arm64_ventura : caskJson);
766
+ }
666
767
  await download(url, archive, downloadTimeout);
667
768
  }
668
769
  catch (err) {
@@ -673,8 +774,7 @@ class Edge extends Browser {
673
774
  await promisify(exec)(`dpkg -i ${archive}`);
674
775
  }
675
776
  else if (platform == "darwin") {
676
- let appName = Edge.#getDarwinAppName(channel);
677
- await fs.promises.rm(`${process.env.HOME}/Applications/${appName}.app`, {force: true, recursive: true});
777
+ await fs.promises.rm(`${process.env.HOME}/Applications/${Edge.#darwinApp}.app`, {force: true, recursive: true});
678
778
  await promisify(exec)(`installer -pkg ${archive} -target CurrentUserHomeDirectory`);
679
779
  }
680
780
 
@@ -688,24 +788,24 @@ class Edge extends Browser {
688
788
  return installedVersion.trim().replace(/.*\s/, "");
689
789
  }
690
790
 
691
- static async #installDriver() {
791
+ static async #installDriver(binary) {
692
792
  async function extractEdgeZip(archive, cacheDir, driverPath) {
693
793
  await killDriverProcess("msedgedriver");
694
794
  await fs.promises.rm(driverPath, {force: true});
695
795
  await extractZip(archive, {dir: cacheDir});
696
796
  }
697
797
 
698
- let binary = Edge.#getBinaryPath();
699
- let versionNumber = await Edge.#getInstalledVersionNumber(binary);
798
+ let binaryPath = binary || Edge.#getBinaryPath();
799
+ let versionNumber = await Edge.#getInstalledVersionNumber(binaryPath);
700
800
  if (!versionNumber)
701
- throw new Error(`${BROWSER_NOT_INSTALLED_ERROR}: Edge`);
801
+ throw new Error(`${BROWSER_NOT_INSTALLED_ERROR}. Binary path: ${binaryPath}`);
702
802
 
703
803
  let [zip, driverBinary] = {
704
804
  "win32-ia32": ["edgedriver_win32.zip", "msedgedriver.exe"],
705
805
  "win32-x64": ["edgedriver_win64.zip", "msedgedriver.exe"],
706
806
  "linux-x64": ["edgedriver_linux64.zip", "msedgedriver"],
707
807
  "darwin-x64": ["edgedriver_mac64.zip", "msedgedriver"],
708
- "darwin-arm64": ["edgedriver_arm64.zip", "msedgedriver"]
808
+ "darwin-arm64": ["edgedriver_mac64_m1.zip", "msedgedriver"]
709
809
  }[platformArch];
710
810
  let cacheDir = path.join(snapshotsBaseDir, "edge", "cache",
711
811
  `edgedriver-${versionNumber}`);
@@ -741,12 +841,13 @@ class Edge extends Browser {
741
841
  /** @see Browser.getDriver */
742
842
  static async getDriver(version = "latest", {
743
843
  headless = true, extensionPaths = [], incognito = false, insecure = false,
744
- extraArgs = []
844
+ extraArgs = [], customBrowserBinary
745
845
  } = {}, downloadTimeout = 0) {
746
- if (platform == "linux" || platform == "darwin")
747
- await Edge.installBrowser(version, downloadTimeout);
846
+ let binary;
847
+ if (!customBrowserBinary && (platform == "linux" || platform == "darwin"))
848
+ ({binary} = await Edge.installBrowser(version, downloadTimeout));
748
849
 
749
- let driverPath = await Edge.#installDriver();
850
+ let driverPath = await Edge.#installDriver(customBrowserBinary || binary);
750
851
  let serviceBuilder = new edge.ServiceBuilder(driverPath);
751
852
 
752
853
  let options = new edge.Options().addArguments("no-sandbox", ...extraArgs);
@@ -755,7 +856,7 @@ class Edge extends Browser {
755
856
  if (extensionPaths.length > 0)
756
857
  options.addArguments(`load-extension=${extensionPaths.join(",")}`);
757
858
  if (incognito)
758
- options.addArguments("incognito");
859
+ options.addArguments("inprivate");
759
860
  if (insecure)
760
861
  options.addArguments("ignore-certificate-errors");
761
862
 
package/test/browsers.js CHANGED
@@ -28,9 +28,9 @@ import "geckodriver"; // Required to set the driver path on Windows
28
28
  const VERSIONS = {
29
29
  chromium: ["latest", "75.0.3770.0", "beta", "dev"],
30
30
  firefox: ["latest", "60.0", "beta"],
31
- edge: ["latest", "95.0.1020.40", "beta", "dev"]
31
+ edge: ["dev", "latest", "beta", "95.0.1020.40"]
32
32
  };
33
- const TEST_URL = "https://gitlab.com/eyeo/developer-experience/get-browser-binary";
33
+ const TEST_URL = "https://abptestpages.org/en/exceptions/iframe_subdomains";
34
34
  const TEST_URL_LONG_PAGE = "https://abptestpages.org/";
35
35
 
36
36
  async function switchToHandle(driver, testFn) {
@@ -105,12 +105,14 @@ function getExtension(browser, version) {
105
105
  }
106
106
 
107
107
  async function getCachedTimes(browser) {
108
+ let armLinuxChromium = browser == "chromium" &&
109
+ process.platform == "linux" && process.arch == "arm64";
108
110
  let cacheDir = path.join(snapshotsBaseDir, browser, "cache");
109
111
  let cacheFiles = await fs.promises.readdir(cacheDir);
110
112
 
111
113
  let browserCacheTime = null;
112
114
  // Edge gets installed at OS level, that's why it's not tested here
113
- if (browser != "edge") {
115
+ if (browser != "edge" && !armLinuxChromium) {
114
116
  let installTypes = [".zip", ".dmg", ".bz2"];
115
117
  let browserZip =
116
118
  cacheFiles.find(elem => installTypes.some(type => elem.includes(type)));
@@ -119,9 +121,10 @@ async function getCachedTimes(browser) {
119
121
  }
120
122
 
121
123
  let driverCacheTime = null;
122
- // Firefox install file includes the driver, that's why it's not tested here
123
- if (browser != "firefox") {
124
- let driverDir = cacheFiles.find(elem => !elem.endsWith(".zip"));
124
+ // geckodriver is installed by npm, that's why Firefox is not tested here
125
+ if (browser != "firefox" && !armLinuxChromium) {
126
+ let driverDir = cacheFiles.find(
127
+ elem => !elem.endsWith(".zip") && !elem.endsWith(".pkg"));
125
128
  let driverFiles = await fs.promises.readdir(path.join(cacheDir, driverDir));
126
129
  let driverZip = driverFiles.find(elem => elem.endsWith(".zip"));
127
130
  let driverStat =
@@ -145,6 +148,7 @@ for (let browser of Object.keys(BROWSERS)) {
145
148
  describe(`Version: ${version}`, () => {
146
149
  let driver = null;
147
150
  let emptyCacheTimes = null;
151
+ let customBrowserBinary = null;
148
152
 
149
153
  async function quitDriver() {
150
154
  if (!driver)
@@ -166,7 +170,7 @@ for (let browser of Object.keys(BROWSERS)) {
166
170
  this.skip();
167
171
 
168
172
  let {binary, versionNumber} =
169
- await BROWSERS[browser].installBrowser(version, 60000);
173
+ await BROWSERS[browser].installBrowser(version, this.timeout());
170
174
  let browserName = browser == "edge" ? /(edge|Edge)/ : browser;
171
175
  expect(binary).toEqual(expect.stringMatching(browserName));
172
176
 
@@ -177,6 +181,7 @@ for (let browser of Object.keys(BROWSERS)) {
177
181
 
178
182
  // Adding the version number to the test title for logging purposes
179
183
  this.test.title = `${this.test.title} [v${versionNumber}]`;
184
+ customBrowserBinary = binary;
180
185
  });
181
186
 
182
187
  it("runs", async() => {
@@ -210,6 +215,25 @@ for (let browser of Object.keys(BROWSERS)) {
210
215
  expect(existingCacheTimes).toEqual(emptyCacheTimes);
211
216
  });
212
217
 
218
+ // This test depends on running the "installs" test
219
+ it("runs a custom browser binary", async function() {
220
+ if (!customBrowserBinary)
221
+ this.skip();
222
+
223
+ let names = {
224
+ chromium: "chrome",
225
+ firefox: "firefox",
226
+ edge: /(MicrosoftEdge|msedge)/
227
+ };
228
+
229
+ driver =
230
+ await BROWSERS[browser].getDriver(version, {customBrowserBinary});
231
+ await driver.navigate().to(TEST_URL);
232
+
233
+ expect((await driver.getCapabilities()).getBrowserName())
234
+ .toEqual(expect.stringMatching(names[browser]));
235
+ });
236
+
213
237
  it("supports extra args", async() => {
214
238
  let headless = false;
215
239
  let extraArgs = browser == "firefox" ?
@@ -0,0 +1,22 @@
1
+ # Duplicated from registry.gitlab.com/eyeo/docker/get-browser-binary:node16
2
+ # https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/46
3
+ FROM node:16-bullseye-slim
4
+ # General packages
5
+ RUN apt-get update && apt-get install -y git procps wget unzip bzip2 gnupg
6
+ # xvfb (headful browser run)
7
+ RUN apt-get install -y libgtk-3-0 libxt6 xvfb libnss3 libxss1
8
+ # General browser dependencies
9
+ RUN apt-get install -y libgconf-2-4 libasound2 libgbm1
10
+ # Edge dependencies
11
+ RUN apt-get install -y fonts-liberation libatomic1 xdg-utils libu2f-udev
12
+
13
+ # Chromium ARM
14
+ RUN apt-get install -y chromium
15
+
16
+ COPY package*.json get-browser-binary/
17
+ RUN cd get-browser-binary && npm install
18
+
19
+ COPY . get-browser-binary/
20
+
21
+ ENV TEST_ARGS="--grep Browser"
22
+ ENTRYPOINT get-browser-binary/test/docker/entrypoint.sh