@eyeo/get-browser-binary 0.22.0 → 0.23.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 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,10 @@
1
1
  # Unreleased
2
2
 
3
+ # 0.23.0
4
+
5
+ - Adds beta and dev channels to Edge on Windows and MacOS (#29)
6
+ - Fixes edge driver location (!145)
7
+
3
8
  # 0.22.0
4
9
 
5
10
  - 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.0",
4
4
  "description": "Install browser binaries and matching webdrivers",
5
5
  "repository": {
6
6
  "type": "git",
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,24 +150,11 @@ 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);
163
159
  try {
164
160
  if (await Edge.getInstalledVersion(binary) == versionNumber)
@@ -166,18 +162,44 @@ export class Edge extends Browser {
166
162
  }
167
163
  catch (e) {}
168
164
 
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
- }
165
+ const [plat, arch, ext] = {
166
+ "win32-ia32": ["Windows", "x86", ".msi"],
167
+ "win32-x64": ["Windows", "x64", ".msi"],
168
+ "linux-x64": ["Linux", "x64", ".deb"],
169
+ "darwin-x64": ["MacOS", "universal", ".pkg"],
170
+ "darwin-arm64": ["MacOS", "universal", ".pkg"]
171
+ }[platformArch];
172
+
173
+ let url;
174
+ let filename;
175
+ const downloadChannels = {latest: "Stable", beta: "Beta", dev: "Dev"};
176
+ if (!Edge.#CHANNELS.includes(version) && platform == "linux") {
177
+ filename = `microsoft-edge-${channel}_${versionNumber}-1_amd64.deb`;
178
+ url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`;
179
+ }
180
+ else {
181
+ let products = await got("https://edgeupdates.microsoft.com/api/products?view=enterprise").json();
182
+ for (let product of products) {
183
+ if (product.Product != downloadChannels[version])
184
+ continue;
185
+
186
+ let release = product.Releases.find(
187
+ r => r.Platform == plat && r.Architecture == arch);
188
+ if (!release)
189
+ continue;
190
+
191
+ ({Location: url} =
192
+ release.Artifacts.find(a => a.Location.endsWith(ext)));
193
+ filename = url.split("/").pop();
194
+ break;
180
195
  }
196
+ }
197
+
198
+ if (!url)
199
+ throw new Error(`${errMsg.browserDownload}: Release not found for Edge ${downloadChannels[version]} on ${plat} ${arch}`);
200
+
201
+ const archive = path.join(snapshotsBaseDir, "edge", "cache", filename);
202
+ try {
181
203
  await download(url, archive, downloadTimeout);
182
204
  }
183
205
  catch (err) {
@@ -188,8 +210,41 @@ export class Edge extends Browser {
188
210
  await promisify(exec)(`dpkg -i ${archive}`);
189
211
  }
190
212
  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`);
213
+ let command;
214
+ if (process.env.CI === "true") {
215
+ // For some reason installing apps on the home directory fails on macOS
216
+ // runners. Using the root target as a workaround
217
+ // This may no longer be needed after switching to custom runners
218
+ // https://eyeo.atlassian.net/browse/DOPE-8
219
+ command = `sudo installer -pkg ${archive} -target /`;
220
+ }
221
+ else {
222
+ await fs.promises.rm(
223
+ path.join(process.env.HOME, "Applications", `${Edge.#appName(channel)}.app`),
224
+ {force: true, recursive: true}
225
+ );
226
+ command = `installer -pkg ${archive} -target CurrentUserHomeDirectory`;
227
+ }
228
+
229
+ await promisify(exec)(command);
230
+ }
231
+ else if (platform == "win32") {
232
+ // /S strips quotes and /C executes the runnable file
233
+ const installProcess = spawn("cmd", [`/S /C ${archive}`], {
234
+ detached: true,
235
+ env: process.env
236
+ });
237
+
238
+ await new Promise((resolve, reject) => {
239
+ function onClose(code) {
240
+ if (code != 0)
241
+ reject(new Error(`${errMsg.browserInstall}. Exit code: ${code}`));
242
+
243
+ resolve();
244
+ }
245
+
246
+ installProcess.on("close", onClose);
247
+ });
193
248
  }
194
249
 
195
250
  return {binary, versionNumber};
@@ -212,24 +267,29 @@ export class Edge extends Browser {
212
267
 
213
268
  let binary;
214
269
  let versionNumber;
215
- if (!customBrowserBinary && (platform == "linux" || platform == "darwin")) {
216
- ({binary, versionNumber} =
217
- await Edge.installBrowser(version, downloadTimeout));
270
+ if (customBrowserBinary) {
271
+ binary = customBrowserBinary;
272
+ versionNumber = await Edge.getInstalledVersion(binary);
218
273
  }
219
274
  else {
220
- binary = customBrowserBinary || Edge.#getBinaryPath();
221
- versionNumber =
222
- await Edge.getInstalledVersion(binary);
275
+ ({binary, versionNumber} =
276
+ await Edge.installBrowser(version, downloadTimeout));
223
277
  }
224
278
 
279
+ if (platform == "win32")
280
+ // webdriver can't find the binary when subfolders are enclosed by quotes
281
+ binary = binary.replaceAll("\"", "");
282
+
225
283
  const majorVersion = getMajorVersion(versionNumber);
226
284
  const edgeOptions = {};
227
285
  // https://issues.chromium.org/issues/409441960
228
286
  if (majorVersion >= 136)
229
287
  edgeOptions.enableExtensionTargets = true;
230
288
 
231
- const options = new edge.Options({"ms:edgeOptions": edgeOptions})
232
- .addArguments("no-sandbox", ...extraArgs);
289
+ let options = new edge.Options({"ms:edgeOptions": edgeOptions})
290
+ .addArguments("no-sandbox", ...extraArgs)
291
+ .setEdgeChromiumBinaryPath(binary);
292
+
233
293
  if (headless) {
234
294
  if (versionNumber && majorVersion >= 114)
235
295
  options.addArguments("headless=new");
@@ -244,27 +304,19 @@ export class Edge extends Browser {
244
304
  options.addArguments("inprivate");
245
305
  if (insecure)
246
306
  options.addArguments("ignore-certificate-errors");
247
- if (platform === "linux" || platform === "darwin")
248
- options.setEdgeChromiumBinaryPath(binary);
249
307
 
250
308
  let builder = new Builder();
251
309
  builder.forBrowser("MicrosoftEdge");
252
310
  builder.setEdgeOptions(options);
253
311
 
254
312
  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);
313
+ try {
314
+ process.env.SE_DRIVER_MIRROR_URL = "https://msedgedriver.microsoft.com";
315
+ driver = edge.Driver.createSession(options);
316
+ }
317
+ catch (err) {
318
+ throw new Error(`${errMsg.driverStart}: msedgedriver\n${err}`);
319
+ }
268
320
 
269
321
  // From Edge 134 on, developer mode needs to be enabled
270
322
  // 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;
@@ -360,12 +367,8 @@ for (let browser of Object.keys(BROWSERS)) {
360
367
  });
361
368
  }
362
369
 
363
-
364
370
  describe("Any version", async() => {
365
- it("does not install unsupported versions", async function() {
366
- if (browser == "edge" && process.platform == "win32")
367
- this.skip();
368
-
371
+ it("does not install unsupported versions", async() => {
369
372
  for (let unsupported of ["0.0", "invalid"]) {
370
373
  await expect(BROWSERS[browser].installBrowser(unsupported))
371
374
  .rejects.toThrow(`Unsupported browser version: ${unsupported}`);