package bo.gotthardt.webdriver;
import com.google.common.collect.ImmutableList;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.util.List;
import java.util.logging.Level;
/**
* Utility for creating WebDriver instances with better settings than the default.
*/
@Slf4j
public class WebDriverFactory {
private static final String WEBDRIVER_ENV_NAME = "WEBDRIVER";
private static final String REPORTS_CLASS_PREFIX = "bo.gotthardt";
/**
* Create a WebDriver instance with useful settings based on the WEBDRIVER environment variable.
* @return The WebDriver
*/
public static EventFiringWebDriver createFromEnvVar() {
String browser = System.getenv(WEBDRIVER_ENV_NAME);
if (browser == null) {
log.info("WebDriver type not specified, defaulting to Chrome.");
browser = "chrome";
}
switch (browser.toLowerCase()) {
case "firefox":
return createFirefox();
default:
log.warn("Unknown WebDriver type '{}', defaulting to Chrome.", browser);
case "chrome":
return createChrome();
}
}
/**
* Create a Firefox WebDriver instance.
* @return The WebDriver
*/
public static EventFiringWebDriver createFirefox() {
return withReports(new FirefoxDriver(getCapabilities()));
}
/**
* Create a Chrome WebDriver instance.
* @return The WebDriver
*/
public static EventFiringWebDriver createChrome() {
String chromeDriverBinary = WebDriverBinaryFinder.findChromeDriver();
System.setProperty("webdriver.chrome.driver", chromeDriverBinary);
log.info("Using ChromeDriver binary from {}", chromeDriverBinary);
// Prevent annoying yellow warning bar from being displayed.
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("excludeSwitches", ImmutableList.of("ignore-certificate-errors"));
DesiredCapabilities caps = getCapabilities();
caps.setCapability(ChromeOptions.CAPABILITY, options);
return withReports(new ChromeDriver(caps));
}
private static DesiredCapabilities getCapabilities() {
DesiredCapabilities caps = new DesiredCapabilities();
withSystemProxy(caps);
withBrowserLogs(caps);
return caps;
}
/**
* Use the system proxy (i.e. Charles) if one is running.
* This does not seem to happen automatically, even though it does happen automatically when running the browser normally.
*
* @param caps The capabilities to modify
*/
private static void withSystemProxy(DesiredCapabilities caps) {
List<Proxy> proxies = ProxySelector.getDefault().select(URI.create("http://www.google.com"));
java.net.Proxy proxy = proxies.get(0);
if (proxy.type() == java.net.Proxy.Type.HTTP) {
InetSocketAddress address = (InetSocketAddress) proxy.address();
if ("127.0.0.1".equals(address.getHostString())) {
log.info("Detected local proxy on port {}, using for WebDriver-controlled browser.", address.getPort());
caps.setCapability(CapabilityType.PROXY, new org.openqa.selenium.Proxy().setHttpProxy("localhost:" + address.getPort()));
}
}
}
private static void withBrowserLogs(DesiredCapabilities caps) {
LoggingPreferences logs = new LoggingPreferences();
logs.enable(LogType.BROWSER, Level.ALL);
caps.setCapability(CapabilityType.LOGGING_PREFS, logs);
}
private static EventFiringWebDriver withReports(WebDriver driver) {
return ReportingWebDriverEventListener.applyTo(driver, REPORTS_CLASS_PREFIX);
}
}