I have selenium grid setup with multiple node machines , where in I am manually downloading chromeDriver & geckoDriver on all selenium node machines & using them for chrome & firefox browsers respectively.
Now here chrome & firefox browsers (on all selenium node machines) are set on 'Automatic Update' (which is required as I want my application to be tested always on latest browser versions) , because of this browsers on my node machines keep getting updated more often & since respective driver updates is a manual process , it forces me to log in to each selenium node machine & update them manually.
Can this process be automated ?
PS : I know that dockerized selenium grid can be used to fetch/pull latest browser images & their drivers , however switching from traditional selenium grid to dockerized selenium grid is another thing & will take some time to implement.
First @Asyranok is right, even when implemented auto update code will not work 100% of the time. However, for many of us, this occasional downtime is "ok" as long as it's just a few days.
I've found that manually updating X servers every few months to be incredibly irritating and while there are well written instructions on the selenium website on how to "auto update" the driver I've yet to see one openly available non-library implementation of this guide.
My answer is specific to C#, for this language the solution typically suggested is to use NuGet to pull the latest driver automatically, this has two issues:
You need to deploy at the frequency of chrome updating (most companies aren't there yet, neither are we) or your application will be "broken" for the time between chrome updating and your "new" version of the application deploying, and again this is only if you release on a schedule, if you release ad-hoc your going to have to go through a series of manual steps to update, build, release etc. to get your application working again.
You need (typically, without a work around) to pull the latest chromedrive from NuGet by hand, again a manual process.
What would be nice would be what python has and @leminhnguyenHUST suggests which is using a library that will automatically pull the latest chromedriver on runtime. I've looked around and haven't yet found anything for C# that does this, so I decided to roll my own and build that into my application:
public void DownloadLatestVersionOfChromeDriver()
{
string path = DownloadLatestVersionOfChromeDriverGetVersionPath();
var version = DownloadLatestVersionOfChromeDriverGetChromeVersion(path);
var urlToDownload = DownloadLatestVersionOfChromeDriverGetURLToDownload(version);
DownloadLatestVersionOfChromeDriverKillAllChromeDriverProcesses();
DownloadLatestVersionOfChromeDriverDownloadNewVersionOfChrome(urlToDownload);
}
public string DownloadLatestVersionOfChromeDriverGetVersionPath()
{
//Path originates from here: https://chromedriver.chromium.org/downloads/version-selection
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe"))
{
if (key != null)
{
Object o = key.GetValue("");
if (!String.IsNullOrEmpty(o.ToString()))
{
return o.ToString();
}
else
{
throw new ArgumentException("Unable to get version because chrome registry value was null");
}
}
else
{
throw new ArgumentException("Unable to get version because chrome registry path was null");
}
}
}
public string DownloadLatestVersionOfChromeDriverGetChromeVersion(string productVersionPath)
{
if (String.IsNullOrEmpty(productVersionPath))
{
throw new ArgumentException("Unable to get version because path is empty");
}
if (!File.Exists(productVersionPath))
{
throw new FileNotFoundException("Unable to get version because path specifies a file that does not exists");
}
var versionInfo = FileVersionInfo.GetVersionInfo(productVersionPath);
if (versionInfo != null && !String.IsNullOrEmpty(versionInfo.FileVersion))
{
return versionInfo.FileVersion;
}
else
{
throw new ArgumentException("Unable to get version from path because the version is either null or empty: " + productVersionPath);
}
}
public string DownloadLatestVersionOfChromeDriverGetURLToDownload(string version)
{
if (String.IsNullOrEmpty(version))
{
throw new ArgumentException("Unable to get url because version is empty");
}
//URL's originates from here: https://chromedriver.chromium.org/downloads/version-selection
string html = string.Empty;
string urlToPathLocation = @"https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + String.Join(".", version.Split('.').Take(3));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToPathLocation);
request.AutomaticDecompression = DecompressionMethods.GZip;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
if (String.IsNullOrEmpty(html))
{
throw new WebException("Unable to get version path from website");
}
return "https://chromedriver.storage.googleapis.com/" + html + "/chromedriver_win32.zip";
}
public void DownloadLatestVersionOfChromeDriverKillAllChromeDriverProcesses()
{
//It's important to kill all processes before attempting to replace the chrome driver, because if you do not you may still have file locks left over
var processes = Process.GetProcessesByName("chromedriver");
foreach (var process in processes)
{
try
{
process.Kill();
}
catch
{
//We do our best here but if another user account is running the chrome driver we may not be able to kill it unless we run from a elevated user account + various other reasons we don't care about
}
}
}
public void DownloadLatestVersionOfChromeDriverDownloadNewVersionOfChrome(string urlToDownload)
{
if (String.IsNullOrEmpty(urlToDownload))
{
throw new ArgumentException("Unable to get url because urlToDownload is empty");
}
//Downloaded files always come as a zip, we need to do a bit of switching around to get everything in the right place
using (var client = new WebClient())
{
if (File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.zip"))
{
File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.zip");
}
client.DownloadFile(urlToDownload, "chromedriver.zip");
if (File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.zip") && File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.exe"))
{
File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.exe");
}
if (File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.zip"))
{
System.IO.Compression.ZipFile.ExtractToDirectory(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\chromedriver.zip", System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
}
}
}
Then usually I'll stick this very hacky invocation at the beginning of my application to invoke this feature and ensure that the latest chromedriver is available for my application:
//This is a very poor way of determining if I "need" to update the chromedriver,
//however I've yet to figure out a better way of doing this...
try
{
using (var chromeDriver = SetupChromeDriver())
{
chromeDriver.Navigate().GoToUrl("www.google.com");
chromeDriver.Quit();
}
}
catch
{
DownloadLatestVersionOfChromeDriver();
}
I'm sure this could be improved significantly, but so far it's worked for me.
Note: Cross Posted Here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With