@eyeo/get-browser-binary 0.15.0 → 0.16.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 +1 -1
- package/RELEASE_NOTES.md +24 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/browser.js +5 -4
- package/src/chromium.js +18 -68
- package/src/edge.js +20 -18
- package/src/firefox.js +15 -4
- package/src/utils.js +19 -1
- package/test/browsers.js +44 -40
- package/test/runner.js +4 -2
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ the right side.
|
|
|
32
32
|
|
|
33
33
|
- Chromium >= 77 (Chromium ARM >= 92)
|
|
34
34
|
- Firefox >= 68
|
|
35
|
-
- Edge >= 95
|
|
35
|
+
- Edge >= 95 (Windows Edge >= 79)
|
|
36
36
|
|
|
37
37
|
Note: Installing Edge is not supported on Windows. It is assumed to be installed
|
|
38
38
|
because it is the default browser on that platform. On macOS, only the latest
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
# 0.16.0
|
|
2
|
+
|
|
3
|
+
- Starts using selenium's automated driver management (#67)
|
|
4
|
+
- Loads the extension in Firefox by local path instead of being copied to a
|
|
5
|
+
temporary folder (!104)
|
|
6
|
+
- Checks if extensions can be loaded beforehand, by ensuring they contain a
|
|
7
|
+
`manifest.json` file. If not, a new `Extension manifest file not found` error
|
|
8
|
+
will be thrown (#71)
|
|
9
|
+
- Refactors headless runs by not using webdriver's deprecated headless() method
|
|
10
|
+
(#72)
|
|
11
|
+
|
|
12
|
+
### Testing
|
|
13
|
+
|
|
14
|
+
- Fixes an issue with `npm test` which would fail when the `grep` option would
|
|
15
|
+
include parenthesis (#69)
|
|
16
|
+
- Adds the browser version information in the "runs" test (#74)
|
|
17
|
+
|
|
18
|
+
### Notes for integrators
|
|
19
|
+
|
|
20
|
+
- Please make sure that your selenium-webdriver package version is at least
|
|
21
|
+
4.15.0 (the one used in this release) (#67)
|
|
22
|
+
- If you experience chromedriver issues, try deleting the `/browser-snapshots`
|
|
23
|
+
cache folder.
|
|
24
|
+
|
|
1
25
|
# 0.15.0
|
|
2
26
|
|
|
3
27
|
- Fixes the downloads of Chromium versions < 91 by replacing the remaining
|
package/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import {Chromium} from "./src/chromium.js";
|
|
|
19
19
|
import {Firefox} from "./src/firefox.js";
|
|
20
20
|
import {Edge} from "./src/edge.js";
|
|
21
21
|
|
|
22
|
-
export {download, takeFullPageScreenshot, snapshotsBaseDir}
|
|
22
|
+
export {download, takeFullPageScreenshot, snapshotsBaseDir, getMajorVersion}
|
|
23
23
|
from "./src/utils.js";
|
|
24
24
|
|
|
25
25
|
/**
|
package/package.json
CHANGED
package/src/browser.js
CHANGED
|
@@ -84,11 +84,11 @@ export class Browser {
|
|
|
84
84
|
/**
|
|
85
85
|
* @typedef {Object} driverOptions
|
|
86
86
|
* @property {boolean} [headless=true] Run the browser in headless mode,
|
|
87
|
-
* or not. In Chromium >= 111
|
|
87
|
+
* or not. In Chromium >= 111 and Edge >= 114 the
|
|
88
88
|
* {@link https://developer.chrome.com/articles/new-headless/ new headless mode}
|
|
89
89
|
* is used.
|
|
90
|
-
* @property {Array.<string>} [extensionPaths=[]]
|
|
91
|
-
* browser.
|
|
90
|
+
* @property {Array.<string>} [extensionPaths=[]] Paths to folders containing
|
|
91
|
+
* unpacked extensions which will be loaded to the browser.
|
|
92
92
|
* @property {boolean} [incognito=false] Runs the browser in incognito mode,
|
|
93
93
|
* or not.
|
|
94
94
|
* @property {boolean} [insecure=false] Forces the browser to accept insecure
|
|
@@ -110,7 +110,8 @@ export class Browser {
|
|
|
110
110
|
* browser install files to complete. When set to 0 there is no time limit.
|
|
111
111
|
* @return {webdriver}
|
|
112
112
|
* @throws {Error} Unsupported browser version, Unsupported platform, Browser
|
|
113
|
-
* download failed, Driver download failed, Unable to start driver
|
|
113
|
+
* download failed, Driver download failed, Unable to start driver, Manifest
|
|
114
|
+
* file not found.
|
|
114
115
|
*/
|
|
115
116
|
static async getDriver(version, options = {}, downloadTimeout = 0) {
|
|
116
117
|
// to be implemented by the subclass
|
package/src/chromium.js
CHANGED
|
@@ -24,9 +24,8 @@ import chrome from "selenium-webdriver/chrome.js";
|
|
|
24
24
|
import extractZip from "extract-zip";
|
|
25
25
|
|
|
26
26
|
import {Browser} from "./browser.js";
|
|
27
|
-
import {download,
|
|
28
|
-
|
|
29
|
-
from "./utils.js";
|
|
27
|
+
import {download, getMajorVersion, checkVersion, checkPlatform, errMsg,
|
|
28
|
+
snapshotsBaseDir, platformArch, checkExtensionPaths} from "./utils.js";
|
|
30
29
|
|
|
31
30
|
/**
|
|
32
31
|
* Browser and webdriver functionality for Chromium.
|
|
@@ -116,8 +115,7 @@ export class Chromium extends Browser {
|
|
|
116
115
|
// Linux example: "Chromium 112.0.5615.49 built on Debian 11.6"
|
|
117
116
|
// Windows example: "114.0.5735.0"
|
|
118
117
|
let versionNumber = installedVersion.split(" ")[1] || installedVersion;
|
|
119
|
-
|
|
120
|
-
return {binary, versionNumber, base};
|
|
118
|
+
return {binary, versionNumber};
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
/**
|
|
@@ -134,14 +132,10 @@ export class Chromium extends Browser {
|
|
|
134
132
|
static async installBrowser(version = "latest", downloadTimeout = 0) {
|
|
135
133
|
const MIN_VERSION = process.arch == "arm64" ? 92 : 77;
|
|
136
134
|
|
|
137
|
-
let binary;
|
|
138
|
-
let versionNumber;
|
|
139
|
-
let base;
|
|
140
|
-
|
|
141
135
|
checkVersion(version, MIN_VERSION, Chromium.#CHANNELS);
|
|
142
|
-
versionNumber = await Chromium.#getVersionForChannel(version);
|
|
136
|
+
let versionNumber = await Chromium.#getVersionForChannel(version);
|
|
143
137
|
|
|
144
|
-
base = await Chromium.#getBase(versionNumber);
|
|
138
|
+
let base = await Chromium.#getBase(versionNumber);
|
|
145
139
|
let startBase = base;
|
|
146
140
|
let [platformDir, fileName] = {
|
|
147
141
|
"win32-ia32": ["Win", "chrome-win.zip"],
|
|
@@ -154,6 +148,7 @@ export class Chromium extends Browser {
|
|
|
154
148
|
let browserDir;
|
|
155
149
|
let snapshotsDir = path.join(snapshotsBaseDir, "chromium");
|
|
156
150
|
|
|
151
|
+
let binary;
|
|
157
152
|
while (true) {
|
|
158
153
|
browserDir = path.join(snapshotsDir, `chromium-${platformArch}-${base}`);
|
|
159
154
|
binary = Chromium.#getBinaryPath(browserDir);
|
|
@@ -192,54 +187,7 @@ export class Chromium extends Browser {
|
|
|
192
187
|
}
|
|
193
188
|
await extractZip(archive, {dir: browserDir});
|
|
194
189
|
|
|
195
|
-
return {binary, versionNumber
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
static async #installDriver(startBase) {
|
|
199
|
-
let [dir, zip, driverBinary] = {
|
|
200
|
-
"win32-ia32": ["Win", "chromedriver_win32.zip", "chromedriver.exe"],
|
|
201
|
-
"win32-x64": ["Win_x64", "chromedriver_win32.zip", "chromedriver.exe"],
|
|
202
|
-
"linux-x64": ["Linux_x64", "chromedriver_linux64.zip", "chromedriver"],
|
|
203
|
-
"darwin-x64": ["Mac", "chromedriver_mac64.zip", "chromedriver"],
|
|
204
|
-
"darwin-arm64": ["Mac_Arm", "chromedriver_mac64.zip", "chromedriver"]
|
|
205
|
-
}[platformArch];
|
|
206
|
-
|
|
207
|
-
let cacheDir = path.join(snapshotsBaseDir, "chromium", "cache",
|
|
208
|
-
"chromedriver");
|
|
209
|
-
let archive = path.join(cacheDir, `${startBase}-${zip}`);
|
|
210
|
-
try {
|
|
211
|
-
await fs.promises.access(archive);
|
|
212
|
-
await extractZip(archive, {dir: cacheDir});
|
|
213
|
-
}
|
|
214
|
-
catch (e) { // zip file is either not cached or corrupted
|
|
215
|
-
let base = startBase;
|
|
216
|
-
while (true) {
|
|
217
|
-
let url = `https://commondatastorage.googleapis.com/chromium-browser-snapshots/${dir}/${base}/${zip}`;
|
|
218
|
-
try {
|
|
219
|
-
await download(url, archive);
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
catch (err) {
|
|
223
|
-
if (err.name == "HTTPError") {
|
|
224
|
-
base--;
|
|
225
|
-
archive = path.join(cacheDir, `${base}-${zip}`);
|
|
226
|
-
if (base <= startBase - Chromium.#MAX_VERSION_DECREMENTS)
|
|
227
|
-
throw new Error(`${errMsg.driverDownload}: Chromium base ${startBase}`);
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
throw new Error(`${errMsg.driverDownload}: ${url}\n${err}`);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
await extractZip(archive, {dir: cacheDir});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
await killDriverProcess("chromedriver");
|
|
238
|
-
let driverPath = path.join(cacheDir, zip.split(".")[0], driverBinary);
|
|
239
|
-
await fs.promises.rm(driverPath, {force: true});
|
|
240
|
-
await extractZip(archive, {dir: cacheDir});
|
|
241
|
-
|
|
242
|
-
return driverPath;
|
|
190
|
+
return {binary, versionNumber};
|
|
243
191
|
}
|
|
244
192
|
|
|
245
193
|
/** @see Browser.getDriver */
|
|
@@ -247,21 +195,24 @@ export class Chromium extends Browser {
|
|
|
247
195
|
headless = true, extensionPaths = [], incognito = false, insecure = false,
|
|
248
196
|
extraArgs = [], customBrowserBinary
|
|
249
197
|
} = {}, downloadTimeout = 0) {
|
|
250
|
-
let {binary, versionNumber
|
|
198
|
+
let {binary, versionNumber} = customBrowserBinary ?
|
|
251
199
|
await Chromium.#getInstalledBrowserInfo(customBrowserBinary) :
|
|
252
200
|
await Chromium.installBrowser(version, downloadTimeout);
|
|
253
|
-
|
|
254
|
-
let serviceBuilder = new chrome.ServiceBuilder(driverPath);
|
|
201
|
+
|
|
255
202
|
let options = new chrome.Options().addArguments("no-sandbox", ...extraArgs);
|
|
256
|
-
if (extensionPaths.length > 0)
|
|
203
|
+
if (extensionPaths.length > 0) {
|
|
204
|
+
await checkExtensionPaths(extensionPaths);
|
|
257
205
|
options.addArguments(`load-extension=${extensionPaths.join(",")}`);
|
|
206
|
+
}
|
|
258
207
|
if (headless) {
|
|
259
|
-
|
|
260
|
-
// https://
|
|
261
|
-
if (
|
|
208
|
+
let majorVersion = getMajorVersion(versionNumber);
|
|
209
|
+
// https://www.selenium.dev/blog/2023/headless-is-going-away/
|
|
210
|
+
if (majorVersion >= 109)
|
|
262
211
|
options.addArguments("headless=new");
|
|
212
|
+
else if (majorVersion >= 96)
|
|
213
|
+
options.addArguments("headless=chrome");
|
|
263
214
|
else
|
|
264
|
-
options.headless
|
|
215
|
+
options.addArguments("headless");
|
|
265
216
|
}
|
|
266
217
|
if (insecure)
|
|
267
218
|
options.addArguments("ignore-certificate-errors");
|
|
@@ -272,7 +223,6 @@ export class Chromium extends Browser {
|
|
|
272
223
|
let builder = new webdriver.Builder();
|
|
273
224
|
builder.forBrowser("chrome");
|
|
274
225
|
builder.setChromeOptions(options);
|
|
275
|
-
builder.setChromeService(serviceBuilder);
|
|
276
226
|
|
|
277
227
|
return builder.build();
|
|
278
228
|
}
|
package/src/edge.js
CHANGED
|
@@ -27,7 +27,7 @@ import extractZip from "extract-zip";
|
|
|
27
27
|
|
|
28
28
|
import {Browser} from "./browser.js";
|
|
29
29
|
import {download, killDriverProcess, wait, getMajorVersion, checkVersion,
|
|
30
|
-
checkPlatform, errMsg, snapshotsBaseDir,
|
|
30
|
+
checkPlatform, errMsg, snapshotsBaseDir, checkExtensionPaths}
|
|
31
31
|
from "./utils.js";
|
|
32
32
|
|
|
33
33
|
let {By} = webdriver;
|
|
@@ -93,7 +93,7 @@ export class Edge extends Browser {
|
|
|
93
93
|
return `${programFiles}\\Microsoft\\Edge\\Application\\msedge.exe`;
|
|
94
94
|
case "linux":
|
|
95
95
|
return channel == "stable" ?
|
|
96
|
-
"microsoft-edge" :
|
|
96
|
+
"/usr/bin/microsoft-edge" : `/usr/bin/microsoft-edge-${channel}`;
|
|
97
97
|
case "darwin":
|
|
98
98
|
return `${process.env.HOME}/Applications/${Edge.#darwinApp}.app/Contents/MacOS/${Edge.#darwinApp}`;
|
|
99
99
|
default:
|
|
@@ -179,7 +179,7 @@ export class Edge extends Browser {
|
|
|
179
179
|
return installedVersion.trim().replace(/.*\s/, "");
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
static async #
|
|
182
|
+
static async #installOldWindowsDriver(binary) {
|
|
183
183
|
async function extractEdgeZip(archive, cacheDir, driverPath) {
|
|
184
184
|
await killDriverProcess("msedgedriver");
|
|
185
185
|
await fs.promises.rm(driverPath, {force: true});
|
|
@@ -188,17 +188,12 @@ export class Edge extends Browser {
|
|
|
188
188
|
|
|
189
189
|
let binaryPath = binary || Edge.#getBinaryPath();
|
|
190
190
|
let versionNumber = await Edge.#getInstalledVersionNumber(binaryPath);
|
|
191
|
-
let [zip, driverBinary] = {
|
|
192
|
-
"win32-ia32": ["edgedriver_win32.zip", "msedgedriver.exe"],
|
|
193
|
-
"win32-x64": ["edgedriver_win64.zip", "msedgedriver.exe"],
|
|
194
|
-
"linux-x64": ["edgedriver_linux64.zip", "msedgedriver"],
|
|
195
|
-
"darwin-x64": ["edgedriver_mac64.zip", "msedgedriver"],
|
|
196
|
-
"darwin-arm64": ["edgedriver_mac64_m1.zip", "msedgedriver"]
|
|
197
|
-
}[platformArch];
|
|
198
191
|
let cacheDir = path.join(snapshotsBaseDir, "edge", "cache",
|
|
199
192
|
`edgedriver-${versionNumber}`);
|
|
193
|
+
let zip = process.arch == "ia32" ?
|
|
194
|
+
"edgedriver_win32.zip" : "edgedriver_win64.zip";
|
|
200
195
|
let archive = path.join(cacheDir, `${versionNumber}-${zip}`);
|
|
201
|
-
let driverPath = path.join(cacheDir,
|
|
196
|
+
let driverPath = path.join(cacheDir, "msedgedriver.exe");
|
|
202
197
|
|
|
203
198
|
try {
|
|
204
199
|
await fs.promises.access(archive);
|
|
@@ -243,29 +238,36 @@ export class Edge extends Browser {
|
|
|
243
238
|
await Edge.#getInstalledVersionNumber(binary);
|
|
244
239
|
}
|
|
245
240
|
|
|
246
|
-
let driverPath = await Edge.#installDriver(binary);
|
|
247
|
-
let serviceBuilder = new edge.ServiceBuilder(driverPath);
|
|
248
|
-
|
|
249
241
|
let options = new edge.Options().addArguments("no-sandbox", ...extraArgs);
|
|
250
242
|
if (headless) {
|
|
251
243
|
if (versionNumber && getMajorVersion(versionNumber) >= 114)
|
|
252
244
|
options.addArguments("headless=new");
|
|
253
245
|
else
|
|
254
|
-
options.headless
|
|
246
|
+
options.addArguments("headless");
|
|
255
247
|
}
|
|
256
|
-
if (extensionPaths.length > 0)
|
|
248
|
+
if (extensionPaths.length > 0) {
|
|
249
|
+
await checkExtensionPaths(extensionPaths);
|
|
257
250
|
options.addArguments(`load-extension=${extensionPaths.join(",")}`);
|
|
251
|
+
}
|
|
258
252
|
if (incognito)
|
|
259
253
|
options.addArguments("inprivate");
|
|
260
254
|
if (insecure)
|
|
261
255
|
options.addArguments("ignore-certificate-errors");
|
|
262
256
|
if (platform == "linux")
|
|
263
|
-
options.setEdgeChromiumBinaryPath(
|
|
257
|
+
options.setEdgeChromiumBinaryPath(binary);
|
|
264
258
|
|
|
265
259
|
let builder = new webdriver.Builder();
|
|
266
260
|
builder.forBrowser("MicrosoftEdge");
|
|
267
261
|
builder.setEdgeOptions(options);
|
|
268
|
-
|
|
262
|
+
|
|
263
|
+
if (getMajorVersion(versionNumber) < 95) {
|
|
264
|
+
// Selenium's automated driver download doesn't work on old Edge versions.
|
|
265
|
+
// Support to installing old drivers is only needed by Windows CI jobs.
|
|
266
|
+
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/2#note_1189235804
|
|
267
|
+
let driverPath = await Edge.#installOldWindowsDriver(binary);
|
|
268
|
+
let serviceBuilder = new edge.ServiceBuilder(driverPath);
|
|
269
|
+
builder.setEdgeService(serviceBuilder);
|
|
270
|
+
}
|
|
269
271
|
|
|
270
272
|
let driver;
|
|
271
273
|
// On Windows CI, occasionally a SessionNotCreatedError is thrown, likely
|
package/src/firefox.js
CHANGED
|
@@ -23,11 +23,12 @@ import fs from "fs";
|
|
|
23
23
|
import got from "got";
|
|
24
24
|
import webdriver from "selenium-webdriver";
|
|
25
25
|
import firefox from "selenium-webdriver/firefox.js";
|
|
26
|
+
import {Command} from "selenium-webdriver/lib/command.js";
|
|
26
27
|
|
|
27
28
|
import {Browser} from "./browser.js";
|
|
28
29
|
import {download, extractTar, extractDmg, killDriverProcess, wait,
|
|
29
30
|
getMajorVersion, checkVersion, checkPlatform, errMsg, snapshotsBaseDir,
|
|
30
|
-
platformArch} from "./utils.js";
|
|
31
|
+
platformArch, checkExtensionPaths} from "./utils.js";
|
|
31
32
|
|
|
32
33
|
let {until, By} = webdriver;
|
|
33
34
|
|
|
@@ -152,7 +153,7 @@ export class Firefox extends Browser {
|
|
|
152
153
|
|
|
153
154
|
let options = new firefox.Options();
|
|
154
155
|
if (headless)
|
|
155
|
-
options.headless
|
|
156
|
+
options.addArguments("--headless");
|
|
156
157
|
if (incognito)
|
|
157
158
|
options.addArguments("--private");
|
|
158
159
|
if (insecure)
|
|
@@ -184,8 +185,18 @@ export class Firefox extends Browser {
|
|
|
184
185
|
}, 30000, `${errMsg.driverStart}: geckodriver`, 1000);
|
|
185
186
|
|
|
186
187
|
for (let extensionPath of extensionPaths) {
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
await checkExtensionPaths([extensionPath]);
|
|
189
|
+
|
|
190
|
+
// This is based on Selenium's Firefox `installAddon` function. Rather
|
|
191
|
+
// than setting the "addon" parameter, which is the actual extension
|
|
192
|
+
// base64 encoded, we need to set the "path" which is the filepath to the
|
|
193
|
+
// extension. This allows downstream to test upgrade paths by updating the
|
|
194
|
+
// extension source code and reloading it.
|
|
195
|
+
// See https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/node/selenium-webdriver/firefox.js
|
|
196
|
+
await driver.execute(
|
|
197
|
+
new Command("install addon")
|
|
198
|
+
.setParameter("path", extensionPath)
|
|
199
|
+
.setParameter("temporary", true));
|
|
189
200
|
}
|
|
190
201
|
return driver;
|
|
191
202
|
}
|
package/src/utils.js
CHANGED
|
@@ -34,7 +34,8 @@ export const errMsg = {
|
|
|
34
34
|
browserDownload: "Browser download failed",
|
|
35
35
|
browserNotInstalled: "Browser is not installed",
|
|
36
36
|
browserVersionCheck: "Checking the browser version failed",
|
|
37
|
-
elemNotFound: "HTML element not found"
|
|
37
|
+
elemNotFound: "HTML element not found",
|
|
38
|
+
manifestNotFound: "Extension manifest file not found"
|
|
38
39
|
};
|
|
39
40
|
export const platformArch = `${process.platform}-${process.arch}`;
|
|
40
41
|
|
|
@@ -238,6 +239,12 @@ export async function takeFullPageScreenshot(driver, hideScrollbars = true) {
|
|
|
238
239
|
return fullScreenshot;
|
|
239
240
|
}
|
|
240
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Returns the major version of a browser version number.
|
|
244
|
+
* @param {string} versionNumber Full browser version number.
|
|
245
|
+
* @return {number} Major version number.
|
|
246
|
+
* @throws {Error} Unsupported browser version.
|
|
247
|
+
*/
|
|
241
248
|
export function getMajorVersion(versionNumber) {
|
|
242
249
|
let majorVersion = parseInt(versionNumber && versionNumber.split(".")[0], 10);
|
|
243
250
|
if (isNaN(majorVersion))
|
|
@@ -258,3 +265,14 @@ export function checkPlatform() {
|
|
|
258
265
|
if (!["win32", "linux", "darwin"].includes(process.platform))
|
|
259
266
|
throw new Error(`${errMsg.unsupportedPlatform}: ${process.platform}`);
|
|
260
267
|
}
|
|
268
|
+
|
|
269
|
+
export async function checkExtensionPaths(extensionPaths) {
|
|
270
|
+
for (let extensionPath of extensionPaths) {
|
|
271
|
+
try {
|
|
272
|
+
await fs.promises.access(path.join(extensionPath, "manifest.json"));
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
throw new Error(`${errMsg.manifestNotFound}: ${extensionPath}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
package/test/browsers.js
CHANGED
|
@@ -25,8 +25,6 @@ import {BROWSERS, snapshotsBaseDir, takeFullPageScreenshot} from "../index.js";
|
|
|
25
25
|
import {killDriverProcess} from "../src/utils.js";
|
|
26
26
|
import {TEST_SERVER_URL} from "./test-server.js";
|
|
27
27
|
|
|
28
|
-
import "geckodriver"; // Required to set the driver path on Windows
|
|
29
|
-
|
|
30
28
|
const VERSIONS = {
|
|
31
29
|
chromium: ["latest", "77.0.3865.0", "beta", "dev"],
|
|
32
30
|
firefox: ["latest", "68.0", "beta"],
|
|
@@ -106,33 +104,21 @@ function getExtension(browser, version) {
|
|
|
106
104
|
return {extensionPaths, manifest};
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
async function
|
|
110
|
-
let cacheDir = path.join(snapshotsBaseDir, browser, "cache");
|
|
111
|
-
let cacheFiles = await fs.promises.readdir(cacheDir);
|
|
112
|
-
|
|
113
|
-
let browserCacheTime = null;
|
|
107
|
+
async function getInstallFileCTime(browser) {
|
|
114
108
|
// Browsers installed at OS level are not tested
|
|
115
|
-
if (browser
|
|
116
|
-
|
|
117
|
-
let browserZip =
|
|
118
|
-
cacheFiles.find(elem => installTypes.some(type => elem.includes(type)));
|
|
119
|
-
let browserStat = await fs.promises.stat(path.join(cacheDir, browserZip));
|
|
120
|
-
browserCacheTime = browserStat.ctimeMs;
|
|
121
|
-
}
|
|
109
|
+
if (browser == "edge" && process.platform == "win32")
|
|
110
|
+
return null;
|
|
122
111
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
await fs.promises.stat(path.join(cacheDir, driverDir, driverZip));
|
|
132
|
-
driverCacheTime = driverStat.ctimeMs;
|
|
133
|
-
}
|
|
112
|
+
const installTypes = [".zip", ".dmg", ".bz2", ".deb", ".exe"];
|
|
113
|
+
|
|
114
|
+
let cacheDir = path.join(snapshotsBaseDir, browser, "cache");
|
|
115
|
+
let cacheFiles = await fs.promises.readdir(cacheDir);
|
|
116
|
+
let browserZip =
|
|
117
|
+
cacheFiles.find(elem => installTypes.some(type => elem.includes(type)));
|
|
118
|
+
if (!browserZip)
|
|
119
|
+
throw new Error(`Files in ${cacheDir} don't belong to any known install file types: ${installTypes}`);
|
|
134
120
|
|
|
135
|
-
return
|
|
121
|
+
return (await fs.promises.stat(path.join(cacheDir, browserZip))).ctimeMs;
|
|
136
122
|
}
|
|
137
123
|
|
|
138
124
|
const browserNames = {
|
|
@@ -150,6 +136,11 @@ async function basicUrlTest(driver, browser) {
|
|
|
150
136
|
expect(text).toEqual("Test server basic page");
|
|
151
137
|
}
|
|
152
138
|
|
|
139
|
+
// Adding the browser version to the test title for logging purposes
|
|
140
|
+
function addVersionToTitle(ctx, version) {
|
|
141
|
+
ctx.test.title = `${ctx.test.title} [v${version}]`;
|
|
142
|
+
}
|
|
143
|
+
|
|
153
144
|
for (let browser of Object.keys(BROWSERS)) {
|
|
154
145
|
describe(`Browser: ${browser}`, () => {
|
|
155
146
|
before(async() => {
|
|
@@ -162,7 +153,7 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
162
153
|
for (let version of VERSIONS[browser]) {
|
|
163
154
|
describe(`Version: ${version}`, () => {
|
|
164
155
|
let driver = null;
|
|
165
|
-
let
|
|
156
|
+
let firstInstallFileCTime = null;
|
|
166
157
|
let customBrowserBinary = null;
|
|
167
158
|
let failedInstall = false;
|
|
168
159
|
|
|
@@ -208,31 +199,32 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
208
199
|
expect(installedVersion).toEqual(
|
|
209
200
|
expect.stringContaining(normalize(versionNumber)));
|
|
210
201
|
|
|
211
|
-
|
|
212
|
-
|
|
202
|
+
addVersionToTitle(this, versionNumber);
|
|
203
|
+
|
|
204
|
+
// Data used in further tests
|
|
213
205
|
customBrowserBinary = binary;
|
|
206
|
+
firstInstallFileCTime = await getInstallFileCTime(browser);
|
|
214
207
|
});
|
|
215
208
|
|
|
216
|
-
it("runs", async()
|
|
209
|
+
it("runs", async function() {
|
|
217
210
|
driver = await BROWSERS[browser].getDriver(version);
|
|
218
211
|
await basicUrlTest(driver, browser);
|
|
219
212
|
|
|
220
|
-
|
|
221
|
-
|
|
213
|
+
let browserVersion =
|
|
214
|
+
(await driver.getCapabilities()).getBrowserVersion();
|
|
215
|
+
addVersionToTitle(this, browserVersion);
|
|
222
216
|
});
|
|
223
217
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
await quitDriver();
|
|
229
|
-
}
|
|
218
|
+
// This test depends on running the "installs" test
|
|
219
|
+
it("uses cached install files", async function() {
|
|
220
|
+
if (!firstInstallFileCTime)
|
|
221
|
+
this.skip();
|
|
230
222
|
|
|
231
223
|
// assigning `driver` to allow the afterEach hook quit the driver
|
|
232
224
|
driver = await BROWSERS[browser].getDriver(version);
|
|
233
|
-
let
|
|
225
|
+
let secondInstallFileCTime = await getInstallFileCTime(browser);
|
|
234
226
|
|
|
235
|
-
expect(
|
|
227
|
+
expect(secondInstallFileCTime).toEqual(firstInstallFileCTime);
|
|
236
228
|
});
|
|
237
229
|
|
|
238
230
|
// This test depends on running the "installs" test
|
|
@@ -279,6 +271,11 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
279
271
|
expect(fullImg.bitmap.height).toBeGreaterThan(partImg.bitmap.height);
|
|
280
272
|
});
|
|
281
273
|
|
|
274
|
+
// The only reason the geckodriver package is required in package.json
|
|
275
|
+
// is to install a specific version needed by Firefox 68.0, otherwise it
|
|
276
|
+
// fails to load extensions. When the oldest Firefox version is bumped,
|
|
277
|
+
// Selenium's automated driver download should be able to manage it.
|
|
278
|
+
// https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/44
|
|
282
279
|
it("loads an extension", async() => {
|
|
283
280
|
// Chromium's old headless mode doesn't support loading extensions
|
|
284
281
|
let headless = browser == "firefox" || (browser == "chromium" &&
|
|
@@ -314,5 +311,12 @@ for (let browser of Object.keys(BROWSERS)) {
|
|
|
314
311
|
.rejects.toThrow(`Unsupported browser version: ${unsupported}`);
|
|
315
312
|
}
|
|
316
313
|
});
|
|
314
|
+
|
|
315
|
+
it("does not load an invalid extension", async() => {
|
|
316
|
+
let extensionPaths = [process.cwd()];
|
|
317
|
+
|
|
318
|
+
await expect(BROWSERS[browser].getDriver("latest", {extensionPaths}))
|
|
319
|
+
.rejects.toThrow(`Extension manifest file not found: ${extensionPaths[0]}`);
|
|
320
|
+
});
|
|
317
321
|
});
|
|
318
322
|
}
|
package/test/runner.js
CHANGED
|
@@ -53,10 +53,12 @@ export async function killTestServer() {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async function run() {
|
|
56
|
-
let args = process.argv.
|
|
56
|
+
let args = process.argv.slice(2); // Keep npm args from "--" onwards
|
|
57
|
+
args = args.map(v => v.startsWith("-") ? v : `"${v}"`);
|
|
58
|
+
|
|
57
59
|
await runTestServer();
|
|
58
60
|
try {
|
|
59
|
-
execSync(`npm run test-suite
|
|
61
|
+
execSync(`npm run test-suite ${args.join(" ")}`, {stdio: "inherit"});
|
|
60
62
|
}
|
|
61
63
|
finally {
|
|
62
64
|
await killTestServer();
|