@eyeo/get-browser-binary 0.11.0 → 0.13.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 +10 -9
- package/RELEASE_NOTES.md +31 -0
- package/package.json +1 -1
- package/src/browsers.js +186 -92
- package/test/browsers.js +32 -9
- package/test/extension/mv3/manifest.json +2 -1
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
|
|
|
@@ -82,6 +83,14 @@ Increasing the timeout may be useful on slow connection environments:
|
|
|
82
83
|
npm test -- --timeout <ms>
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
By default, tests delete the `./browser-snapshots` before each `Browser` suite
|
|
87
|
+
runs. To change that behavior you may set the `TEST_KEEP_SNAPSHOTS` environment
|
|
88
|
+
variable to `true`. Example:
|
|
89
|
+
|
|
90
|
+
```shell
|
|
91
|
+
TEST_KEEP_SNAPSHOTS=true npm test
|
|
92
|
+
```
|
|
93
|
+
|
|
85
94
|
### Running tests on Docker
|
|
86
95
|
|
|
87
96
|
Useful to reproduce the CI environment of the `test:browsers:linux` job.
|
|
@@ -100,14 +109,6 @@ parameter:
|
|
|
100
109
|
docker run --shm-size=512m -e TEST_ARGS="--grep chromium.*latest --timeout 100000" -it browsers
|
|
101
110
|
```
|
|
102
111
|
|
|
103
|
-
By default, tests delete the `./browser-snapshots` before each `Browser` suite
|
|
104
|
-
runs. To change that behavior you may set the `TEST_KEEP_SNAPSHOTS` environment
|
|
105
|
-
variable to `true`. Example:
|
|
106
|
-
|
|
107
|
-
```shell
|
|
108
|
-
TEST_KEEP_SNAPSHOTS=true npm test
|
|
109
|
-
```
|
|
110
|
-
|
|
111
112
|
#### ARM architecture (M1/M2 Apple Silicon)
|
|
112
113
|
|
|
113
114
|
Chromium (ARM native):
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
# 0.13.0
|
|
2
|
+
|
|
3
|
+
- Fixes an issue that prevented the webdriver from locating the Edge binary on
|
|
4
|
+
Linux (#60)
|
|
5
|
+
- Uses headless new mode on Edge >= 116 (!74)
|
|
6
|
+
- Replaces omahaproxy API (deprecated) with chromiumdash (!73)
|
|
7
|
+
- Throws a `browser not installed` error when `customBinaryPath` doesn't exist
|
|
8
|
+
(!72)
|
|
9
|
+
|
|
10
|
+
### Testing
|
|
11
|
+
|
|
12
|
+
- Changes the test extension in incognito mode from spanning to split (#59)
|
|
13
|
+
- Runs Linux Edge tests in a different browser version order (!71)
|
|
14
|
+
|
|
15
|
+
# 0.12.0
|
|
16
|
+
|
|
17
|
+
- Adds a new field `customBrowserBinary` to `getDriver()` options parameter that
|
|
18
|
+
accepts the path of a custom (pre-installed) browser binary. When used, that is
|
|
19
|
+
the browser that will run (#56)
|
|
20
|
+
- Fixes Edge install URLs for mac. Unfortunately, the new URLs provided by Edge
|
|
21
|
+
offer a limited number of old versions only. For that reason `latest`
|
|
22
|
+
becomes the only accepted value for Edge on mac (!64). Please see #56 as a
|
|
23
|
+
possible workaround
|
|
24
|
+
- Fixes an issue with Chromium 115 that prevented loading extensions in
|
|
25
|
+
incognito mode (#52)
|
|
26
|
+
- Logs URL info on previously uncaught http errors (!67)
|
|
27
|
+
|
|
28
|
+
### Testing
|
|
29
|
+
|
|
30
|
+
- Fixes recent failures when running Edge tests (#48)
|
|
31
|
+
|
|
1
32
|
# 0.11.0
|
|
2
33
|
|
|
3
34
|
- Fixes an issue on arm64 edgedriver links that prevented the driver to run on
|
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) {
|
|
@@ -101,19 +102,29 @@ class Browser {
|
|
|
101
102
|
* Gets the installed version returned by the browser binary.
|
|
102
103
|
* @param {string} binary The path to the browser binary.
|
|
103
104
|
* @return {string} Installed browser version.
|
|
105
|
+
* @throws {Error} Browser is not installed.
|
|
104
106
|
*/
|
|
105
107
|
static async getInstalledVersion(binary) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
{
|
|
111
|
-
|
|
108
|
+
try {
|
|
109
|
+
let stdout;
|
|
110
|
+
let stderr;
|
|
111
|
+
if (platform == "win32") {
|
|
112
|
+
({stdout, stderr} = await promisify(exec)(
|
|
113
|
+
`(Get-ItemProperty ${binary}).VersionInfo.ProductVersion`,
|
|
114
|
+
{shell: "powershell.exe"})
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
({stdout, stderr} = await promisify(execFile)(binary, ["--version"]));
|
|
119
|
+
}
|
|
120
|
+
if (stderr)
|
|
121
|
+
throw new Error(stderr);
|
|
122
|
+
|
|
123
|
+
return stdout.trim();
|
|
112
124
|
}
|
|
113
|
-
|
|
114
|
-
({
|
|
125
|
+
catch (err) {
|
|
126
|
+
throw new Error(`${BROWSER_NOT_INSTALLED_ERROR}.\nBinary path: ${binary}\n${err}`);
|
|
115
127
|
}
|
|
116
|
-
return stdout.trim();
|
|
117
128
|
}
|
|
118
129
|
|
|
119
130
|
/**
|
|
@@ -135,6 +146,9 @@ class Browser {
|
|
|
135
146
|
* certificates, or not.
|
|
136
147
|
* @property {Array.<string>} [extraArgs=[]] Additional arguments to start
|
|
137
148
|
* the browser with.
|
|
149
|
+
* @property {string} [customBrowserBinary] Path to the browser binary to be
|
|
150
|
+
* used, instead of the browser installed by installBrowser(). This option
|
|
151
|
+
* overrides the version parameter in getDriver().
|
|
138
152
|
*/
|
|
139
153
|
|
|
140
154
|
/**
|
|
@@ -177,6 +191,7 @@ class Browser {
|
|
|
177
191
|
*/
|
|
178
192
|
class Chromium extends Browser {
|
|
179
193
|
static #CHANNELS = ["latest", "beta", "dev"];
|
|
194
|
+
static #MAX_VERSION_DECREMENTS = 200;
|
|
180
195
|
|
|
181
196
|
static async #getVersionForChannel(channel) {
|
|
182
197
|
if (!Chromium.#CHANNELS.includes(channel))
|
|
@@ -192,14 +207,16 @@ class Chromium extends Browser {
|
|
|
192
207
|
"darwin-x64": "mac",
|
|
193
208
|
"darwin-arm64": "mac_arm64"
|
|
194
209
|
}[platformArch];
|
|
195
|
-
let
|
|
196
|
-
let release = data[0].versions.find(ver => ver.channel == channel);
|
|
197
|
-
let {current_version: version} = release;
|
|
210
|
+
let url = `https://versionhistory.googleapis.com/v1/chrome/platforms/${os}/channels/${channel}/versions/all/releases`;
|
|
198
211
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
212
|
+
let data;
|
|
213
|
+
try {
|
|
214
|
+
data = await got(url).json();
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
|
|
218
|
+
}
|
|
219
|
+
let {version} = data.releases[0];
|
|
203
220
|
|
|
204
221
|
return version;
|
|
205
222
|
}
|
|
@@ -214,6 +231,35 @@ class Chromium extends Browser {
|
|
|
214
231
|
}[platform];
|
|
215
232
|
}
|
|
216
233
|
|
|
234
|
+
static async #getBase(chromiumVersion) {
|
|
235
|
+
let url;
|
|
236
|
+
let chromiumBase;
|
|
237
|
+
try {
|
|
238
|
+
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/55
|
|
239
|
+
if (getMajorVersion(chromiumVersion) < 91) {
|
|
240
|
+
url = `https://omahaproxy.appspot.com/deps.json?version=${chromiumVersion}`;
|
|
241
|
+
({chromium_base_position: chromiumBase} = await got(url).json());
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
url = `https://chromiumdash.appspot.com/fetch_version?version=${chromiumVersion}`;
|
|
245
|
+
({chromium_main_branch_position: chromiumBase} = await got(url).json());
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
|
|
250
|
+
}
|
|
251
|
+
return parseInt(chromiumBase, 10);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
static async #getInstalledBrowserInfo(binary) {
|
|
255
|
+
let installedVersion = await Chromium.getInstalledVersion(binary);
|
|
256
|
+
// Linux example: "Chromium 112.0.5615.49 built on Debian 11.6"
|
|
257
|
+
// Windows example: "114.0.5735.0"
|
|
258
|
+
let versionNumber = installedVersion.split(" ")[1] || installedVersion;
|
|
259
|
+
let base = await Chromium.#getBase(versionNumber);
|
|
260
|
+
return {binary, versionNumber, base};
|
|
261
|
+
}
|
|
262
|
+
|
|
217
263
|
/**
|
|
218
264
|
* Installs the browser. The Chromium executable gets extracted in the
|
|
219
265
|
* {@link snapshotsBaseDir} folder, ready to go.
|
|
@@ -227,32 +273,19 @@ class Chromium extends Browser {
|
|
|
227
273
|
*/
|
|
228
274
|
static async installBrowser(version = "latest", downloadTimeout = 0) {
|
|
229
275
|
const MIN_VERSION = 75;
|
|
230
|
-
const MAX_VERSION_DECREMENTS = 200;
|
|
231
276
|
|
|
232
277
|
let binary;
|
|
233
278
|
let versionNumber;
|
|
234
279
|
let base;
|
|
235
280
|
|
|
236
|
-
async function getBase(chromiumVersion) {
|
|
237
|
-
let {chromium_base_position: chromiumBase} =
|
|
238
|
-
await got(`https://omahaproxy.appspot.com/deps.json?version=${chromiumVersion}`).json();
|
|
239
|
-
return parseInt(chromiumBase, 10);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
281
|
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/46
|
|
243
|
-
if (platformArch == "linux-arm64")
|
|
244
|
-
|
|
245
|
-
let installedVersion = await Chromium.getInstalledVersion(binary);
|
|
246
|
-
// installedVersion example: "Chromium 112.0.5615.49 built on Debian 11.6"
|
|
247
|
-
versionNumber = installedVersion.split(" ")[1];
|
|
248
|
-
base = await getBase(versionNumber);
|
|
249
|
-
return {binary, versionNumber, base};
|
|
250
|
-
}
|
|
282
|
+
if (platformArch == "linux-arm64")
|
|
283
|
+
return await Chromium.#getInstalledBrowserInfo("/usr/bin/chromium");
|
|
251
284
|
|
|
252
285
|
checkVersion(version, MIN_VERSION, Chromium.#CHANNELS);
|
|
253
286
|
versionNumber = await Chromium.#getVersionForChannel(version);
|
|
254
287
|
|
|
255
|
-
base = await getBase(versionNumber);
|
|
288
|
+
base = await Chromium.#getBase(versionNumber);
|
|
256
289
|
let startBase = base;
|
|
257
290
|
let [platformDir, fileName] = {
|
|
258
291
|
"win32-ia32": ["Win", "chrome-win.zip"],
|
|
@@ -293,7 +326,7 @@ class Chromium extends Browser {
|
|
|
293
326
|
// Chromium advises decrementing the branch_base_position when no
|
|
294
327
|
// matching build was found. See https://www.chromium.org/getting-involved/download-chromium
|
|
295
328
|
base--;
|
|
296
|
-
if (base <= startBase - MAX_VERSION_DECREMENTS)
|
|
329
|
+
if (base <= startBase - Chromium.#MAX_VERSION_DECREMENTS)
|
|
297
330
|
throw new Error(`${BROWSER_DOWNLOAD_ERROR}: Chromium base ${startBase}`);
|
|
298
331
|
}
|
|
299
332
|
else {
|
|
@@ -306,7 +339,7 @@ class Chromium extends Browser {
|
|
|
306
339
|
return {binary, versionNumber, base};
|
|
307
340
|
}
|
|
308
341
|
|
|
309
|
-
static async #installDriver(
|
|
342
|
+
static async #installDriver(startBase) {
|
|
310
343
|
let [dir, zip, driverBinary] = {
|
|
311
344
|
"win32-ia32": ["Win", "chromedriver_win32.zip", "chromedriver.exe"],
|
|
312
345
|
"win32-x64": ["Win_x64", "chromedriver_win32.zip", "chromedriver.exe"],
|
|
@@ -317,27 +350,46 @@ class Chromium extends Browser {
|
|
|
317
350
|
}[platformArch];
|
|
318
351
|
|
|
319
352
|
let cacheDir = path.join(snapshotsBaseDir, "chromium", "cache",
|
|
320
|
-
|
|
321
|
-
let archive = path.join(cacheDir, `${
|
|
322
|
-
|
|
353
|
+
"chromedriver");
|
|
354
|
+
let archive = path.join(cacheDir, `${startBase}-${zip}`);
|
|
323
355
|
try {
|
|
324
356
|
await fs.promises.access(archive);
|
|
325
357
|
await extractZip(archive, {dir: cacheDir});
|
|
326
358
|
}
|
|
327
359
|
catch (e) { // zip file is either not cached or corrupted
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
360
|
+
if (platformArch == "linux-arm64") {
|
|
361
|
+
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/46
|
|
362
|
+
// It's unclear how electron releases match Chromium versions. Once that
|
|
363
|
+
// is figured out, the link below will depend on the Chromium version.
|
|
364
|
+
// https://stackoverflow.com/questions/38732822/compile-chromedriver-on-arm
|
|
365
|
+
let url = "https://github.com/electron/electron/releases/download/v24.1.2/chromedriver-v24.1.2-linux-arm64.zip";
|
|
366
|
+
try {
|
|
367
|
+
await download(url, archive);
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
throw new Error(`${DRIVER_DOWNLOAD_ERROR}: ${url}\n${err}`);
|
|
371
|
+
}
|
|
338
372
|
}
|
|
339
|
-
|
|
340
|
-
|
|
373
|
+
else {
|
|
374
|
+
let base = startBase;
|
|
375
|
+
while (true) {
|
|
376
|
+
let url = `https://commondatastorage.googleapis.com/chromium-browser-snapshots/${dir}/${base}/${zip}`;
|
|
377
|
+
try {
|
|
378
|
+
await download(url, archive);
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
if (err.name == "HTTPError") {
|
|
383
|
+
base--;
|
|
384
|
+
archive = path.join(cacheDir, `${base}-${zip}`);
|
|
385
|
+
if (base <= startBase - Chromium.#MAX_VERSION_DECREMENTS)
|
|
386
|
+
throw new Error(`${DRIVER_DOWNLOAD_ERROR}: Chromium base ${startBase}`);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
throw new Error(`${DRIVER_DOWNLOAD_ERROR}: ${url}\n${err}`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
341
393
|
}
|
|
342
394
|
await extractZip(archive, {dir: cacheDir});
|
|
343
395
|
}
|
|
@@ -355,11 +407,12 @@ class Chromium extends Browser {
|
|
|
355
407
|
/** @see Browser.getDriver */
|
|
356
408
|
static async getDriver(version = "latest", {
|
|
357
409
|
headless = true, extensionPaths = [], incognito = false, insecure = false,
|
|
358
|
-
extraArgs = []
|
|
410
|
+
extraArgs = [], customBrowserBinary
|
|
359
411
|
} = {}, downloadTimeout = 0) {
|
|
360
|
-
let {binary, versionNumber, base} =
|
|
412
|
+
let {binary, versionNumber, base} = customBrowserBinary ?
|
|
413
|
+
await Chromium.#getInstalledBrowserInfo(customBrowserBinary) :
|
|
361
414
|
await Chromium.installBrowser(version, downloadTimeout);
|
|
362
|
-
let driverPath = await Chromium.#installDriver(base
|
|
415
|
+
let driverPath = await Chromium.#installDriver(base);
|
|
363
416
|
let serviceBuilder = new chrome.ServiceBuilder(driverPath);
|
|
364
417
|
let options = new chrome.Options().addArguments("no-sandbox", ...extraArgs);
|
|
365
418
|
if (extensionPaths.length > 0)
|
|
@@ -388,6 +441,15 @@ class Chromium extends Browser {
|
|
|
388
441
|
|
|
389
442
|
/** @see Browser.enableExtensionInIncognito */
|
|
390
443
|
static async enableExtensionInIncognito(driver, extensionTitle) {
|
|
444
|
+
let handle = await driver.getWindowHandle();
|
|
445
|
+
|
|
446
|
+
let version = getMajorVersion(
|
|
447
|
+
(await driver.getCapabilities()).getBrowserVersion());
|
|
448
|
+
if (version >= 115)
|
|
449
|
+
// On Chromium 115 opening chrome://extensions on the default tab causes
|
|
450
|
+
// WebDriverError: disconnected. Switching to a new window as a workaround
|
|
451
|
+
await driver.switchTo().newWindow("window");
|
|
452
|
+
|
|
391
453
|
await driver.navigate().to("chrome://extensions");
|
|
392
454
|
await driver.executeScript((...args) => {
|
|
393
455
|
let enable = () => document.querySelector("extensions-manager").shadowRoot
|
|
@@ -415,6 +477,11 @@ class Chromium extends Browser {
|
|
|
415
477
|
setTimeout(() => resolve(enable()), 100);
|
|
416
478
|
});
|
|
417
479
|
}, extensionTitle, EXTENSION_NOT_FOUND_ERROR);
|
|
480
|
+
if (version >= 115)
|
|
481
|
+
// Closing the previously opened new window
|
|
482
|
+
await driver.close();
|
|
483
|
+
|
|
484
|
+
await driver.switchTo().window(handle);
|
|
418
485
|
}
|
|
419
486
|
}
|
|
420
487
|
|
|
@@ -430,7 +497,14 @@ class Firefox extends Browser {
|
|
|
430
497
|
if (!Firefox.#CHANNELS.includes(channel))
|
|
431
498
|
return channel;
|
|
432
499
|
|
|
433
|
-
let
|
|
500
|
+
let url = "https://product-details.mozilla.org/1.0/firefox_versions.json";
|
|
501
|
+
let data;
|
|
502
|
+
try {
|
|
503
|
+
data = await got(url).json();
|
|
504
|
+
}
|
|
505
|
+
catch (err) {
|
|
506
|
+
throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
|
|
507
|
+
}
|
|
434
508
|
return channel == "beta" ?
|
|
435
509
|
data.LATEST_FIREFOX_DEVEL_VERSION : data.LATEST_FIREFOX_VERSION;
|
|
436
510
|
}
|
|
@@ -514,9 +588,11 @@ class Firefox extends Browser {
|
|
|
514
588
|
/** @see Browser.getDriver */
|
|
515
589
|
static async getDriver(version = "latest", {
|
|
516
590
|
headless = true, extensionPaths = [], incognito = false, insecure = false,
|
|
517
|
-
extraArgs = []
|
|
591
|
+
extraArgs = [], customBrowserBinary
|
|
518
592
|
} = {}, downloadTimeout = 0) {
|
|
519
|
-
let
|
|
593
|
+
let binary;
|
|
594
|
+
if (!customBrowserBinary)
|
|
595
|
+
({binary} = await Firefox.installBrowser(version, downloadTimeout));
|
|
520
596
|
|
|
521
597
|
let options = new firefox.Options();
|
|
522
598
|
if (headless)
|
|
@@ -527,7 +603,7 @@ class Firefox extends Browser {
|
|
|
527
603
|
options.set("acceptInsecureCerts", true);
|
|
528
604
|
if (extraArgs.length > 0)
|
|
529
605
|
options.addArguments(...extraArgs);
|
|
530
|
-
options.setBinary(binary);
|
|
606
|
+
options.setBinary(customBrowserBinary || binary);
|
|
531
607
|
|
|
532
608
|
let driver;
|
|
533
609
|
// The OS may be low on resources, that's why building the driver is retried
|
|
@@ -588,7 +664,14 @@ class Edge extends Browser {
|
|
|
588
664
|
if (Edge.#CHANNELS.includes(version) && version != "latest")
|
|
589
665
|
channel = version;
|
|
590
666
|
|
|
591
|
-
let
|
|
667
|
+
let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/`;
|
|
668
|
+
let body;
|
|
669
|
+
try {
|
|
670
|
+
({body} = await got(url));
|
|
671
|
+
}
|
|
672
|
+
catch (err) {
|
|
673
|
+
throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${url}\n${err}`);
|
|
674
|
+
}
|
|
592
675
|
let versionNumber;
|
|
593
676
|
if (Edge.#CHANNELS.includes(version)) {
|
|
594
677
|
let regex = /href="microsoft-edge-(stable|beta|dev)_(.*?)-1_/gm;
|
|
@@ -618,11 +701,7 @@ class Edge extends Browser {
|
|
|
618
701
|
return {versionNumber, channel};
|
|
619
702
|
}
|
|
620
703
|
|
|
621
|
-
static #
|
|
622
|
-
let extra = channel == "stable" ?
|
|
623
|
-
"" : " " + channel.charAt(0).toUpperCase() + channel.slice(1);
|
|
624
|
-
return `Microsoft Edge${extra}`;
|
|
625
|
-
}
|
|
704
|
+
static #darwinApp = "Microsoft Edge";
|
|
626
705
|
|
|
627
706
|
static #getBinaryPath(channel = "stable") {
|
|
628
707
|
switch (platform) {
|
|
@@ -634,8 +713,7 @@ class Edge extends Browser {
|
|
|
634
713
|
return channel == "stable" ?
|
|
635
714
|
"microsoft-edge" : `microsoft-edge-${channel}`;
|
|
636
715
|
case "darwin":
|
|
637
|
-
|
|
638
|
-
return `${process.env.HOME}/Applications/${appName}.app/Contents/MacOS/${appName}`;
|
|
716
|
+
return `${process.env.HOME}/Applications/${Edge.#darwinApp}.app/Contents/MacOS/${Edge.#darwinApp}`;
|
|
639
717
|
default:
|
|
640
718
|
checkPlatform();
|
|
641
719
|
}
|
|
@@ -659,25 +737,17 @@ class Edge extends Browser {
|
|
|
659
737
|
// https://support.microsoft.com/en-us/microsoft-edge/why-can-t-i-uninstall-microsoft-edge-ee150b3b-7d7a-9984-6d83-eb36683d526d
|
|
660
738
|
throw new Error(`${UNSUPPORTED_PLATFORM_ERROR}: ${platform}`);
|
|
661
739
|
|
|
740
|
+
if (platform == "darwin" && version != "latest")
|
|
741
|
+
// Only latest Edge is supported on macOS
|
|
742
|
+
throw new Error(`${UNSUPPORTED_VERSION_ERROR}: ${version}. Only "latest" is supported`);
|
|
743
|
+
|
|
662
744
|
const MIN_VERSION = 95;
|
|
663
745
|
checkVersion(version, MIN_VERSION, Edge.#CHANNELS);
|
|
664
746
|
let {versionNumber, channel} = await Edge.#getVersionForChannel(version);
|
|
665
747
|
|
|
666
|
-
let darwinName = {
|
|
667
|
-
stable: "MicrosoftEdge",
|
|
668
|
-
beta: "MicrosoftEdgeBeta",
|
|
669
|
-
dev: "MicrosoftEdgeDev"
|
|
670
|
-
}[channel];
|
|
671
748
|
let filename = {
|
|
672
749
|
linux: `microsoft-edge-${channel}_${versionNumber}-1_amd64.deb`,
|
|
673
|
-
darwin:
|
|
674
|
-
}[platform];
|
|
675
|
-
let darwinArch = process.arch == "arm64" ?
|
|
676
|
-
"03adf619-38c6-4249-95ff-4a01c0ffc962" :
|
|
677
|
-
"C1297A47-86C4-4C1F-97FA-950631F94777";
|
|
678
|
-
let url = {
|
|
679
|
-
linux: `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`,
|
|
680
|
-
darwin: `https://officecdnmac.microsoft.com/pr/${darwinArch}/MacAutoupdate/${filename}`
|
|
750
|
+
darwin: `MicrosoftEdge-${versionNumber}.pkg`
|
|
681
751
|
}[platform];
|
|
682
752
|
|
|
683
753
|
let snapshotsDir = path.join(snapshotsBaseDir, "edge");
|
|
@@ -689,7 +759,20 @@ class Edge extends Browser {
|
|
|
689
759
|
}
|
|
690
760
|
catch (e) {}
|
|
691
761
|
|
|
762
|
+
let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`;
|
|
692
763
|
try {
|
|
764
|
+
if (platform == "darwin") {
|
|
765
|
+
let caskUrl = "https://formulae.brew.sh/api/cask/microsoft-edge.json";
|
|
766
|
+
let caskJson;
|
|
767
|
+
try {
|
|
768
|
+
caskJson = await got(caskUrl).json();
|
|
769
|
+
}
|
|
770
|
+
catch (err) {
|
|
771
|
+
throw new Error(`${BROWSER_VERSION_CHECK_ERROR}: ${caskUrl}\n${err}`);
|
|
772
|
+
}
|
|
773
|
+
({url} = process.arch == "arm64" ?
|
|
774
|
+
caskJson.variations.arm64_ventura : caskJson);
|
|
775
|
+
}
|
|
693
776
|
await download(url, archive, downloadTimeout);
|
|
694
777
|
}
|
|
695
778
|
catch (err) {
|
|
@@ -700,8 +783,7 @@ class Edge extends Browser {
|
|
|
700
783
|
await promisify(exec)(`dpkg -i ${archive}`);
|
|
701
784
|
}
|
|
702
785
|
else if (platform == "darwin") {
|
|
703
|
-
|
|
704
|
-
await fs.promises.rm(`${process.env.HOME}/Applications/${appName}.app`, {force: true, recursive: true});
|
|
786
|
+
await fs.promises.rm(`${process.env.HOME}/Applications/${Edge.#darwinApp}.app`, {force: true, recursive: true});
|
|
705
787
|
await promisify(exec)(`installer -pkg ${archive} -target CurrentUserHomeDirectory`);
|
|
706
788
|
}
|
|
707
789
|
|
|
@@ -715,18 +797,15 @@ class Edge extends Browser {
|
|
|
715
797
|
return installedVersion.trim().replace(/.*\s/, "");
|
|
716
798
|
}
|
|
717
799
|
|
|
718
|
-
static async #installDriver() {
|
|
800
|
+
static async #installDriver(binary) {
|
|
719
801
|
async function extractEdgeZip(archive, cacheDir, driverPath) {
|
|
720
802
|
await killDriverProcess("msedgedriver");
|
|
721
803
|
await fs.promises.rm(driverPath, {force: true});
|
|
722
804
|
await extractZip(archive, {dir: cacheDir});
|
|
723
805
|
}
|
|
724
806
|
|
|
725
|
-
let
|
|
726
|
-
let versionNumber = await Edge.#getInstalledVersionNumber(
|
|
727
|
-
if (!versionNumber)
|
|
728
|
-
throw new Error(`${BROWSER_NOT_INSTALLED_ERROR}: Edge`);
|
|
729
|
-
|
|
807
|
+
let binaryPath = binary || Edge.#getBinaryPath();
|
|
808
|
+
let versionNumber = await Edge.#getInstalledVersionNumber(binaryPath);
|
|
730
809
|
let [zip, driverBinary] = {
|
|
731
810
|
"win32-ia32": ["edgedriver_win32.zip", "msedgedriver.exe"],
|
|
732
811
|
"win32-x64": ["edgedriver_win64.zip", "msedgedriver.exe"],
|
|
@@ -768,23 +847,38 @@ class Edge extends Browser {
|
|
|
768
847
|
/** @see Browser.getDriver */
|
|
769
848
|
static async getDriver(version = "latest", {
|
|
770
849
|
headless = true, extensionPaths = [], incognito = false, insecure = false,
|
|
771
|
-
extraArgs = []
|
|
850
|
+
extraArgs = [], customBrowserBinary
|
|
772
851
|
} = {}, downloadTimeout = 0) {
|
|
773
|
-
|
|
774
|
-
|
|
852
|
+
let binary;
|
|
853
|
+
let versionNumber;
|
|
854
|
+
if (!customBrowserBinary && (platform == "linux" || platform == "darwin")) {
|
|
855
|
+
({binary, versionNumber} =
|
|
856
|
+
await Edge.installBrowser(version, downloadTimeout));
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
binary = customBrowserBinary || Edge.#getBinaryPath();
|
|
860
|
+
versionNumber =
|
|
861
|
+
await Edge.#getInstalledVersionNumber(binary);
|
|
862
|
+
}
|
|
775
863
|
|
|
776
|
-
let driverPath = await Edge.#installDriver();
|
|
864
|
+
let driverPath = await Edge.#installDriver(binary);
|
|
777
865
|
let serviceBuilder = new edge.ServiceBuilder(driverPath);
|
|
778
866
|
|
|
779
867
|
let options = new edge.Options().addArguments("no-sandbox", ...extraArgs);
|
|
780
|
-
if (headless)
|
|
781
|
-
|
|
868
|
+
if (headless) {
|
|
869
|
+
if (versionNumber && getMajorVersion(versionNumber) >= 114)
|
|
870
|
+
options.addArguments("headless=new");
|
|
871
|
+
else
|
|
872
|
+
options.headless();
|
|
873
|
+
}
|
|
782
874
|
if (extensionPaths.length > 0)
|
|
783
875
|
options.addArguments(`load-extension=${extensionPaths.join(",")}`);
|
|
784
876
|
if (incognito)
|
|
785
|
-
options.addArguments("
|
|
877
|
+
options.addArguments("inprivate");
|
|
786
878
|
if (insecure)
|
|
787
879
|
options.addArguments("ignore-certificate-errors");
|
|
880
|
+
if (platform == "linux")
|
|
881
|
+
options.setEdgeChromiumBinaryPath(`/usr/bin/${binary}`);
|
|
788
882
|
|
|
789
883
|
let builder = new webdriver.Builder();
|
|
790
884
|
builder.forBrowser("MicrosoftEdge");
|
package/test/browsers.js
CHANGED
|
@@ -28,7 +28,8 @@ 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
|
-
|
|
31
|
+
// Unusual ordering: https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/57
|
|
32
|
+
edge: ["dev", "beta", "latest", "95.0.1020.40"]
|
|
32
33
|
};
|
|
33
34
|
const TEST_URL = "https://abptestpages.org/en/exceptions/iframe_subdomains";
|
|
34
35
|
const TEST_URL_LONG_PAGE = "https://abptestpages.org/";
|
|
@@ -121,9 +122,10 @@ async function getCachedTimes(browser) {
|
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
let driverCacheTime = null;
|
|
124
|
-
//
|
|
125
|
+
// geckodriver is installed by npm, that's why Firefox is not tested here
|
|
125
126
|
if (browser != "firefox" && !armLinuxChromium) {
|
|
126
|
-
let driverDir = cacheFiles.find(
|
|
127
|
+
let driverDir = cacheFiles.find(
|
|
128
|
+
elem => !elem.endsWith(".zip") && !elem.endsWith(".pkg"));
|
|
127
129
|
let driverFiles = await fs.promises.readdir(path.join(cacheDir, driverDir));
|
|
128
130
|
let driverZip = driverFiles.find(elem => elem.endsWith(".zip"));
|
|
129
131
|
let driverStat =
|
|
@@ -147,6 +149,7 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
147
149
|
describe(`Version: ${version}`, () => {
|
|
148
150
|
let driver = null;
|
|
149
151
|
let emptyCacheTimes = null;
|
|
152
|
+
let customBrowserBinary = null;
|
|
150
153
|
|
|
151
154
|
async function quitDriver() {
|
|
152
155
|
if (!driver)
|
|
@@ -168,7 +171,7 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
168
171
|
this.skip();
|
|
169
172
|
|
|
170
173
|
let {binary, versionNumber} =
|
|
171
|
-
await BROWSERS[browser].installBrowser(version,
|
|
174
|
+
await BROWSERS[browser].installBrowser(version, this.timeout());
|
|
172
175
|
let browserName = browser == "edge" ? /(edge|Edge)/ : browser;
|
|
173
176
|
expect(binary).toEqual(expect.stringMatching(browserName));
|
|
174
177
|
|
|
@@ -179,6 +182,7 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
179
182
|
|
|
180
183
|
// Adding the version number to the test title for logging purposes
|
|
181
184
|
this.test.title = `${this.test.title} [v${versionNumber}]`;
|
|
185
|
+
customBrowserBinary = binary;
|
|
182
186
|
});
|
|
183
187
|
|
|
184
188
|
it("runs", async() => {
|
|
@@ -212,13 +216,26 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
212
216
|
expect(existingCacheTimes).toEqual(emptyCacheTimes);
|
|
213
217
|
});
|
|
214
218
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (browser == "edge" && version == "latest" &&
|
|
219
|
-
process.platform == "linux")
|
|
219
|
+
// This test depends on running the "installs" test
|
|
220
|
+
it("runs a custom browser binary", async function() {
|
|
221
|
+
if (!customBrowserBinary)
|
|
220
222
|
this.skip();
|
|
221
223
|
|
|
224
|
+
let names = {
|
|
225
|
+
chromium: "chrome",
|
|
226
|
+
firefox: "firefox",
|
|
227
|
+
edge: /(MicrosoftEdge|msedge)/
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
driver =
|
|
231
|
+
await BROWSERS[browser].getDriver(version, {customBrowserBinary});
|
|
232
|
+
await driver.navigate().to(TEST_URL);
|
|
233
|
+
|
|
234
|
+
expect((await driver.getCapabilities()).getBrowserName())
|
|
235
|
+
.toEqual(expect.stringMatching(names[browser]));
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("supports extra args", async() => {
|
|
222
239
|
let headless = false;
|
|
223
240
|
let extraArgs = browser == "firefox" ?
|
|
224
241
|
["--devtools"] : ["auto-open-devtools-for-tabs"];
|
|
@@ -284,5 +301,11 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
284
301
|
.rejects.toThrow(`Unsupported browser version: ${unsupported}`);
|
|
285
302
|
}
|
|
286
303
|
});
|
|
304
|
+
|
|
305
|
+
it("does not run not installed custom browsers", async() => {
|
|
306
|
+
let customBrowserBinary = "not-installed";
|
|
307
|
+
await expect(BROWSERS[browser].getDriver("latest", {customBrowserBinary}))
|
|
308
|
+
.rejects.toThrow(/(Browser is not installed|binary is not a Firefox executable)/);
|
|
309
|
+
});
|
|
287
310
|
});
|
|
288
311
|
}
|