@eyeo/get-browser-binary 0.22.0 → 0.23.1

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 CHANGED
@@ -57,19 +57,16 @@ test:browsers:linux:dev:
57
57
  test:browsers:windows:
58
58
  extends: .windows
59
59
  script:
60
- # Running Edge tests only on the preinstalled version
61
- # https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/29
62
- - npm test "--" --grep "edge.*latest"
60
+ - npm test "--" --grep "^.*edge((?!Version:.dev).)*$"
63
61
  # Chromium excluded until this is fixed: https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/87
64
62
  # - npm test "--" --grep "^.*chromium((?!Version:.dev).)*$"
65
- # Running only a subset of Firefox tests to avoid low OS resources error
66
- # https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/2
67
63
  # Firefox excluded until this is fixed: https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/87
68
64
  # - npm test "--" --grep "firefox.*installs"
69
65
 
70
66
  test:browsers:windows:dev:
71
67
  extends: .windows
72
68
  script:
69
+ - npm test "--" --grep "edge.*Version:.dev"
73
70
  - npm test "--" --grep "chromium.*Version:.dev"
74
71
  allow_failure: true
75
72
 
@@ -84,8 +81,7 @@ test:browsers:macos:
84
81
  - npm install
85
82
  script:
86
83
  # Only checking that latest browsers can be installed on macOS
87
- # Edge excluded until this is fixed: https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/88
88
- - npm test -- -g "(chromium|firefox).*latest.*installs"
84
+ - npm test -- -g ".*latest.*installs"
89
85
 
90
86
  docs:
91
87
  stage: docs
package/README.md CHANGED
@@ -32,11 +32,7 @@ the right side.
32
32
 
33
33
  - Chromium >= 77 (Chromium ARM >= 92)
34
34
  - Firefox >= 68
35
- - Edge >= 114
36
-
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. On macOS, only the latest
39
- Edge version is supported.
35
+ - Edge >= 114 (Linux), Edge >= latest (MacOS, Windows)
40
36
 
41
37
  ### Verbose logging
42
38
 
package/RELEASE_NOTES.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Unreleased
2
2
 
3
+ # 0.23.1
4
+
5
+ - Re-enables local network access checks on Chromium v.139 (!149)
6
+
7
+ # 0.23.0
8
+
9
+ - Adds beta and dev channels to Edge on Windows and MacOS (#29)
10
+ - Fixes edge driver location (!145)
11
+
3
12
  # 0.22.0
4
13
 
5
14
  - Adds macOS CI job (!141)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eyeo/get-browser-binary",
3
- "version": "0.22.0",
3
+ "version": "0.23.1",
4
4
  "description": "Install browser binaries and matching webdrivers",
5
5
  "repository": {
6
6
  "type": "git",
package/src/chromium.js CHANGED
@@ -248,8 +248,6 @@ export class Chromium extends Browser {
248
248
  await checkExtensionPaths(extensionPaths);
249
249
  options.addArguments(`load-extension=${extensionPaths.join(",")}`);
250
250
  }
251
- if (majorVersion >= 139)
252
- options.addArguments("--disable-features=LocalNetworkAccessChecks");
253
251
  if (headless) {
254
252
  // https://www.selenium.dev/blog/2023/headless-is-going-away/
255
253
  if (majorVersion >= 109)
package/src/edge.js CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import path from "path";
19
- import {exec} from "child_process";
19
+ import {exec, spawn} from "child_process";
20
20
  import {promisify} from "util";
21
21
  import fs from "fs";
22
22
 
@@ -25,9 +25,8 @@ import {until, By, Builder} from "selenium-webdriver";
25
25
  import edge from "selenium-webdriver/edge.js";
26
26
 
27
27
  import {Browser} from "./browser.js";
28
- import {download, killDriverProcess, wait, getMajorVersion, checkVersion,
29
- checkPlatform, errMsg, snapshotsBaseDir, checkExtensionPaths}
30
- from "./utils.js";
28
+ import {download, getMajorVersion, checkVersion, checkPlatform, errMsg,
29
+ snapshotsBaseDir, checkExtensionPaths, platformArch} from "./utils.js";
31
30
 
32
31
  let {platform} = process;
33
32
 
@@ -105,24 +104,34 @@ export class Edge extends Browser {
105
104
  return {versionNumber, channel};
106
105
  }
107
106
 
108
- static #getDarwinApp(channel = "stable") {
109
- const firstUppercase =
110
- String(channel).charAt(0).toUpperCase() + String(channel).slice(1);
111
- return channel === "stable" ? "Microsoft Edge" : `Microsoft Edge ${firstUppercase}`;
107
+ static #appName(channel) {
108
+ const channels = {stable: "", beta: " Beta", dev: " Dev"};
109
+
110
+ if (platform == "linux") {
111
+ return channel == "stable" ?
112
+ "microsoft-edge" : `microsoft-edge-${channel}`;
113
+ }
114
+ else if (platform == "darwin") {
115
+ return `Microsoft Edge${channels[channel]}`;
116
+ }
117
+ else if (platform == "win32") {
118
+ return `"Edge${channels[channel]}"`;
119
+ }
112
120
  }
113
121
 
114
122
  static #getBinaryPath(channel = "stable") {
115
123
  switch (platform) {
116
124
  case "win32":
117
- const programFiles = process.env["ProgramFiles(x86)"] ?
118
- "${Env:ProgramFiles(x86)}" : "${Env:ProgramFiles}";
119
- return `${programFiles}\\Microsoft\\Edge\\Application\\msedge.exe`;
125
+ return path.join("C:", "\"Program Files (x86)\"", "Microsoft",
126
+ Edge.#appName(channel), "Application", "msedge.exe");
120
127
  case "linux":
121
- return channel == "stable" ?
122
- "/usr/bin/microsoft-edge" : `/usr/bin/microsoft-edge-${channel}`;
128
+ return path.join("/usr", "bin", Edge.#appName(channel));
123
129
  case "darwin":
124
- const darwinApp = Edge.#getDarwinApp(channel);
125
- return `${process.env.HOME}/Applications/${darwinApp}.app/Contents/MacOS/${darwinApp}`;
130
+ // Root path may no longer be needed after switching to custom runners
131
+ // https://eyeo.atlassian.net/browse/DOPE-8
132
+ const homePath = process.env.CI === "true" ? "/" : process.env.HOME;
133
+ return path.join(homePath, "Applications", `${Edge.#appName(channel)}.app`,
134
+ "Contents", "MacOS", Edge.#appName(channel));
126
135
  default:
127
136
  checkPlatform();
128
137
  }
@@ -141,43 +150,61 @@ export class Edge extends Browser {
141
150
  * download failed.
142
151
  */
143
152
  static async installBrowser(version = "latest", downloadTimeout = 0) {
144
- if (platform == "win32")
145
- // Edge is mandatory on Windows, can't be uninstalled or downgraded
146
- // https://support.microsoft.com/en-us/microsoft-edge/why-can-t-i-uninstall-microsoft-edge-ee150b3b-7d7a-9984-6d83-eb36683d526d
147
- throw new Error(`${errMsg.unsupportedPlatform}: ${platform}`);
148
-
149
- if (platform == "darwin" && !/latest|beta|dev/.test(version))
150
- throw new Error(`${errMsg.unsupportedVersion}: ${version}. Only "latest", "beta" or "dev" are supported`);
151
-
152
153
  checkVersion(version, Edge.#MIN_VERSION, Edge.#CHANNELS);
153
- let {versionNumber, channel} = await Edge.#getVersionForChannel(version);
154
-
155
- let filename = {
156
- linux: `microsoft-edge-${channel}_${versionNumber}-1_amd64.deb`,
157
- darwin: `MicrosoftEdge-${versionNumber}.pkg`
158
- }[platform];
154
+ if (!Edge.#CHANNELS.includes(version) && platform != "linux")
155
+ throw new Error(`${errMsg.unsupportedVersion}: ${version}. Supported versions: ${Edge.#CHANNELS.join(",")}`);
159
156
 
160
- let snapshotsDir = path.join(snapshotsBaseDir, "edge");
161
- let archive = path.join(snapshotsDir, "cache", filename);
157
+ let {versionNumber, channel} = await Edge.#getVersionForChannel(version);
162
158
  let binary = Edge.#getBinaryPath(channel);
159
+
160
+ // Patch versions differ between Debian repo and Enterprise API.
161
+ // We treat same-major versions as installed to avoid re-downloads.
162
+ // Applies to both channel builds and numeric Linux versions.
163
163
  try {
164
- if (await Edge.getInstalledVersion(binary) == versionNumber)
165
- return {binary, versionNumber};
164
+ const installedVersion = await Edge.getInstalledVersion(binary);
165
+ if (getMajorVersion(installedVersion) == getMajorVersion(versionNumber))
166
+ return {binary, versionNumber: installedVersion};
166
167
  }
167
168
  catch (e) {}
168
169
 
169
- let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`;
170
- try {
171
- if (platform == "darwin") {
172
- const caskFile = channel === "stable" ? "microsoft-edge.json" : `microsoft-edge@${channel}.json`;
173
- const caskUrl = `https://formulae.brew.sh/api/cask/${caskFile}`;
174
- try {
175
- ({url} = await got(caskUrl).json());
176
- }
177
- catch (err) {
178
- throw new Error(`${errMsg.browserVersionCheck}: ${caskUrl}\n${err}`);
179
- }
170
+ const [plat, arch, ext] = {
171
+ "win32-ia32": ["Windows", "x86", ".msi"],
172
+ "win32-x64": ["Windows", "x64", ".msi"],
173
+ "linux-x64": ["Linux", "x64", ".deb"],
174
+ "darwin-x64": ["MacOS", "universal", ".pkg"],
175
+ "darwin-arm64": ["MacOS", "universal", ".pkg"]
176
+ }[platformArch];
177
+
178
+ let url;
179
+ let filename;
180
+ const downloadChannels = {latest: "Stable", beta: "Beta", dev: "Dev"};
181
+ if (!Edge.#CHANNELS.includes(version) && platform == "linux") {
182
+ filename = `microsoft-edge-${channel}_${versionNumber}-1_amd64.deb`;
183
+ url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`;
184
+ }
185
+ else {
186
+ let products = await got("https://edgeupdates.microsoft.com/api/products?view=enterprise").json();
187
+ for (let product of products) {
188
+ if (product.Product != downloadChannels[version])
189
+ continue;
190
+
191
+ let release = product.Releases.find(
192
+ r => r.Platform == plat && r.Architecture == arch);
193
+ if (!release)
194
+ continue;
195
+
196
+ ({Location: url} =
197
+ release.Artifacts.find(a => a.Location.endsWith(ext)));
198
+ filename = url.split("/").pop();
199
+ break;
180
200
  }
201
+ }
202
+
203
+ if (!url)
204
+ throw new Error(`${errMsg.browserDownload}: Release not found for Edge ${downloadChannels[version]} on ${plat} ${arch}`);
205
+
206
+ const archive = path.join(snapshotsBaseDir, "edge", "cache", filename);
207
+ try {
181
208
  await download(url, archive, downloadTimeout);
182
209
  }
183
210
  catch (err) {
@@ -188,8 +215,41 @@ export class Edge extends Browser {
188
215
  await promisify(exec)(`dpkg -i ${archive}`);
189
216
  }
190
217
  else if (platform == "darwin") {
191
- await fs.promises.rm(`${process.env.HOME}/Applications/${Edge.#getDarwinApp(channel)}.app`, {force: true, recursive: true});
192
- await promisify(exec)(`installer -pkg ${archive} -target CurrentUserHomeDirectory`);
218
+ let command;
219
+ if (process.env.CI === "true") {
220
+ // For some reason installing apps on the home directory fails on macOS
221
+ // runners. Using the root target as a workaround
222
+ // This may no longer be needed after switching to custom runners
223
+ // https://eyeo.atlassian.net/browse/DOPE-8
224
+ command = `sudo installer -pkg ${archive} -target /`;
225
+ }
226
+ else {
227
+ await fs.promises.rm(
228
+ path.join(process.env.HOME, "Applications", `${Edge.#appName(channel)}.app`),
229
+ {force: true, recursive: true}
230
+ );
231
+ command = `installer -pkg ${archive} -target CurrentUserHomeDirectory`;
232
+ }
233
+
234
+ await promisify(exec)(command);
235
+ }
236
+ else if (platform == "win32") {
237
+ // /S strips quotes and /C executes the runnable file
238
+ const installProcess = spawn("cmd", [`/S /C ${archive}`], {
239
+ detached: true,
240
+ env: process.env
241
+ });
242
+
243
+ await new Promise((resolve, reject) => {
244
+ function onClose(code) {
245
+ if (code != 0)
246
+ reject(new Error(`${errMsg.browserInstall}. Exit code: ${code}`));
247
+
248
+ resolve();
249
+ }
250
+
251
+ installProcess.on("close", onClose);
252
+ });
193
253
  }
194
254
 
195
255
  return {binary, versionNumber};
@@ -212,24 +272,29 @@ export class Edge extends Browser {
212
272
 
213
273
  let binary;
214
274
  let versionNumber;
215
- if (!customBrowserBinary && (platform == "linux" || platform == "darwin")) {
216
- ({binary, versionNumber} =
217
- await Edge.installBrowser(version, downloadTimeout));
275
+ if (customBrowserBinary) {
276
+ binary = customBrowserBinary;
277
+ versionNumber = await Edge.getInstalledVersion(binary);
218
278
  }
219
279
  else {
220
- binary = customBrowserBinary || Edge.#getBinaryPath();
221
- versionNumber =
222
- await Edge.getInstalledVersion(binary);
280
+ ({binary, versionNumber} =
281
+ await Edge.installBrowser(version, downloadTimeout));
223
282
  }
224
283
 
284
+ if (platform == "win32")
285
+ // webdriver can't find the binary when subfolders are enclosed by quotes
286
+ binary = binary.replaceAll("\"", "");
287
+
225
288
  const majorVersion = getMajorVersion(versionNumber);
226
289
  const edgeOptions = {};
227
290
  // https://issues.chromium.org/issues/409441960
228
291
  if (majorVersion >= 136)
229
292
  edgeOptions.enableExtensionTargets = true;
230
293
 
231
- const options = new edge.Options({"ms:edgeOptions": edgeOptions})
232
- .addArguments("no-sandbox", ...extraArgs);
294
+ let options = new edge.Options({"ms:edgeOptions": edgeOptions})
295
+ .addArguments("no-sandbox", ...extraArgs)
296
+ .setEdgeChromiumBinaryPath(binary);
297
+
233
298
  if (headless) {
234
299
  if (versionNumber && majorVersion >= 114)
235
300
  options.addArguments("headless=new");
@@ -244,27 +309,19 @@ export class Edge extends Browser {
244
309
  options.addArguments("inprivate");
245
310
  if (insecure)
246
311
  options.addArguments("ignore-certificate-errors");
247
- if (platform === "linux" || platform === "darwin")
248
- options.setEdgeChromiumBinaryPath(binary);
249
312
 
250
313
  let builder = new Builder();
251
314
  builder.forBrowser("MicrosoftEdge");
252
315
  builder.setEdgeOptions(options);
253
316
 
254
317
  let driver;
255
- // On Windows CI, occasionally a SessionNotCreatedError is thrown, likely
256
- // due to low OS resources, that's why building the driver is retried
257
- await wait(async() => {
258
- try {
259
- driver = await builder.build();
260
- return true;
261
- }
262
- catch (err) {
263
- if (err.name != "SessionNotCreatedError")
264
- throw err;
265
- await killDriverProcess("msedgedriver");
266
- }
267
- }, 30000, `${errMsg.driverStart}: msedgedriver`, 1000);
318
+ try {
319
+ process.env.SE_DRIVER_MIRROR_URL = "https://msedgedriver.microsoft.com";
320
+ driver = edge.Driver.createSession(options);
321
+ }
322
+ catch (err) {
323
+ throw new Error(`${errMsg.driverStart}: msedgedriver\n${err}`);
324
+ }
268
325
 
269
326
  // From Edge 134 on, developer mode needs to be enabled
270
327
  // for custom extensions to work properly
package/src/utils.js CHANGED
@@ -32,6 +32,7 @@ export const errMsg = {
32
32
  driverStart: "Unable to start driver",
33
33
  extensionNotFound: "Extension not found",
34
34
  browserDownload: "Browser download failed",
35
+ browserInstall: "Browser installation failed",
35
36
  browserNotInstalled: "Browser is not installed",
36
37
  browserVersionCheck: "Checking the browser version failed",
37
38
  elemNotFound: "HTML element not found",
package/test/browsers.js CHANGED
@@ -180,13 +180,20 @@ for (let browser of Object.keys(BROWSERS)) {
180
180
  await killDriverProcess("geckodriver");
181
181
 
182
182
  // https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/77
183
- if (process.platform == "win32" && browser == "chromium")
183
+ if (process.platform == "win32" && browser == "chromium") {
184
184
  await killDriverProcess("chrome");
185
- else if (process.platform == "win32" && browser == "edge")
185
+ }
186
+ else if (process.platform == "win32" && browser == "edge") {
187
+ await killDriverProcess("msedgedriver");
186
188
  await killDriverProcess("msedge");
189
+ }
187
190
  }
188
191
 
189
192
  beforeEach(function() {
193
+ if (browser == "edge" && process.platform != "linux" &&
194
+ version == "114.0.1823.82")
195
+ this.skip();
196
+
190
197
  if (failedInstall)
191
198
  this.skip();
192
199
  });
@@ -194,8 +201,8 @@ for (let browser of Object.keys(BROWSERS)) {
194
201
  afterEach(quitDriver);
195
202
 
196
203
  it("installs", async function() {
197
- if (browser == "edge" && process.platform == "win32")
198
- this.skip();
204
+ // installing browsers may take a while on the CI
205
+ this.timeout(150000);
199
206
 
200
207
  let binary;
201
208
  let versionNumber;
@@ -326,6 +333,10 @@ for (let browser of Object.keys(BROWSERS)) {
326
333
  if (browser == "firefox" && version == "68.0")
327
334
  this.skip();
328
335
 
336
+ // Skipping flaky test until solution is found, see issue #89
337
+ if (process.platform === "win32")
338
+ this.skip();
339
+
329
340
  let {extensionPaths, manifest} = getExtension(browser, version);
330
341
  driver = await BROWSERS[browser].getDriver(
331
342
  version, {headless: false, extensionPaths, incognito: true});
@@ -360,12 +371,8 @@ for (let browser of Object.keys(BROWSERS)) {
360
371
  });
361
372
  }
362
373
 
363
-
364
374
  describe("Any version", async() => {
365
- it("does not install unsupported versions", async function() {
366
- if (browser == "edge" && process.platform == "win32")
367
- this.skip();
368
-
375
+ it("does not install unsupported versions", async() => {
369
376
  for (let unsupported of ["0.0", "invalid"]) {
370
377
  await expect(BROWSERS[browser].installBrowser(unsupported))
371
378
  .rejects.toThrow(`Unsupported browser version: ${unsupported}`);