@eyeo/get-browser-binary 0.2.0 → 0.3.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 +13 -12
- package/README.md +19 -5
- package/RELEASE_NOTES.md +8 -0
- package/index.js +1 -0
- package/package.json +4 -4
- package/src/browsers.js +95 -58
- package/src/utils.js +29 -1
- package/test/{runner.js → browsers.js} +11 -43
- package/test/utils.js +42 -0
package/.gitlab-ci.yml
CHANGED
|
@@ -19,7 +19,15 @@ cache:
|
|
|
19
19
|
paths:
|
|
20
20
|
- node_modules/
|
|
21
21
|
|
|
22
|
-
test:
|
|
22
|
+
test:basic:
|
|
23
|
+
stage: test
|
|
24
|
+
before_script:
|
|
25
|
+
- npm install
|
|
26
|
+
script:
|
|
27
|
+
- npm run lint
|
|
28
|
+
- npm test -- --grep "Utils"
|
|
29
|
+
|
|
30
|
+
test:browsers:linux:
|
|
23
31
|
stage: test
|
|
24
32
|
before_script:
|
|
25
33
|
- apt-get update && apt-get install -y procps
|
|
@@ -32,13 +40,9 @@ test:linux:
|
|
|
32
40
|
- rm microsoft.*
|
|
33
41
|
- apt-get update && apt-get install -y microsoft-edge-stable
|
|
34
42
|
script:
|
|
35
|
-
- npm
|
|
36
|
-
- xvfb-run -a npm test -- -g "chromium (latest|beta)"
|
|
37
|
-
- xvfb-run -a npm test -- -g "chromium dev"
|
|
38
|
-
- xvfb-run -a npm test -- -g "chromium 77"
|
|
39
|
-
- xvfb-run -a npm test -- -g "(edge|firefox)"
|
|
43
|
+
- xvfb-run -a npm test -- --grep "Browser"
|
|
40
44
|
|
|
41
|
-
test:windows:
|
|
45
|
+
test:browsers:windows:
|
|
42
46
|
stage: test
|
|
43
47
|
variables:
|
|
44
48
|
CI_PROJECT_ID_MAINSTREAM: 36688302
|
|
@@ -52,11 +56,8 @@ test:windows:
|
|
|
52
56
|
- choco upgrade -y nodejs --version 16.10.0
|
|
53
57
|
- npm install
|
|
54
58
|
script:
|
|
55
|
-
- npm test --
|
|
56
|
-
- npm test --
|
|
57
|
-
- npm test -- -g "chromium dev"
|
|
58
|
-
- npm test -- -g "chromium 77"
|
|
59
|
-
- npm test -- -g "edge"
|
|
59
|
+
- npm test -- --grep "chromium"
|
|
60
|
+
- npm test -- --grep "edge"
|
|
60
61
|
tags:
|
|
61
62
|
- shared-windows
|
|
62
63
|
- windows
|
package/README.md
CHANGED
|
@@ -25,10 +25,9 @@ import {BROWSERS} from "@eyeo/get-browser-binary";
|
|
|
25
25
|
await driver.navigate().to("https://example.com/");
|
|
26
26
|
await driver.quit();
|
|
27
27
|
})();
|
|
28
|
-
|
|
29
28
|
```
|
|
30
29
|
|
|
31
|
-
[test/
|
|
30
|
+
[test/browsers.js](https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/blob/main/test/browsers.js)
|
|
32
31
|
provides other usage examples of the library.
|
|
33
32
|
|
|
34
33
|
For more information, please refer to the [API documention](https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/jobs/artifacts/main/file/docs/index.html?job=docs).
|
|
@@ -48,15 +47,30 @@ the right side.
|
|
|
48
47
|
npm install
|
|
49
48
|
```
|
|
50
49
|
|
|
50
|
+
### Folders to ignore / cache
|
|
51
|
+
|
|
52
|
+
All browser and webdriver files will be downloaded to the `./browser-snapshots`
|
|
53
|
+
folder, which probably makes sense to be ignored (for instance, by adding it to
|
|
54
|
+
`.gitignore`).
|
|
55
|
+
|
|
56
|
+
On the other hand, `./browser-snapshots/<browser_name>/cache` will hold all the
|
|
57
|
+
downloaded installation files required by `<browser_name>`. Therefore, it may be
|
|
58
|
+
useful to add `./browser-snapshots/*/cache` to the list of cached folders in
|
|
59
|
+
your CI pipeline configuration.
|
|
60
|
+
|
|
51
61
|
## Testing
|
|
52
62
|
|
|
53
|
-
|
|
63
|
+
Running all tests:
|
|
54
64
|
|
|
55
65
|
```shell
|
|
56
|
-
npm test
|
|
66
|
+
npm test
|
|
57
67
|
```
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
The `grep` option filters the tests to run with a regular expression. Example:
|
|
70
|
+
|
|
71
|
+
```shell
|
|
72
|
+
npm test -- --grep "chromium latest"
|
|
73
|
+
```
|
|
60
74
|
|
|
61
75
|
## Building the documentation
|
|
62
76
|
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
# 0.3.0
|
|
2
|
+
|
|
3
|
+
- Adds incognito mode support to all browsers (#5)
|
|
4
|
+
- Exports the utils download function (#12)
|
|
5
|
+
- Adds the details of the directories to ignore / cache to the README (#13)
|
|
6
|
+
- Fixes Chromium tests execution on all platforms (#3)
|
|
7
|
+
- Updates the geckodriver package (#14)
|
|
8
|
+
|
|
1
9
|
# 0.2.0
|
|
2
10
|
|
|
3
11
|
Change `Browser.getDriver` signature to use `driverOptions` parameter.
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eyeo/get-browser-binary",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Download browser binaries and matching webdrivers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dmg": "^0.1.0",
|
|
20
20
|
"extract-zip": "^2.0.1",
|
|
21
21
|
"fs-extra": "^10.0.0",
|
|
22
|
-
"geckodriver": "^
|
|
22
|
+
"geckodriver": "^3.0.2",
|
|
23
23
|
"got": "^11.8.2",
|
|
24
24
|
"msedgedriver": "^91.0.0",
|
|
25
25
|
"selenium-webdriver": "^4.2.0"
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"mocha": "^10.0.0"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
|
-
"docs": "jsdoc --readme README.md --destination docs src
|
|
35
|
+
"docs": "jsdoc --readme README.md --destination docs src/*.js",
|
|
36
36
|
"lint": "eslint --ext js .",
|
|
37
|
-
"test": "mocha test
|
|
37
|
+
"test": "mocha test/*.js --"
|
|
38
38
|
}
|
|
39
39
|
}
|
package/src/browsers.js
CHANGED
|
@@ -27,8 +27,8 @@ import firefox from "selenium-webdriver/firefox.js";
|
|
|
27
27
|
import command from "selenium-webdriver/lib/command.js";
|
|
28
28
|
import extractZip from "extract-zip";
|
|
29
29
|
|
|
30
|
-
import {download, extractTar, extractDmg, runWinInstaller, getBrowserVersion
|
|
31
|
-
|
|
30
|
+
import {download, extractTar, extractDmg, runWinInstaller, getBrowserVersion,
|
|
31
|
+
killDriverProcess} from "./utils.js";
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Root folder where browser and webdriver binaries get downloaded.
|
|
@@ -37,9 +37,9 @@ import {download, extractTar, extractDmg, runWinInstaller, getBrowserVersion}
|
|
|
37
37
|
export let snapshotsBaseDir = path.join(process.cwd(), "browser-snapshots");
|
|
38
38
|
|
|
39
39
|
let {until, By} = webdriver;
|
|
40
|
-
const ERROR_INCOGNITO_NOT_SUPPORTED = "Incognito mode is not supported";
|
|
41
40
|
const ERROR_DOWNLOAD_NOT_SUPPORTED =
|
|
42
41
|
"Downloading this browser is not supported";
|
|
42
|
+
let platform = `${process.platform}-${process.arch}`;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Base class for browser download functionality. Please see subclasses for
|
|
@@ -89,6 +89,7 @@ class Browser {
|
|
|
89
89
|
* no effect.
|
|
90
90
|
* @param {driverOptions?} options - Options to start the browser with.
|
|
91
91
|
* @return {webdriver}
|
|
92
|
+
* @throws {Error} Unsupported webdriver version.
|
|
92
93
|
*/
|
|
93
94
|
static async getDriver(version, options = {}) {
|
|
94
95
|
// to be implemented by the subclass
|
|
@@ -102,7 +103,10 @@ class Browser {
|
|
|
102
103
|
* @return {webdriver}
|
|
103
104
|
*/
|
|
104
105
|
static async enableExtensionInIncognito(driver, extensionTitle) {
|
|
105
|
-
|
|
106
|
+
// Allowing the extension in incognito mode can't happen programmatically:
|
|
107
|
+
// https://stackoverflow.com/questions/57419654
|
|
108
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1729315
|
|
109
|
+
// That is done through the UI, to be implemented by the subclass
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -159,17 +163,13 @@ class Chromium extends Browser {
|
|
|
159
163
|
|
|
160
164
|
let revision = parseInt(chromiumRevision, 10);
|
|
161
165
|
let startingRevision = revision;
|
|
162
|
-
let
|
|
163
|
-
|
|
164
|
-
let buildTypes = {
|
|
166
|
+
let [platformDir, fileName] = {
|
|
165
167
|
"win32-ia32": ["Win", "chrome-win.zip"],
|
|
166
168
|
"win32-x64": ["Win_x64", "chrome-win.zip"],
|
|
167
169
|
"linux-x64": ["Linux_x64", "chrome-linux.zip"],
|
|
168
170
|
"darwin-x64": ["Mac", "chrome-mac.zip"],
|
|
169
171
|
"dawrin-arm64": ["Mac_Arm", "chrome-mac.zip"]
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
let [platformDir, fileName] = buildTypes[platform];
|
|
172
|
+
}[platform];
|
|
173
173
|
let archive = null;
|
|
174
174
|
let browserDir = null;
|
|
175
175
|
let snapshotsDir = path.join(snapshotsBaseDir, "chromium");
|
|
@@ -229,15 +229,13 @@ class Chromium extends Browser {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
static async #installDriver(revision, version) {
|
|
232
|
-
let
|
|
233
|
-
let buildTypes = {
|
|
232
|
+
let [dir, zip, driver] = {
|
|
234
233
|
"win32-ia32": ["Win", "chromedriver_win32.zip", "chromedriver.exe"],
|
|
235
234
|
"win32-x64": ["Win_x64", "chromedriver_win32.zip", "chromedriver.exe"],
|
|
236
235
|
"linux-x64": ["Linux_x64", "chromedriver_linux64.zip", "chromedriver"],
|
|
237
236
|
"darwin-x64": ["Mac", "chromedriver_mac64.zip", "chromedriver"],
|
|
238
237
|
"darwin-arm64": ["Mac_Arm", "chromedriver_mac64.zip", "chromedriver"]
|
|
239
|
-
};
|
|
240
|
-
let [dir, zip, driver] = buildTypes[platform];
|
|
238
|
+
}[platform];
|
|
241
239
|
|
|
242
240
|
let cacheDir = path.join(snapshotsBaseDir, "chromium", "cache", version);
|
|
243
241
|
let destinationDir = path.join(process.cwd(), "node_modules",
|
|
@@ -247,25 +245,17 @@ class Chromium extends Browser {
|
|
|
247
245
|
await download(`https://commondatastorage.googleapis.com/chromium-browser-snapshots/${dir}/${revision}/${zip}`,
|
|
248
246
|
archive);
|
|
249
247
|
await extractZip(archive, {dir: cacheDir});
|
|
248
|
+
// avoid driver copy failing if the file would be locked
|
|
249
|
+
await killDriverProcess(Chromium.#DRIVER);
|
|
250
250
|
await fs.promises.mkdir(destinationDir, {recursive: true});
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
path.join(destinationDir, driver));
|
|
254
|
-
}
|
|
255
|
-
catch (err) {
|
|
256
|
-
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/3
|
|
257
|
-
if (!err.toString().includes("copyfile"))
|
|
258
|
-
throw err;
|
|
259
|
-
}
|
|
251
|
+
await fs.promises.copyFile(path.join(cacheDir, zip.split(".")[0], driver),
|
|
252
|
+
path.join(destinationDir, driver));
|
|
260
253
|
}
|
|
261
254
|
|
|
262
255
|
/** @see Browser.getDriver */
|
|
263
256
|
static async getDriver(version, {headless = true, extensionPaths = [],
|
|
264
257
|
incognito = false, insecure = false,
|
|
265
258
|
extraArgs = []} = {}) {
|
|
266
|
-
if (incognito)
|
|
267
|
-
throw new Error(ERROR_INCOGNITO_NOT_SUPPORTED);
|
|
268
|
-
|
|
269
259
|
let {binary, revision, downloadedVersion} =
|
|
270
260
|
await Chromium.downloadBinary(version);
|
|
271
261
|
await Chromium.#installDriver(revision, downloadedVersion);
|
|
@@ -277,6 +267,8 @@ class Chromium extends Browser {
|
|
|
277
267
|
options.headless();
|
|
278
268
|
if (insecure)
|
|
279
269
|
options.addArguments("ignore-certificate-errors");
|
|
270
|
+
if (incognito)
|
|
271
|
+
options.addArguments("incognito");
|
|
280
272
|
options.setChromeBinaryPath(binary);
|
|
281
273
|
|
|
282
274
|
let builder = new webdriver.Builder();
|
|
@@ -285,6 +277,41 @@ class Chromium extends Browser {
|
|
|
285
277
|
|
|
286
278
|
return builder.build();
|
|
287
279
|
}
|
|
280
|
+
|
|
281
|
+
/** @see Browser.enableExtensionInIncognito */
|
|
282
|
+
static async enableExtensionInIncognito(driver, extensionTitle) {
|
|
283
|
+
let version = await getBrowserVersion(driver);
|
|
284
|
+
if (version < 75)
|
|
285
|
+
// The UI workaround needs a chromedriver >= 75
|
|
286
|
+
throw new Error(`Only supported on Chromium >= 75. Current version: ${version}`);
|
|
287
|
+
|
|
288
|
+
await driver.navigate().to("chrome://extensions");
|
|
289
|
+
await driver.executeScript(`
|
|
290
|
+
let enable = () => document.querySelector("extensions-manager").shadowRoot
|
|
291
|
+
.querySelector("extensions-detail-view").shadowRoot
|
|
292
|
+
.getElementById("allow-incognito").shadowRoot
|
|
293
|
+
.getElementById("crToggle").click();
|
|
294
|
+
|
|
295
|
+
let extensions = document.querySelector("extensions-manager").shadowRoot
|
|
296
|
+
.getElementById("items-list").shadowRoot
|
|
297
|
+
.querySelectorAll("extensions-item");
|
|
298
|
+
|
|
299
|
+
return new Promise((resolve, reject) => {
|
|
300
|
+
let extensionDetails;
|
|
301
|
+
for (let {shadowRoot} of extensions) {
|
|
302
|
+
if (shadowRoot.getElementById("name").innerHTML != arguments[0])
|
|
303
|
+
continue;
|
|
304
|
+
|
|
305
|
+
extensionDetails = shadowRoot.getElementById("detailsButton");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!extensionDetails)
|
|
309
|
+
reject("Extension was not found");
|
|
310
|
+
|
|
311
|
+
extensionDetails.click();
|
|
312
|
+
setTimeout(() => resolve(enable()), 100);
|
|
313
|
+
});`, extensionTitle);
|
|
314
|
+
}
|
|
288
315
|
}
|
|
289
316
|
|
|
290
317
|
/**
|
|
@@ -326,18 +353,18 @@ class Firefox {
|
|
|
326
353
|
}
|
|
327
354
|
|
|
328
355
|
static async #downloadFirefox(version) {
|
|
329
|
-
let
|
|
330
|
-
if (platform == "win32")
|
|
331
|
-
platform += "-" + process.arch;
|
|
332
|
-
let buildTypes = {
|
|
356
|
+
let [buildPlatform, fileName] = {
|
|
333
357
|
"win32-ia32": ["win32", `Firefox Setup ${version}.exe`],
|
|
334
358
|
"win32-x64": ["win64", `Firefox Setup ${version}.exe`],
|
|
335
|
-
"linux": ["linux-x86_64", `firefox-${version}.tar.bz2`],
|
|
336
|
-
"darwin": ["mac", `Firefox ${version}.dmg`]
|
|
337
|
-
|
|
359
|
+
"linux-x64": ["linux-x86_64", `firefox-${version}.tar.bz2`],
|
|
360
|
+
"darwin-x64": ["mac", `Firefox ${version}.dmg`],
|
|
361
|
+
"darwin-arm64": ["mac", `Firefox ${version}.dmg`]
|
|
362
|
+
}[platform];
|
|
338
363
|
|
|
339
364
|
let snapshotsDir = path.join(snapshotsBaseDir, "firefox");
|
|
340
365
|
let browserDir = path.join(snapshotsDir, `firefox-${platform}-${version}`);
|
|
366
|
+
let archive = path.join(snapshotsDir, "cache", fileName);
|
|
367
|
+
|
|
341
368
|
try {
|
|
342
369
|
await fs.promises.access(browserDir);
|
|
343
370
|
return Firefox.#getFirefoxBinary(browserDir);
|
|
@@ -345,10 +372,6 @@ class Firefox {
|
|
|
345
372
|
catch (e) {}
|
|
346
373
|
|
|
347
374
|
await fs.promises.mkdir(path.dirname(browserDir), {recursive: true});
|
|
348
|
-
|
|
349
|
-
let [buildPlatform, fileName] = buildTypes[platform];
|
|
350
|
-
let archive = path.join(snapshotsDir, "cache", fileName);
|
|
351
|
-
|
|
352
375
|
try {
|
|
353
376
|
await fs.promises.access(archive);
|
|
354
377
|
}
|
|
@@ -409,14 +432,10 @@ class Firefox {
|
|
|
409
432
|
|
|
410
433
|
/** @see Browser.enableExtensionInIncognito */
|
|
411
434
|
static async enableExtensionInIncognito(driver, extensionTitle) {
|
|
412
|
-
// Allowing the extension in private browsing can't happen programmatically:
|
|
413
|
-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1729315
|
|
414
|
-
// Therefore, that is done through the UI
|
|
415
435
|
let version = await getBrowserVersion(driver);
|
|
416
|
-
if (version < 87)
|
|
436
|
+
if (version < 87)
|
|
417
437
|
// The UI workaround assumes web elements only present on Firefox >= 87
|
|
418
438
|
throw new Error(`Only supported on Firefox >= 87. Current version: ${version}`);
|
|
419
|
-
}
|
|
420
439
|
|
|
421
440
|
await driver.navigate().to("about:addons");
|
|
422
441
|
await driver.wait(until.elementLocated(By.name("extension")), 1000).click();
|
|
@@ -464,15 +483,13 @@ class Edge {
|
|
|
464
483
|
|
|
465
484
|
// Based on "node_modules/msedgedriver/install.js", adding a fallback
|
|
466
485
|
// mechanism when msedgedriver doesn't exist for the latest Edge version.
|
|
467
|
-
let
|
|
468
|
-
let buildTypes = {
|
|
486
|
+
let [zip, driver] = {
|
|
469
487
|
"win32-ia32": ["edgedriver_win32.zip", "msedgedriver.exe"],
|
|
470
488
|
"win32-x64": ["edgedriver_win64.zip", "msedgedriver.exe"],
|
|
471
489
|
"linux-x64": ["edgedriver_linux64.zip", "msedgedriver"],
|
|
472
490
|
"darwin-x64": ["edgedriver_mac64.zip", "msedgedriver"],
|
|
473
491
|
"darwin-arm64": ["edgedriver_arm64.zip", "msedgedriver"]
|
|
474
|
-
};
|
|
475
|
-
let [zip, driver] = buildTypes[platform];
|
|
492
|
+
}[platform];
|
|
476
493
|
let cacheDir = path.join(snapshotsBaseDir, "edge", "cache");
|
|
477
494
|
let driverBinDir = path.join(process.cwd(), "node_modules", Edge.#DRIVER,
|
|
478
495
|
"bin");
|
|
@@ -498,17 +515,12 @@ class Edge {
|
|
|
498
515
|
throw new Error(`msedgedriver was not found for Edge ${version}`);
|
|
499
516
|
|
|
500
517
|
await extractZip(archive, {dir: cacheDir});
|
|
518
|
+
// avoid driver copy failing if the file would be locked
|
|
519
|
+
await killDriverProcess(Edge.#DRIVER);
|
|
501
520
|
for (let destinationDir of [driverBinDir, driverLibDir]) {
|
|
502
521
|
await fs.promises.mkdir(destinationDir, {recursive: true});
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
path.join(destinationDir, driver));
|
|
506
|
-
}
|
|
507
|
-
catch (err) {
|
|
508
|
-
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/3
|
|
509
|
-
if (!err.toString().includes("copyfile"))
|
|
510
|
-
throw err;
|
|
511
|
-
}
|
|
522
|
+
await fs.promises.copyFile(path.join(cacheDir, driver),
|
|
523
|
+
path.join(destinationDir, driver));
|
|
512
524
|
}
|
|
513
525
|
}
|
|
514
526
|
|
|
@@ -516,9 +528,6 @@ class Edge {
|
|
|
516
528
|
static async getDriver(version, {headless = true, extensionPaths = [],
|
|
517
529
|
incognito = false, insecure = false,
|
|
518
530
|
extraArgs = []} = {}) {
|
|
519
|
-
if (incognito)
|
|
520
|
-
throw new Error(ERROR_INCOGNITO_NOT_SUPPORTED);
|
|
521
|
-
|
|
522
531
|
await Edge.#installDriver();
|
|
523
532
|
|
|
524
533
|
let args = ["no-sandbox", ...extraArgs];
|
|
@@ -526,6 +535,8 @@ class Edge {
|
|
|
526
535
|
args.push("headless");
|
|
527
536
|
if (extensionPaths.length > 0)
|
|
528
537
|
args.push(`load-extension=${extensionPaths.join(",")}`);
|
|
538
|
+
if (incognito)
|
|
539
|
+
args.push("incognito");
|
|
529
540
|
|
|
530
541
|
let builder = new webdriver.Builder();
|
|
531
542
|
builder.forBrowser("MicrosoftEdge");
|
|
@@ -538,6 +549,32 @@ class Edge {
|
|
|
538
549
|
|
|
539
550
|
return builder.build();
|
|
540
551
|
}
|
|
552
|
+
|
|
553
|
+
/** @see Browser.enableExtensionInIncognito */
|
|
554
|
+
static async enableExtensionInIncognito(driver, extensionTitle) {
|
|
555
|
+
let version = await getBrowserVersion(driver);
|
|
556
|
+
if (version < 79)
|
|
557
|
+
// The UI workaround needs a chromium based msedgedriver
|
|
558
|
+
throw new Error(`Only supported on Edge >= 79. Current version: ${version}`);
|
|
559
|
+
|
|
560
|
+
await driver.navigate().to("edge://extensions/");
|
|
561
|
+
for (let elem of await driver.findElements(By.css("[role=listitem]"))) {
|
|
562
|
+
let text = await elem.getAttribute("innerHTML");
|
|
563
|
+
if (!text.includes(extensionTitle))
|
|
564
|
+
continue;
|
|
565
|
+
|
|
566
|
+
for (let button of await elem.findElements(By.css("button"))) {
|
|
567
|
+
text = await elem.getAttribute("innerHTML");
|
|
568
|
+
if (!text.includes("Details"))
|
|
569
|
+
continue;
|
|
570
|
+
|
|
571
|
+
await button.click();
|
|
572
|
+
return await driver.findElement(By.id("itemAllowIncognito")).click();
|
|
573
|
+
}
|
|
574
|
+
throw new Error("Details button not found");
|
|
575
|
+
}
|
|
576
|
+
throw new Error(`Extension "${extensionTitle}" not found`);
|
|
577
|
+
}
|
|
541
578
|
}
|
|
542
579
|
|
|
543
580
|
|
package/src/utils.js
CHANGED
|
@@ -25,6 +25,12 @@ import got from "got";
|
|
|
25
25
|
import fsExtra from "fs-extra";
|
|
26
26
|
import dmg from "dmg";
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Downloads url resources.
|
|
30
|
+
* @param {string} url - The url of the resource to be downloaded.
|
|
31
|
+
* @param {string} destFile - The destination file path.
|
|
32
|
+
* @throws {TypeError} Invalid URL.
|
|
33
|
+
*/
|
|
28
34
|
export async function download(url, destFile) {
|
|
29
35
|
let cacheDir = path.dirname(destFile);
|
|
30
36
|
|
|
@@ -37,7 +43,11 @@ export async function download(url, destFile) {
|
|
|
37
43
|
await promisify(pipeline)(got.stream(url), writable);
|
|
38
44
|
}
|
|
39
45
|
catch (error) {
|
|
40
|
-
|
|
46
|
+
try {
|
|
47
|
+
await fs.promises.rm(tempDest, {recursive: true});
|
|
48
|
+
}
|
|
49
|
+
catch (e) {}
|
|
50
|
+
|
|
41
51
|
throw error;
|
|
42
52
|
}
|
|
43
53
|
|
|
@@ -78,3 +88,21 @@ export async function getBrowserVersion(driver) {
|
|
|
78
88
|
let version = (await driver.getCapabilities()).getBrowserVersion();
|
|
79
89
|
return parseInt(version.split(".")[0], 10);
|
|
80
90
|
}
|
|
91
|
+
|
|
92
|
+
export async function killDriverProcess(driverName) {
|
|
93
|
+
let cmd = `kill $(pgrep ${driverName})`;
|
|
94
|
+
let shell;
|
|
95
|
+
if (process.platform == "win32") {
|
|
96
|
+
cmd = `Get-Process -Name ${driverName} | Stop-Process; Start-Sleep 1`;
|
|
97
|
+
shell = "powershell.exe";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
await promisify(exec)(cmd, {shell});
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
// Command will fail when the driver process is not found
|
|
105
|
+
if (!err.toString().includes("Command failed"))
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -18,14 +18,12 @@
|
|
|
18
18
|
import fs from "fs";
|
|
19
19
|
import expect from "expect";
|
|
20
20
|
import path from "path";
|
|
21
|
-
import {exec} from "child_process";
|
|
22
|
-
import {promisify} from "util";
|
|
23
21
|
|
|
24
|
-
import {BROWSERS, snapshotsBaseDir} from "../
|
|
22
|
+
import {BROWSERS, snapshotsBaseDir} from "../index.js";
|
|
23
|
+
import {killDriverProcess} from "../src/utils.js";
|
|
25
24
|
|
|
26
|
-
// Required to
|
|
25
|
+
// Required to set the driver path on Windows
|
|
27
26
|
import "chromedriver";
|
|
28
|
-
import "geckodriver";
|
|
29
27
|
import "msedgedriver";
|
|
30
28
|
|
|
31
29
|
const VERSIONS = {
|
|
@@ -64,44 +62,10 @@ async function getHandle(driver, page) {
|
|
|
64
62
|
return handle;
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
async function killDriverProcess() {
|
|
68
|
-
for (let name of ["chromedriver", "msedgedriver"]) {
|
|
69
|
-
let stdout;
|
|
70
|
-
if (process.platform == "win32") {
|
|
71
|
-
try {
|
|
72
|
-
({stdout} = await promisify(exec)(
|
|
73
|
-
`(Get-Process -Name ${name}).Id | Stop-Process`,
|
|
74
|
-
{shell: "powershell.exe"}
|
|
75
|
-
));
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
if (err.toString().includes("Command failed"))
|
|
79
|
-
continue; // Command will fail when driver process is not found
|
|
80
|
-
|
|
81
|
-
throw err;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
try {
|
|
86
|
-
({stdout} =
|
|
87
|
-
await promisify(exec)(`ps -a | grep ${name} | grep -v grep`));
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
if (err.toString().includes("Command failed"))
|
|
91
|
-
continue; // Command will fail when driver process is not found
|
|
92
|
-
|
|
93
|
-
throw err;
|
|
94
|
-
}
|
|
95
|
-
let pid = /\s*(\d*)/.exec(stdout)[1]; // first number after any spaces
|
|
96
|
-
await promisify(exec)(`kill ${pid}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
65
|
for (let browser of Object.keys(BROWSERS)) {
|
|
102
66
|
for (let version of VERSIONS[browser]) {
|
|
103
67
|
describe(`Browser: ${browser} ${version || "latest"}`, function() {
|
|
104
|
-
this.timeout(
|
|
68
|
+
this.timeout(20000);
|
|
105
69
|
|
|
106
70
|
before(async() => {
|
|
107
71
|
try {
|
|
@@ -117,8 +81,9 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
117
81
|
|
|
118
82
|
await driver.quit();
|
|
119
83
|
driver = null;
|
|
120
|
-
// Some platforms don't immediately kill the
|
|
121
|
-
|
|
84
|
+
// Some platforms don't immediately kill the chromedriver process
|
|
85
|
+
if (browser == "chromium")
|
|
86
|
+
await killDriverProcess("chromedriver");
|
|
122
87
|
});
|
|
123
88
|
|
|
124
89
|
it("downloads", async function() {
|
|
@@ -163,9 +128,12 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
163
128
|
});
|
|
164
129
|
|
|
165
130
|
it("loads an extension in incognito mode", async function() {
|
|
166
|
-
if (browser
|
|
131
|
+
if (browser == "firefox" && version == "68.0")
|
|
167
132
|
this.skip();
|
|
168
133
|
|
|
134
|
+
if (process.platform == "win32")
|
|
135
|
+
this.timeout(30000);
|
|
136
|
+
|
|
169
137
|
driver = await BROWSERS[browser].getDriver(
|
|
170
138
|
version, {headless: false, extensionPaths, incognito: true});
|
|
171
139
|
await BROWSERS[browser].enableExtensionInIncognito(
|
package/test/utils.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2006-present eyeo GmbH
|
|
3
|
+
*
|
|
4
|
+
* This module is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from "fs";
|
|
19
|
+
import expect from "expect";
|
|
20
|
+
import path from "path";
|
|
21
|
+
|
|
22
|
+
import {snapshotsBaseDir, download} from "../index.js";
|
|
23
|
+
|
|
24
|
+
describe("Utils", () => {
|
|
25
|
+
it("defines a browser snapshots folder", () => expect(snapshotsBaseDir)
|
|
26
|
+
.toBe(path.join(process.cwd(), "browser-snapshots")));
|
|
27
|
+
|
|
28
|
+
let destFile = path.join(snapshotsBaseDir, "download-test.txt");
|
|
29
|
+
|
|
30
|
+
it("downloads resources", async() => {
|
|
31
|
+
let url = "https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/raw/main/package.json";
|
|
32
|
+
await download(url, destFile);
|
|
33
|
+
let contents = await fs.promises.readFile(destFile, {encoding: "utf8"});
|
|
34
|
+
expect(contents).toEqual(
|
|
35
|
+
expect.stringContaining("\"name\": \"@eyeo/get-browser-binary\""));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("does not download invalid resources", async() => {
|
|
39
|
+
expect(download("invalid", destFile)).rejects
|
|
40
|
+
.toThrow("TypeError [ERR_INVALID_URL]: Invalid URL");
|
|
41
|
+
});
|
|
42
|
+
});
|