blob: 41c41fa8f63c02e0f6699ce2c873da2f428bfe05 [file] [log] [blame]
// <copyright file="DriverFactory.cs" company="Selenium Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// </copyright>
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Chromium;
using OpenQA.Selenium.Edge;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Safari;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace OpenQA.Selenium.Environment;
public class DriverFactory
{
private readonly string driverPath;
private readonly string browserBinaryLocation;
private readonly Dictionary<Browser, Type> serviceTypes = new Dictionary<Browser, Type>();
private readonly Dictionary<Browser, Type> optionsTypes = new Dictionary<Browser, Type>();
public DriverFactory(string driverPath, string browserBinaryLocation)
{
this.driverPath = driverPath;
this.browserBinaryLocation = browserBinaryLocation;
this.PopulateServiceTypes();
this.PopulateOptionsTypes();
}
private void PopulateOptionsTypes()
{
this.optionsTypes[Browser.Chrome] = typeof(ChromeOptions);
this.optionsTypes[Browser.Edge] = typeof(EdgeOptions);
this.optionsTypes[Browser.Firefox] = typeof(FirefoxOptions);
this.optionsTypes[Browser.IE] = typeof(InternetExplorerOptions);
this.optionsTypes[Browser.Safari] = typeof(SafariOptions);
}
private void PopulateServiceTypes()
{
this.serviceTypes[Browser.Chrome] = typeof(ChromeDriverService);
this.serviceTypes[Browser.Edge] = typeof(EdgeDriverService);
this.serviceTypes[Browser.Firefox] = typeof(FirefoxDriverService);
this.serviceTypes[Browser.IE] = typeof(InternetExplorerDriverService);
this.serviceTypes[Browser.Safari] = typeof(SafariDriverService);
}
public event EventHandler<DriverStartingEventArgs> DriverStarting;
public IWebDriver CreateDriver(Type driverType, bool logging = false)
{
return CreateDriverWithOptions(driverType, null, logging);
}
public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverOptions, bool logging = false)
{
Browser browser = Browser.All;
DriverService service = null;
DriverOptions options = null;
bool enableLogging = logging;
List<Type> constructorArgTypeList = new List<Type>();
IWebDriver driver = null;
if (typeof(ChromeDriver).IsAssignableFrom(driverType))
{
browser = Browser.Chrome;
options = GetDriverOptions<ChromeOptions>(driverType, driverOptions);
var chromeOptions = (ChromeOptions)options;
chromeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage");
service = CreateService<ChromeDriverService>();
if (!string.IsNullOrEmpty(this.browserBinaryLocation))
{
((ChromeOptions)options).BinaryLocation = this.browserBinaryLocation;
}
if (enableLogging)
{
((ChromiumDriverService)service).EnableVerboseLogging = true;
}
}
else if (typeof(EdgeDriver).IsAssignableFrom(driverType))
{
browser = Browser.Edge;
options = GetDriverOptions<EdgeOptions>(driverType, driverOptions);
var edgeOptions = (EdgeOptions)options;
edgeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage");
service = CreateService<EdgeDriverService>();
if (!string.IsNullOrEmpty(this.browserBinaryLocation))
{
((EdgeOptions)options).BinaryLocation = this.browserBinaryLocation;
}
if (enableLogging)
{
((ChromiumDriverService)service).EnableVerboseLogging = true;
}
}
else if (typeof(InternetExplorerDriver).IsAssignableFrom(driverType))
{
browser = Browser.IE;
options = GetDriverOptions<InternetExplorerOptions>(driverType, driverOptions);
service = CreateService<InternetExplorerDriverService>();
if (enableLogging)
{
((InternetExplorerDriverService)service).LoggingLevel = InternetExplorerDriverLogLevel.Trace;
}
}
else if (typeof(FirefoxDriver).IsAssignableFrom(driverType))
{
browser = Browser.Firefox;
options = GetDriverOptions<FirefoxOptions>(driverType, driverOptions);
service = CreateService<FirefoxDriverService>();
if (!string.IsNullOrEmpty(this.browserBinaryLocation))
{
((FirefoxOptions)options).BinaryLocation = this.browserBinaryLocation;
}
if (enableLogging)
{
((FirefoxDriverService)service).LogLevel = FirefoxDriverLogLevel.Trace;
}
}
else if (typeof(SafariDriver).IsAssignableFrom(driverType))
{
browser = Browser.Safari;
options = GetDriverOptions<SafariOptions>(driverType, driverOptions);
service = CreateService<SafariDriverService>();
}
if (!String.IsNullOrEmpty(this.driverPath) && service != null)
{
service.DriverServicePath = Path.GetDirectoryName(this.driverPath);
service.DriverServiceExecutableName = Path.GetFileName(this.driverPath);
}
this.OnDriverLaunching(service, options);
if (browser != Browser.All)
{
constructorArgTypeList.Add(this.serviceTypes[browser]);
constructorArgTypeList.Add(this.optionsTypes[browser]);
ConstructorInfo ctorInfo = driverType.GetConstructor(constructorArgTypeList.ToArray());
if (ctorInfo != null)
{
return (IWebDriver)ctorInfo.Invoke(new object[] { service, options });
}
}
driver = (IWebDriver)Activator.CreateInstance(driverType);
return driver;
}
protected void OnDriverLaunching(DriverService service, DriverOptions options)
{
if (this.DriverStarting != null)
{
DriverStartingEventArgs args = new DriverStartingEventArgs(service, options);
this.DriverStarting(this, args);
}
}
private T GetDriverOptions<T>(Type driverType, DriverOptions overriddenOptions) where T : DriverOptions, new()
{
T options = new T();
Type optionsType = typeof(T);
PropertyInfo defaultOptionsProperty = driverType.GetProperty("DefaultOptions", BindingFlags.Public | BindingFlags.Static);
if (defaultOptionsProperty != null && defaultOptionsProperty.PropertyType == optionsType)
{
options = (T)defaultOptionsProperty.GetValue(null, null);
}
if (overriddenOptions != null)
{
options.PageLoadStrategy = overriddenOptions.PageLoadStrategy;
options.UnhandledPromptBehavior = overriddenOptions.UnhandledPromptBehavior;
options.Proxy = overriddenOptions.Proxy;
options.ScriptTimeout = overriddenOptions.ScriptTimeout;
options.PageLoadTimeout = overriddenOptions.PageLoadTimeout;
options.ImplicitWaitTimeout = overriddenOptions.ImplicitWaitTimeout;
options.UseWebSocketUrl = overriddenOptions.UseWebSocketUrl;
}
return options;
}
private T MergeOptions<T>(object baseOptions, DriverOptions overriddenOptions) where T : DriverOptions, new()
{
// If the driver type has a static DefaultOptions property,
// get the value of that property, which should be a valid
// options of the generic type (T). Otherwise, create a new
// instance of the browser-specific options class.
T mergedOptions = new T();
if (baseOptions != null && baseOptions is T)
{
mergedOptions = (T)baseOptions;
}
if (overriddenOptions != null)
{
mergedOptions.PageLoadStrategy = overriddenOptions.PageLoadStrategy;
mergedOptions.UnhandledPromptBehavior = overriddenOptions.UnhandledPromptBehavior;
mergedOptions.Proxy = overriddenOptions.Proxy;
}
return mergedOptions;
}
private T CreateService<T>() where T : DriverService
{
T service = default(T);
Type serviceType = typeof(T);
MethodInfo createDefaultServiceMethod = serviceType.GetMethod("CreateDefaultService", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null);
if (createDefaultServiceMethod != null && createDefaultServiceMethod.ReturnType == serviceType)
{
service = (T)createDefaultServiceMethod.Invoke(null, new object[] { });
}
return service;
}
}