@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eyeo/get-browser-binary",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Install browser binaries and matching webdrivers",
5
5
  "repository": {
6
6
  "type": "git",
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, the
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=[]] Loads extensions to the
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, killDriverProcess, getMajorVersion, checkVersion,
28
- checkPlatform, errMsg, snapshotsBaseDir, platformArch}
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
- let base = await Chromium.#getBase(versionNumber);
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, base};
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, base} = customBrowserBinary ?
198
+ let {binary, versionNumber} = customBrowserBinary ?
251
199
  await Chromium.#getInstalledBrowserInfo(customBrowserBinary) :
252
200
  await Chromium.installBrowser(version, downloadTimeout);
253
- let driverPath = await Chromium.#installDriver(base);
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
- // New headless mode introduced in Chrome 111
260
- // https://developer.chrome.com/articles/new-headless/
261
- if (getMajorVersion(versionNumber) >= 111)
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, platformArch}
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" : `microsoft-edge-${channel}`;
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 #installDriver(binary) {
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, driverBinary);
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(`/usr/bin/${binary}`);
257
+ options.setEdgeChromiumBinaryPath(binary);
264
258
 
265
259
  let builder = new webdriver.Builder();
266
260
  builder.forBrowser("MicrosoftEdge");
267
261
  builder.setEdgeOptions(options);
268
- builder.setEdgeService(serviceBuilder);
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
- let temporary = true; // Parameter not documented on the webdriver docs
188
- await driver.installAddon(extensionPath, temporary);
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 getCachedTimes(browser) {
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 != "edge") {
116
- let installTypes = [".zip", ".dmg", ".bz2"];
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
- let driverCacheTime = null;
124
- // geckodriver is installed by npm, that's why Firefox is not tested here
125
- if (browser != "firefox") {
126
- let driverDir = cacheFiles.find(
127
- elem => !elem.endsWith(".zip") && !elem.endsWith(".pkg"));
128
- let driverFiles = await fs.promises.readdir(path.join(cacheDir, driverDir));
129
- let driverZip = driverFiles.find(elem => elem.endsWith(".zip"));
130
- let driverStat =
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 {browserCTime: browserCacheTime, driverCTime: driverCacheTime};
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 emptyCacheTimes = null;
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
- // Adding the version number to the test title for logging purposes
212
- this.test.title = `${this.test.title} [v${versionNumber}]`;
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
- // When running all tests, this saves time on the cache test
221
- emptyCacheTimes = await getCachedTimes(browser);
213
+ let browserVersion =
214
+ (await driver.getCapabilities()).getBrowserVersion();
215
+ addVersionToTitle(this, browserVersion);
222
216
  });
223
217
 
224
- it("uses cached install files", async() => {
225
- if (emptyCacheTimes == null) { // Single test case run
226
- driver = await BROWSERS[browser].getDriver(version);
227
- emptyCacheTimes = await getCachedTimes(browser);
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 existingCacheTimes = await getCachedTimes(browser);
225
+ let secondInstallFileCTime = await getInstallFileCTime(browser);
234
226
 
235
- expect(existingCacheTimes).toEqual(emptyCacheTimes);
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.join(" ").split("-- ")[1];
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 -- ${args}`, {stdio: "inherit"});
61
+ execSync(`npm run test-suite ${args.join(" ")}`, {stdio: "inherit"});
60
62
  }
61
63
  finally {
62
64
  await killTestServer();