@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 +23 -2
- package/RELEASE_NOTES.md +28 -0
- package/package.json +1 -1
- package/src/browsers.js +167 -66
- package/test/browsers.js +31 -7
- package/test/docker/arm64.Dockerfile +22 -0
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
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
|
-
|
|
108
|
-
(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
277
|
+
versionNumber = await Chromium.#getVersionForChannel(version);
|
|
234
278
|
|
|
235
|
-
|
|
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(
|
|
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
|
-
|
|
303
|
-
let archive = path.join(cacheDir, `${
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
315
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 #
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
699
|
-
let versionNumber = await Edge.#getInstalledVersionNumber(
|
|
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}:
|
|
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": ["
|
|
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
|
-
|
|
747
|
-
|
|
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("
|
|
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: ["
|
|
31
|
+
edge: ["dev", "latest", "beta", "95.0.1020.40"]
|
|
32
32
|
};
|
|
33
|
-
const TEST_URL = "https://
|
|
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
|
-
//
|
|
123
|
-
if (browser != "firefox") {
|
|
124
|
-
let driverDir = cacheFiles.find(
|
|
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,
|
|
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
|