diff --git a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs index 489109d34f2d4..8fe31ce9249af 100644 --- a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs +++ b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs @@ -128,7 +128,7 @@ public class ChromiumDriver : WebDriver, ISupportsLogs, IDevTools /// The to be used with the ChromiumDriver. /// The maximum amount of time to wait for each command. protected ChromiumDriver(ChromiumDriverService service, ChromiumOptions options, TimeSpan commandTimeout) - : base(GenerateDriverServiceCommandExecutor(service, options, commandTimeout), ConvertOptionsToCapabilities(options)) + : base(service.CreateCommandExecutor(options, commandTimeout, searchForBrowserPath: true), ConvertOptionsToCapabilities(options)) { this.optionsCapabilityName = options.CapabilityName; } @@ -141,30 +141,6 @@ protected static IReadOnlyDictionary ChromiumCustomCommands get { return new ReadOnlyDictionary(chromiumCustomCommands); } } - /// - /// Uses DriverFinder to set Service attributes if necessary when creating the command executor - /// - /// - /// - /// - /// - private static ICommandExecutor GenerateDriverServiceCommandExecutor(DriverService service, DriverOptions options, TimeSpan commandTimeout) - { - if (service.DriverServicePath == null) - { - DriverFinder finder = new DriverFinder(options); - string fullServicePath = finder.GetDriverPath(); - service.DriverServicePath = Path.GetDirectoryName(fullServicePath); - service.DriverServiceExecutableName = Path.GetFileName(fullServicePath); - if (finder.HasBrowserPath()) - { - options.BinaryLocation = finder.GetBrowserPath(); - options.BrowserVersion = null; - } - } - return new DriverServiceCommandExecutor(service, commandTimeout); - } - /// /// Gets or sets the responsible for detecting /// sequences of keystrokes representing file paths and names. diff --git a/dotnet/src/webdriver/DriverFinder.cs b/dotnet/src/webdriver/DriverFinder.cs index 2f768af71414f..0b957779d2378 100644 --- a/dotnet/src/webdriver/DriverFinder.cs +++ b/dotnet/src/webdriver/DriverFinder.cs @@ -19,10 +19,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Text; +#nullable enable + namespace OpenQA.Selenium { /// @@ -31,17 +34,18 @@ namespace OpenQA.Selenium /// public class DriverFinder { - private DriverOptions options; - private Dictionary paths = new Dictionary(); + private readonly DriverOptions options; + private readonly Dictionary paths = new Dictionary(); private const string BrowserPathKey = "browser_path"; private const string DriverPathKey = "driver_path"; /// /// Initializes a new instance of the class. /// + /// If is . public DriverFinder(DriverOptions options) { - this.options = options; + this.options = options ?? throw new ArgumentNullException(nameof(options)); } /// @@ -66,11 +70,33 @@ public string GetDriverPath() return BinaryPaths()[DriverPathKey]; } + /// + /// Gets a value indicating whether a browser path exists, as retrieved by the Selenium Manager. + /// + /// if a browser path exists; otherwise, . public bool HasBrowserPath() { return !string.IsNullOrWhiteSpace(GetBrowserPath()); } + /// + /// Tries to get the browser path, as retrieved by Selenium Manager. + /// + /// If the method returns , the full browser path. + /// if a browser path exists; otherwise, . + public bool TryGetBrowserPath([NotNullWhen(true)] out string? browserPath) + { + string? path = GetBrowserPath(); + if (!string.IsNullOrWhiteSpace(path)) + { + browserPath = path; + return true; + } + + browserPath = null; + return false; + } + /// /// Invokes Selenium Manager to get the binaries paths and validates if they exist. /// @@ -80,29 +106,27 @@ public bool HasBrowserPath() /// If one of the paths does not exist. private Dictionary BinaryPaths() { - if (paths.ContainsKey(DriverPathKey) && !string.IsNullOrWhiteSpace(paths[DriverPathKey])) + if (paths.TryGetValue(DriverPathKey, out string? cachedDriverPath) + && !string.IsNullOrWhiteSpace(cachedDriverPath)) { return paths; } + Dictionary binaryPaths = SeleniumManager.BinaryPaths(CreateArguments()); string driverPath = binaryPaths[DriverPathKey]; string browserPath = binaryPaths[BrowserPathKey]; - if (File.Exists(driverPath)) - { - paths.Add(DriverPathKey, driverPath); - } - else + if (!File.Exists(driverPath)) { throw new NoSuchDriverException($"The driver path is not a valid file: {driverPath}"); } - if (File.Exists(browserPath)) - { - paths.Add(BrowserPathKey, browserPath); - } - else + + if (!File.Exists(browserPath)) { throw new NoSuchDriverException($"The browser path is not a valid file: {browserPath}"); } + + paths.Add(DriverPathKey, driverPath); + paths.Add(BrowserPathKey, browserPath); return paths; } diff --git a/dotnet/src/webdriver/DriverService.cs b/dotnet/src/webdriver/DriverService.cs index 80f2218ba57cc..982381558ba5b 100644 --- a/dotnet/src/webdriver/DriverService.cs +++ b/dotnet/src/webdriver/DriverService.cs @@ -428,5 +428,29 @@ private bool WaitForServiceInitialization() return isInitialized; } + + /// + /// Uses DriverFinder to set Service attributes if necessary when creating the command executor + /// + /// The to be used with the driver. + /// The maximum amount of time to wait for each command. + /// Whether to search for browser binaries. + /// A command executor. + internal DriverServiceCommandExecutor CreateCommandExecutor(DriverOptions options, TimeSpan commandTimeout, bool searchForBrowserPath) + { + if (DriverServicePath == null) + { + DriverFinder finder = new DriverFinder(options); + string fullServicePath = finder.GetDriverPath(); + DriverServicePath = Path.GetDirectoryName(fullServicePath); + DriverServiceExecutableName = Path.GetFileName(fullServicePath); + if (searchForBrowserPath && finder.TryGetBrowserPath(out string browserPath)) + { + options.BinaryLocation = browserPath; + options.BrowserVersion = null; + } + } + return new DriverServiceCommandExecutor(this, commandTimeout); + } } } diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs index 123f0eb6dc545..05155891fe36c 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs @@ -188,36 +188,12 @@ public FirefoxDriver(FirefoxDriverService service, FirefoxOptions options) /// The to be used with the Firefox driver. /// The maximum amount of time to wait for each command. public FirefoxDriver(FirefoxDriverService service, FirefoxOptions options, TimeSpan commandTimeout) - : base(GenerateDriverServiceCommandExecutor(service, options, commandTimeout), ConvertOptionsToCapabilities(options)) + : base(service.CreateCommandExecutor(options, commandTimeout, searchForBrowserPath: true), ConvertOptionsToCapabilities(options)) { // Add the custom commands unique to Firefox this.AddCustomFirefoxCommands(); } - /// - /// Uses DriverFinder to set Service attributes if necessary when creating the command executor - /// - /// - /// - /// - /// - private static ICommandExecutor GenerateDriverServiceCommandExecutor(DriverService service, DriverOptions options, TimeSpan commandTimeout) - { - if (service.DriverServicePath == null) - { - DriverFinder finder = new DriverFinder(options); - string fullServicePath = finder.GetDriverPath(); - service.DriverServicePath = Path.GetDirectoryName(fullServicePath); - service.DriverServiceExecutableName = Path.GetFileName(fullServicePath); - if (finder.HasBrowserPath()) - { - options.BinaryLocation = finder.GetBrowserPath(); - options.BrowserVersion = null; - } - } - return new DriverServiceCommandExecutor(service, commandTimeout); - } - /// /// Gets a read-only dictionary of the custom WebDriver commands defined for FirefoxDriver. /// The keys of the dictionary are the names assigned to the command; the values are the diff --git a/dotnet/src/webdriver/IE/InternetExplorerDriver.cs b/dotnet/src/webdriver/IE/InternetExplorerDriver.cs index f129ef28e2769..94a2c281f7ce8 100644 --- a/dotnet/src/webdriver/IE/InternetExplorerDriver.cs +++ b/dotnet/src/webdriver/IE/InternetExplorerDriver.cs @@ -142,29 +142,10 @@ public InternetExplorerDriver(InternetExplorerDriverService service, InternetExp /// The used to initialize the driver. /// The maximum amount of time to wait for each command. public InternetExplorerDriver(InternetExplorerDriverService service, InternetExplorerOptions options, TimeSpan commandTimeout) - : base(GenerateDriverServiceCommandExecutor(service, options, commandTimeout), ConvertOptionsToCapabilities(options)) + : base(service.CreateCommandExecutor(options, commandTimeout, searchForBrowserPath: false), ConvertOptionsToCapabilities(options)) { } - /// - /// Uses DriverFinder to set Service attributes if necessary when creating the command executor - /// - /// - /// - /// - /// - private static ICommandExecutor GenerateDriverServiceCommandExecutor(DriverService service, DriverOptions options, TimeSpan commandTimeout) - { - if (service.DriverServicePath == null) - { - DriverFinder finder = new DriverFinder(options); - string fullServicePath = finder.GetDriverPath(); - service.DriverServicePath = Path.GetDirectoryName(fullServicePath); - service.DriverServiceExecutableName = Path.GetFileName(fullServicePath); - } - return new DriverServiceCommandExecutor(service, commandTimeout); - } - /// /// Gets or sets the responsible for detecting /// sequences of keystrokes representing file paths and names. diff --git a/dotnet/src/webdriver/Safari/SafariDriver.cs b/dotnet/src/webdriver/Safari/SafariDriver.cs index b8d81c22ed56d..d14386068dbb9 100644 --- a/dotnet/src/webdriver/Safari/SafariDriver.cs +++ b/dotnet/src/webdriver/Safari/SafariDriver.cs @@ -145,32 +145,13 @@ public SafariDriver(SafariDriverService service, SafariOptions options) /// The to be used with the Safari driver. /// The maximum amount of time to wait for each command. public SafariDriver(SafariDriverService service, SafariOptions options, TimeSpan commandTimeout) - : base(GenerateDriverServiceCommandExecutor(service, options, commandTimeout), ConvertOptionsToCapabilities(options)) + : base(service.CreateCommandExecutor(options, commandTimeout, searchForBrowserPath: false), ConvertOptionsToCapabilities(options)) { this.AddCustomSafariCommand(AttachDebuggerCommand, HttpCommandInfo.PostCommand, "/session/{sessionId}/apple/attach_debugger"); this.AddCustomSafariCommand(GetPermissionsCommand, HttpCommandInfo.GetCommand, "/session/{sessionId}/apple/permissions"); this.AddCustomSafariCommand(SetPermissionsCommand, HttpCommandInfo.PostCommand, "/session/{sessionId}/apple/permissions"); } - /// - /// Uses DriverFinder to set Service attributes if necessary when creating the command executor - /// - /// - /// - /// - /// - private static ICommandExecutor GenerateDriverServiceCommandExecutor(DriverService service, DriverOptions options, TimeSpan commandTimeout) - { - if (service.DriverServicePath == null) - { - DriverFinder finder = new DriverFinder(options); - string fullServicePath = finder.GetDriverPath(); - service.DriverServicePath = Path.GetDirectoryName(fullServicePath); - service.DriverServiceExecutableName = Path.GetFileName(fullServicePath); - } - return new DriverServiceCommandExecutor(service, commandTimeout); - } - /// /// This opens Safari's Web Inspector. /// If driver subsequently executes script of "debugger;"