diff --git a/chrome.js b/chrome.js index 4ade446..27795c2 100644 --- a/chrome.js +++ b/chrome.js @@ -11,6 +11,9 @@ const os = require('os'); const path = require('path'); const CDN_URL = 'https://chromedriver.storage.googleapis.com'; +const VERSION_DATA_URL = 'https://googlechromelabs.github.io/chrome-for-testing/latest-versions-per-milestone-with-downloads.json'; +// Chrome distribution changed in version 115. +const NEW_CHROME_DISTRIBUTION_VERSION = 115; /** * An installer for chromedriver for desktop Chrome. @@ -64,10 +67,26 @@ class ChromeWebDriverInstaller extends WebDriverInstallerBase { */ async getBestDriverVersion(browserVersion) { const idealMajorVersion = parseInt(browserVersion.split('.')[0], 10); - return await InstallerUtils.fetchVersionUrlWithAutomaticDowngrade( - idealMajorVersion, - /* minMajorVersion */ idealMajorVersion - 2, - (majorVersion) => `${CDN_URL}/LATEST_RELEASE_${majorVersion}`); + + if (idealMajorVersion < NEW_CHROME_DISTRIBUTION_VERSION) { + return await InstallerUtils.fetchVersionUrl( + `${CDN_URL}/LATEST_RELEASE_${idealMajorVersion}`); + } else { + const data = await this.getVersionData_(); + + // Fall back on the major version if necessary. + // We haven't seen this become necessary yet since the new distribution + // mechanism debuted, but better safe than sorry. + let majorVersion = idealMajorVersion; + while (majorVersion >= NEW_CHROME_DISTRIBUTION_VERSION) { + if (majorVersion in data['milestones']) { + return data['milestones'][majorVersion]['version']; + } + majorVersion -= 1; + } + + throw new Error(`Unable to locate chromedriver ${idealMajorVersion}!`); + } } /** @@ -76,12 +95,31 @@ class ChromeWebDriverInstaller extends WebDriverInstallerBase { * @return {!Promise} */ async install(driverVersion, outputDirectory) { + const majorVersion = parseInt(driverVersion.split('.')[0], 10); + + if (majorVersion < NEW_CHROME_DISTRIBUTION_VERSION) { + await this.installOld_(driverVersion, outputDirectory); + } else { + await this.installNew_(majorVersion, driverVersion, outputDirectory); + } + } + + /** + * @param {string} driverVersion + * @param {string} outputDirectory + * @return {!Promise} + */ + async installOld_(driverVersion, outputDirectory) { let platform; if (os.platform() == 'linux') { platform = 'linux64'; } else if (os.platform() == 'darwin') { - platform = 'mac64'; + if (process.arch == 'arm64') { + platform = 'mac_arm64'; + } else { + platform = 'mac64'; + } } else if (os.platform() == 'win32') { platform = 'win32'; } else { @@ -105,6 +143,73 @@ class ChromeWebDriverInstaller extends WebDriverInstallerBase { archiveUrl, binaryName, outputName, outputDirectory, /* isZip= */ true); } + + /** + * @param {number} majorVersion + * @param {string} driverVersion + * @param {string} outputDirectory + * @return {!Promise} + */ + async installNew_(majorVersion, driverVersion, outputDirectory) { + let platform; + + if (os.platform() == 'linux') { + platform = 'linux64'; + } else if (os.platform() == 'darwin') { + if (process.arch == 'arm64') { + platform = 'mac-arm64'; + } else { + platform = 'mac-x64'; + } + } else if (os.platform() == 'win32') { + platform = 'win64'; + } else { + throw new Error(`Unrecognized platform: ${os.platform()}`); + } + + let binaryName = `chromedriver-${platform}/chromedriver`; + if (os.platform() == 'win32') { + binaryName += '.exe'; + } + + let outputName = this.getDriverName(); + if (os.platform() == 'win32') { + outputName += '.exe'; + } + + const data = await this.getVersionData_(); + const downloads = data['milestones'][majorVersion]['downloads']['chromedriver']; + + let archiveUrl; + for (const download of downloads) { + if (download['platform'] == platform) { + archiveUrl = download['url']; + break; + } + } + + if (!archiveUrl) { + throw new Error( + `Unable to locate chromedriver ${majorVersion} for ${platform}!`); + } + + return await InstallerUtils.installBinary( + archiveUrl, binaryName, outputName, + outputDirectory, /* isZip= */ true); + } + + /** + * @return {!Object} + * @private + */ + async getVersionData_() { + if (!this.versionDataCache_) { + const response = await InstallerUtils.fetchUrl(VERSION_DATA_URL); + this.versionDataCache_ = await response.json(); + } + + return this.versionDataCache_; + } } module.exports = {ChromeWebDriverInstaller}; diff --git a/package-lock.json b/package-lock.json index 7422c70..32e375e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,9 @@ "regedit": "^5.0.0", "tar-stream": "^2.2.0", "yauzl": "^2.10.0" + }, + "bin": { + "webdriver-installer": "main.js" } }, "node_modules/base64-js": {