@eyeo/get-browser-binary 0.13.0 → 0.14.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/src/edge.js ADDED
@@ -0,0 +1,308 @@
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 path from "path";
19
+ import {exec} from "child_process";
20
+ import {promisify} from "util";
21
+ import fs from "fs";
22
+
23
+ import got from "got";
24
+ import webdriver from "selenium-webdriver";
25
+ import edge from "selenium-webdriver/edge.js";
26
+ import extractZip from "extract-zip";
27
+
28
+ import {Browser} from "./browser.js";
29
+ import {download, killDriverProcess, wait, getMajorVersion, checkVersion,
30
+ checkPlatform, errMsg, snapshotsBaseDir, platformArch}
31
+ from "./utils.js";
32
+
33
+ let {By} = webdriver;
34
+ let {platform} = process;
35
+
36
+ /**
37
+ * Browser and webdriver functionality for Edge.
38
+ * @hideconstructor
39
+ * @extends Browser
40
+ */
41
+ export class Edge extends Browser {
42
+ static #CHANNELS = ["latest", "beta", "dev"];
43
+
44
+ static async #getVersionForChannel(version) {
45
+ let channel = "stable";
46
+ if (Edge.#CHANNELS.includes(version) && version != "latest")
47
+ channel = version;
48
+
49
+ let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/`;
50
+ let body;
51
+ try {
52
+ ({body} = await got(url));
53
+ }
54
+ catch (err) {
55
+ throw new Error(`${errMsg.browserVersionCheck}: ${url}\n${err}`);
56
+ }
57
+ let versionNumber;
58
+ if (Edge.#CHANNELS.includes(version)) {
59
+ let regex = /href="microsoft-edge-(stable|beta|dev)_(.*?)-1_/gm;
60
+ let matches;
61
+ let versionNumbers = [];
62
+ while ((matches = regex.exec(body)) !== null)
63
+ versionNumbers.push(matches[2]);
64
+
65
+ let compareVersions = (v1, v2) =>
66
+ getMajorVersion(v1) < getMajorVersion(v2) ? 1 : -1;
67
+ versionNumber = versionNumbers.sort(compareVersions)[0];
68
+ }
69
+ else {
70
+ let split = version.split(".");
71
+ let minorVersion = split.length == 4 ? parseInt(split.pop(), 10) : -1;
72
+ let majorVersion = split.join(".");
73
+ let found;
74
+ while (!found && minorVersion >= 0) {
75
+ versionNumber = `${majorVersion}.${minorVersion}`;
76
+ found = body.includes(versionNumber);
77
+ minorVersion--;
78
+ }
79
+ if (!found)
80
+ throw new Error(`${errMsg.unsupportedVersion}: ${version}`);
81
+ }
82
+
83
+ return {versionNumber, channel};
84
+ }
85
+
86
+ static #darwinApp = "Microsoft Edge";
87
+
88
+ static #getBinaryPath(channel = "stable") {
89
+ switch (platform) {
90
+ case "win32":
91
+ let programFiles = process.env["ProgramFiles(x86)"] ?
92
+ "${Env:ProgramFiles(x86)}" : "${Env:ProgramFiles}";
93
+ return `${programFiles}\\Microsoft\\Edge\\Application\\msedge.exe`;
94
+ case "linux":
95
+ return channel == "stable" ?
96
+ "microsoft-edge" : `microsoft-edge-${channel}`;
97
+ case "darwin":
98
+ return `${process.env.HOME}/Applications/${Edge.#darwinApp}.app/Contents/MacOS/${Edge.#darwinApp}`;
99
+ default:
100
+ checkPlatform();
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Installs the browser. On Linux, Edge is installed as a system package,
106
+ * which requires root permissions. On MacOS, Edge is installed as a user
107
+ * app (not as a system app). Installing Edge on Windows is not supported.
108
+ * @param {string} [version=latest] Either "latest", "beta", "dev" or a full
109
+ * version number (i.e. "95.0.1020.40").
110
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
111
+ * install files to complete. When set to 0 there is no time limit.
112
+ * @return {BrowserBinary}
113
+ * @throws {Error} Unsupported browser version, Unsupported platform, Browser
114
+ * download failed.
115
+ */
116
+ static async installBrowser(version = "latest", downloadTimeout = 0) {
117
+ if (platform == "win32")
118
+ // Edge is mandatory on Windows, can't be uninstalled or downgraded
119
+ // https://support.microsoft.com/en-us/microsoft-edge/why-can-t-i-uninstall-microsoft-edge-ee150b3b-7d7a-9984-6d83-eb36683d526d
120
+ throw new Error(`${errMsg.unsupportedPlatform}: ${platform}`);
121
+
122
+ if (platform == "darwin" && version != "latest")
123
+ // Only latest Edge is supported on macOS
124
+ throw new Error(`${errMsg.unsupportedVersion}: ${version}. Only "latest" is supported`);
125
+
126
+ const MIN_VERSION = 95;
127
+ checkVersion(version, MIN_VERSION, Edge.#CHANNELS);
128
+ let {versionNumber, channel} = await Edge.#getVersionForChannel(version);
129
+
130
+ let filename = {
131
+ linux: `microsoft-edge-${channel}_${versionNumber}-1_amd64.deb`,
132
+ darwin: `MicrosoftEdge-${versionNumber}.pkg`
133
+ }[platform];
134
+
135
+ let snapshotsDir = path.join(snapshotsBaseDir, "edge");
136
+ let archive = path.join(snapshotsDir, "cache", filename);
137
+ let binary = Edge.#getBinaryPath(channel);
138
+ try {
139
+ if (await Edge.#getInstalledVersionNumber(binary) == versionNumber)
140
+ return {binary, versionNumber};
141
+ }
142
+ catch (e) {}
143
+
144
+ let url = `https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-${channel}/${filename}`;
145
+ try {
146
+ if (platform == "darwin") {
147
+ let caskUrl = "https://formulae.brew.sh/api/cask/microsoft-edge.json";
148
+ let caskJson;
149
+ try {
150
+ caskJson = await got(caskUrl).json();
151
+ }
152
+ catch (err) {
153
+ throw new Error(`${errMsg.browserVersionCheck}: ${caskUrl}\n${err}`);
154
+ }
155
+ ({url} = process.arch == "arm64" ?
156
+ caskJson.variations.arm64_ventura : caskJson);
157
+ }
158
+ await download(url, archive, downloadTimeout);
159
+ }
160
+ catch (err) {
161
+ throw new Error(`${errMsg.browserDownload}: ${url}\n${err}`);
162
+ }
163
+
164
+ if (platform == "linux") {
165
+ await promisify(exec)(`dpkg -i ${archive}`);
166
+ }
167
+ else if (platform == "darwin") {
168
+ await fs.promises.rm(`${process.env.HOME}/Applications/${Edge.#darwinApp}.app`, {force: true, recursive: true});
169
+ await promisify(exec)(`installer -pkg ${archive} -target CurrentUserHomeDirectory`);
170
+ }
171
+
172
+ return {binary, versionNumber};
173
+ }
174
+
175
+ static async #getInstalledVersionNumber(binary) {
176
+ let installedVersion = await Edge.getInstalledVersion(binary);
177
+ for (let word of ["beta", "dev", "Beta", "Dev"])
178
+ installedVersion = installedVersion.replace(word, "");
179
+ return installedVersion.trim().replace(/.*\s/, "");
180
+ }
181
+
182
+ static async #installDriver(binary) {
183
+ async function extractEdgeZip(archive, cacheDir, driverPath) {
184
+ await killDriverProcess("msedgedriver");
185
+ await fs.promises.rm(driverPath, {force: true});
186
+ await extractZip(archive, {dir: cacheDir});
187
+ }
188
+
189
+ let binaryPath = binary || Edge.#getBinaryPath();
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
+ let cacheDir = path.join(snapshotsBaseDir, "edge", "cache",
199
+ `edgedriver-${versionNumber}`);
200
+ let archive = path.join(cacheDir, `${versionNumber}-${zip}`);
201
+ let driverPath = path.join(cacheDir, driverBinary);
202
+
203
+ try {
204
+ await fs.promises.access(archive);
205
+ await extractEdgeZip(archive, cacheDir, driverPath);
206
+ }
207
+ catch (e) { // zip file is either not cached or corrupted
208
+ let vSplit = versionNumber.split(".");
209
+ let lastNum = parseInt(vSplit[3], 10);
210
+ while (lastNum >= 0) {
211
+ try {
212
+ let attempt = `${vSplit[0]}.${vSplit[1]}.${vSplit[2]}.${lastNum}`;
213
+ await download(`https://msedgedriver.azureedge.net/${attempt}/${zip}`,
214
+ archive);
215
+ break;
216
+ }
217
+ catch (e2) {
218
+ lastNum--;
219
+ }
220
+ }
221
+ if (lastNum < 0)
222
+ throw new Error(`${errMsg.driverDownload}: Edge ${versionNumber}`);
223
+
224
+ await extractEdgeZip(archive, cacheDir, driverPath);
225
+ }
226
+ return driverPath;
227
+ }
228
+
229
+ /** @see Browser.getDriver */
230
+ static async getDriver(version = "latest", {
231
+ headless = true, extensionPaths = [], incognito = false, insecure = false,
232
+ extraArgs = [], customBrowserBinary
233
+ } = {}, downloadTimeout = 0) {
234
+ let binary;
235
+ let versionNumber;
236
+ if (!customBrowserBinary && (platform == "linux" || platform == "darwin")) {
237
+ ({binary, versionNumber} =
238
+ await Edge.installBrowser(version, downloadTimeout));
239
+ }
240
+ else {
241
+ binary = customBrowserBinary || Edge.#getBinaryPath();
242
+ versionNumber =
243
+ await Edge.#getInstalledVersionNumber(binary);
244
+ }
245
+
246
+ let driverPath = await Edge.#installDriver(binary);
247
+ let serviceBuilder = new edge.ServiceBuilder(driverPath);
248
+
249
+ let options = new edge.Options().addArguments("no-sandbox", ...extraArgs);
250
+ if (headless) {
251
+ if (versionNumber && getMajorVersion(versionNumber) >= 114)
252
+ options.addArguments("headless=new");
253
+ else
254
+ options.headless();
255
+ }
256
+ if (extensionPaths.length > 0)
257
+ options.addArguments(`load-extension=${extensionPaths.join(",")}`);
258
+ if (incognito)
259
+ options.addArguments("inprivate");
260
+ if (insecure)
261
+ options.addArguments("ignore-certificate-errors");
262
+ if (platform == "linux")
263
+ options.setEdgeChromiumBinaryPath(`/usr/bin/${binary}`);
264
+
265
+ let builder = new webdriver.Builder();
266
+ builder.forBrowser("MicrosoftEdge");
267
+ builder.setEdgeOptions(options);
268
+ builder.setEdgeService(serviceBuilder);
269
+
270
+ let driver;
271
+ // On Windows CI, occasionally a SessionNotCreatedError is thrown, likely
272
+ // due to low OS resources, that's why building the driver is retried
273
+ await wait(async() => {
274
+ try {
275
+ driver = await builder.build();
276
+ return true;
277
+ }
278
+ catch (err) {
279
+ if (err.name != "SessionNotCreatedError")
280
+ throw err;
281
+ await killDriverProcess("msedgedriver");
282
+ }
283
+ }, 30000, `${errMsg.driverStart}: msedgedriver`, 1000);
284
+
285
+ return driver;
286
+ }
287
+
288
+ /** @see Browser.enableExtensionInIncognito */
289
+ static async enableExtensionInIncognito(driver, extensionTitle) {
290
+ await driver.navigate().to("edge://extensions/");
291
+ for (let elem of await driver.findElements(By.css("[role=listitem]"))) {
292
+ let text = await elem.getAttribute("innerHTML");
293
+ if (!text.includes(extensionTitle))
294
+ continue;
295
+
296
+ for (let button of await elem.findElements(By.css("button"))) {
297
+ text = await elem.getAttribute("innerHTML");
298
+ if (!text.includes("Details"))
299
+ continue;
300
+
301
+ await button.click();
302
+ return await driver.findElement(By.id("itemAllowIncognito")).click();
303
+ }
304
+ throw new Error(`${errMsg.elemNotFound}: Details button`);
305
+ }
306
+ throw new Error(`${errMsg.extensionNotFound}: ${extensionTitle}`);
307
+ }
308
+ }
package/src/firefox.js ADDED
@@ -0,0 +1,216 @@
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 path from "path";
19
+ import {exec} from "child_process";
20
+ import {promisify} from "util";
21
+ import fs from "fs";
22
+
23
+ import got from "got";
24
+ import webdriver from "selenium-webdriver";
25
+ import firefox from "selenium-webdriver/firefox.js";
26
+
27
+ import {Browser} from "./browser.js";
28
+ import {download, extractTar, extractDmg, killDriverProcess, wait,
29
+ getMajorVersion, checkVersion, checkPlatform, errMsg, snapshotsBaseDir,
30
+ platformArch} from "./utils.js";
31
+
32
+ let {until, By} = webdriver;
33
+
34
+ /**
35
+ * Browser and webdriver functionality for Firefox.
36
+ * @hideconstructor
37
+ * @extends Browser
38
+ */
39
+ export class Firefox extends Browser {
40
+ static #CHANNELS = ["latest", "beta"];
41
+
42
+ static async #getVersionForChannel(channel) {
43
+ if (!Firefox.#CHANNELS.includes(channel))
44
+ return channel;
45
+
46
+ let url = "https://product-details.mozilla.org/1.0/firefox_versions.json";
47
+ let data;
48
+ try {
49
+ data = await got(url).json();
50
+ }
51
+ catch (err) {
52
+ throw new Error(`${errMsg.browserVersionCheck}: ${url}\n${err}`);
53
+ }
54
+ return channel == "beta" ?
55
+ data.LATEST_FIREFOX_DEVEL_VERSION : data.LATEST_FIREFOX_VERSION;
56
+ }
57
+
58
+ static #getBinaryPath(dir) {
59
+ checkPlatform();
60
+ return {
61
+ win32: path.join(dir, "core", "firefox.exe"),
62
+ linux: path.join(dir, "firefox", "firefox"),
63
+ darwin: path.join(dir, "Firefox.app", "Contents", "MacOS", "firefox")
64
+ }[process.platform];
65
+ }
66
+
67
+ static #extractFirefoxArchive(archive, dir) {
68
+ switch (process.platform) {
69
+ case "win32":
70
+ return promisify(exec)(`"${archive}" /extractdir=${dir}`);
71
+ case "linux":
72
+ return extractTar(archive, dir);
73
+ case "darwin":
74
+ return extractDmg(archive, dir);
75
+ default:
76
+ checkPlatform();
77
+ }
78
+ }
79
+
80
+ static async #getInstalledBrowserInfo(binary) {
81
+ let installedVersion = await Firefox.getInstalledVersion(binary);
82
+ // Linux example: "Mozilla Firefox 102.15.0esr"
83
+ let versionNumber = installedVersion.split(" ")[2] || installedVersion;
84
+ return {binary, versionNumber};
85
+ }
86
+
87
+ /**
88
+ * Installs the browser. The Firefox executable gets extracted in the
89
+ * {@link snapshotsBaseDir} folder, ready to go.
90
+ * @param {string} [version=latest] Either "latest", "beta" or a full version
91
+ * number (i.e. "68.0").
92
+ * @param {number} [downloadTimeout=0] Allowed time in ms for the download of
93
+ * install files to complete. When set to 0 there is no time limit.
94
+ * @return {BrowserBinary}
95
+ * @throws {Error} Unsupported browser version, Unsupported platform, Browser
96
+ * download failed.
97
+ */
98
+ static async installBrowser(version = "latest", downloadTimeout = 0) {
99
+ const MIN_VERSION = 68;
100
+
101
+ // https://gitlab.com/eyeo/developer-experience/get-browser-binary/-/issues/46
102
+ if (platformArch == "linux-arm64")
103
+ return await Firefox.#getInstalledBrowserInfo("/usr/bin/firefox");
104
+
105
+ checkVersion(version, MIN_VERSION, Firefox.#CHANNELS);
106
+ let versionNumber = await Firefox.#getVersionForChannel(version);
107
+
108
+ let [buildPlatform, fileName] = {
109
+ "win32-ia32": ["win32", `Firefox Setup ${versionNumber}.exe`],
110
+ "win32-x64": ["win64", `Firefox Setup ${versionNumber}.exe`],
111
+ "linux-x64": ["linux-x86_64", `firefox-${versionNumber}.tar.bz2`],
112
+ "darwin-x64": ["mac", `Firefox ${versionNumber}.dmg`],
113
+ "darwin-arm64": ["mac", `Firefox ${versionNumber}.dmg`]
114
+ }[platformArch];
115
+
116
+ let snapshotsDir = path.join(snapshotsBaseDir, "firefox");
117
+ let browserDir = path.join(snapshotsDir,
118
+ `firefox-${platformArch}-${versionNumber}`);
119
+ let binary = Firefox.#getBinaryPath(browserDir);
120
+ try {
121
+ await fs.promises.access(browserDir);
122
+ return {binary, versionNumber};
123
+ }
124
+ catch (e) {}
125
+
126
+ let archive = path.join(snapshotsDir, "cache", fileName);
127
+ await fs.promises.mkdir(path.dirname(browserDir), {recursive: true});
128
+ try {
129
+ await fs.promises.access(archive);
130
+ }
131
+ catch (e) {
132
+ let url = `https://archive.mozilla.org/pub/firefox/releases/${versionNumber}/${buildPlatform}/en-US/${fileName}`;
133
+ try {
134
+ await download(url, archive, downloadTimeout);
135
+ }
136
+ catch (err) {
137
+ throw new Error(`${errMsg.browserDownload}: ${url}\n${err}`);
138
+ }
139
+ }
140
+ await Firefox.#extractFirefoxArchive(archive, browserDir);
141
+
142
+ return {binary, versionNumber};
143
+ }
144
+
145
+ /** @see Browser.getDriver */
146
+ static async getDriver(version = "latest", {
147
+ headless = true, extensionPaths = [], incognito = false, insecure = false,
148
+ extraArgs = [], customBrowserBinary
149
+ } = {}, downloadTimeout = 0) {
150
+ let binary;
151
+ let versionNumber;
152
+ if (!customBrowserBinary) {
153
+ ({binary, versionNumber} =
154
+ await Firefox.installBrowser(version, downloadTimeout));
155
+ }
156
+
157
+ let options = new firefox.Options();
158
+ if (headless)
159
+ options.headless();
160
+ if (incognito)
161
+ options.addArguments("--private");
162
+ if (insecure)
163
+ options.set("acceptInsecureCerts", true);
164
+ if (extraArgs.length > 0)
165
+ options.addArguments(...extraArgs);
166
+ // Enabled by default on Firefox > 68
167
+ if (versionNumber && getMajorVersion(versionNumber) == 68)
168
+ options.setPreference("dom.promise_rejection_events.enabled", true);
169
+
170
+ options.setBinary(customBrowserBinary || binary);
171
+
172
+ let driver;
173
+ // The OS may be low on resources, that's why building the driver is retried
174
+ // https://github.com/mozilla/geckodriver/issues/1560
175
+ await wait(async() => {
176
+ try {
177
+ driver = await new webdriver.Builder()
178
+ .forBrowser("firefox")
179
+ .setFirefoxOptions(options)
180
+ .build();
181
+ return true;
182
+ }
183
+ catch (err) {
184
+ if (err.message != "Failed to decode response from marionette")
185
+ throw err;
186
+ await killDriverProcess("geckodriver");
187
+ }
188
+ }, 30000, `${errMsg.driverStart}: geckodriver`, 1000);
189
+
190
+ for (let extensionPath of extensionPaths) {
191
+ let temporary = true; // Parameter not documented on the webdriver docs
192
+ await driver.installAddon(extensionPath, temporary);
193
+ }
194
+ return driver;
195
+ }
196
+
197
+ /** @see Browser.enableExtensionInIncognito */
198
+ static async enableExtensionInIncognito(driver, extensionTitle) {
199
+ let version = (await driver.getCapabilities()).getBrowserVersion();
200
+ // The UI workaround assumes web elements only present on Firefox >= 87
201
+ checkVersion(version, 87);
202
+
203
+ await driver.navigate().to("about:addons");
204
+ await driver.wait(until.elementLocated(By.name("extension")), 1000).click();
205
+
206
+ for (let elem of await driver.findElements(By.className("card addon"))) {
207
+ let text = await elem.getAttribute("innerHTML");
208
+ if (!text.includes(extensionTitle))
209
+ continue;
210
+
211
+ await elem.click();
212
+ return await driver.findElement(By.name("private-browsing")).click();
213
+ }
214
+ throw new Error(`${errMsg.extensionNotFound}: ${extensionTitle}`);
215
+ }
216
+ }
package/src/utils.js CHANGED
@@ -25,6 +25,24 @@ import got from "got";
25
25
  import dmg from "dmg";
26
26
  import Jimp from "jimp";
27
27
 
28
+ export const errMsg = {
29
+ unsupportedVersion: "Unsupported browser version",
30
+ unsupportedPlatform: "Unsupported platform",
31
+ driverDownload: "Driver download failed",
32
+ driverStart: "Unable to start driver",
33
+ extensionNotFound: "Extension not found",
34
+ browserDownload: "Browser download failed",
35
+ browserNotInstalled: "Browser is not installed",
36
+ browserVersionCheck: "Checking the browser version failed",
37
+ elemNotFound: "HTML element not found"
38
+ };
39
+ export const platformArch = `${process.platform}-${process.arch}`;
40
+
41
+ /**
42
+ * Root folder where browser and webdriver files get downloaded and extracted.
43
+ * @type {string}
44
+ */
45
+ export let snapshotsBaseDir = path.join(process.cwd(), "browser-snapshots");
28
46
 
29
47
  /**
30
48
  * Downloads url resources.
@@ -35,6 +53,10 @@ import Jimp from "jimp";
35
53
  * @throws {TypeError} Invalid URL, Download timeout.
36
54
  */
37
55
  export async function download(url, destFile, timeout = 0) {
56
+ if (process.env.VERBOSE == "true")
57
+ // eslint-disable-next-line no-console
58
+ console.log(`Downloading from ${url} ...`);
59
+
38
60
  let cacheDir = path.dirname(destFile);
39
61
  await fs.promises.mkdir(cacheDir, {recursive: true});
40
62
 
@@ -215,3 +237,24 @@ export async function takeFullPageScreenshot(driver, hideScrollbars = true) {
215
237
 
216
238
  return fullScreenshot;
217
239
  }
240
+
241
+ export function getMajorVersion(versionNumber) {
242
+ let majorVersion = parseInt(versionNumber && versionNumber.split(".")[0], 10);
243
+ if (isNaN(majorVersion))
244
+ throw new Error(`${errMsg.unsupportedVersion}: ${versionNumber}`);
245
+
246
+ return majorVersion;
247
+ }
248
+
249
+ export function checkVersion(version, minVersion, channels = []) {
250
+ if (channels.includes(version))
251
+ return;
252
+
253
+ if (getMajorVersion(version) < minVersion)
254
+ throw new Error(`${errMsg.unsupportedVersion}: ${version}`);
255
+ }
256
+
257
+ export function checkPlatform() {
258
+ if (!["win32", "linux", "darwin"].includes(process.platform))
259
+ throw new Error(`${errMsg.unsupportedPlatform}: ${process.platform}`);
260
+ }