org.openqa.selenium.remote.RemoteWebDriver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of selenium-remote-driver Show documentation
Show all versions of selenium-remote-driver Show documentation
Selenium automates browsers. That's it! What you do with that power is entirely up to you.
// 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.
package org.openqa.selenium.remote;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.openqa.selenium.remote.CapabilityType.LOGGING_PREFS;
import static org.openqa.selenium.remote.CapabilityType.PLATFORM;
import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;
import static org.openqa.selenium.remote.CapabilityType.SUPPORTS_JAVASCRIPT;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.openqa.selenium.Alert;
import org.openqa.selenium.Beta;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.NoSuchFrameException;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Platform;
import org.openqa.selenium.Point;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.HasInputDevices;
import org.openqa.selenium.interactions.Interactive;
import org.openqa.selenium.interactions.Keyboard;
import org.openqa.selenium.interactions.Mouse;
import org.openqa.selenium.interactions.Sequence;
import org.openqa.selenium.internal.FindsByClassName;
import org.openqa.selenium.internal.FindsByCssSelector;
import org.openqa.selenium.internal.FindsById;
import org.openqa.selenium.internal.FindsByLinkText;
import org.openqa.selenium.internal.FindsByName;
import org.openqa.selenium.internal.FindsByTagName;
import org.openqa.selenium.internal.FindsByXPath;
import org.openqa.selenium.logging.LocalLogs;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingHandler;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.logging.Logs;
import org.openqa.selenium.logging.NeedsLocalLogs;
import org.openqa.selenium.remote.internal.JsonToWebElementConverter;
import org.openqa.selenium.remote.internal.WebElementToJsonConverter;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Augmentable
public class RemoteWebDriver implements WebDriver, JavascriptExecutor,
FindsById, FindsByClassName, FindsByLinkText, FindsByName,
FindsByCssSelector, FindsByTagName, FindsByXPath,
HasInputDevices, HasCapabilities, Interactive, TakesScreenshot {
// TODO(dawagner): This static logger should be unified with the per-instance localLogs
private static final Logger logger = Logger.getLogger(RemoteWebDriver.class.getName());
private Level level = Level.FINE;
private ErrorHandler errorHandler = new ErrorHandler();
private CommandExecutor executor;
private Capabilities capabilities;
private SessionId sessionId;
private FileDetector fileDetector = new UselessFileDetector();
private ExecuteMethod executeMethod;
private JsonToWebElementConverter converter;
private RemoteKeyboard keyboard;
private RemoteMouse mouse;
private Logs remoteLogs;
private LocalLogs localLogs;
// For cglib
protected RemoteWebDriver() {
init(new ImmutableCapabilities());
}
public RemoteWebDriver(Capabilities capabilities) {
this(new HttpCommandExecutor(null), capabilities);
}
public RemoteWebDriver(CommandExecutor executor, Capabilities capabilities) {
this.executor = executor;
init(capabilities);
if (executor instanceof NeedsLocalLogs) {
((NeedsLocalLogs)executor).setLocalLogs(localLogs);
}
try {
startSession(capabilities);
} catch (RuntimeException e) {
try {
quit();
} catch (Exception ignored) {
// Ignore the clean-up exception. We'll propagate the original failure.
}
throw e;
}
}
public RemoteWebDriver(URL remoteAddress, Capabilities capabilities) {
this(new HttpCommandExecutor(remoteAddress), capabilities);
}
@Beta
public static RemoteWebDriverBuilder builder() {
return new RemoteWebDriverBuilder();
}
private void init(Capabilities capabilities) {
capabilities = capabilities == null ? new ImmutableCapabilities() : capabilities;
logger.addHandler(LoggingHandler.getInstance());
converter = new JsonToWebElementConverter(this);
executeMethod = new RemoteExecuteMethod(this);
keyboard = new RemoteKeyboard(executeMethod);
mouse = new RemoteMouse(executeMethod);
ImmutableSet.Builder builder = new ImmutableSet.Builder<>();
boolean isProfilingEnabled = capabilities.is(CapabilityType.ENABLE_PROFILING_CAPABILITY);
if (isProfilingEnabled) {
builder.add(LogType.PROFILER);
}
LoggingPreferences mergedLoggingPrefs = new LoggingPreferences();
mergedLoggingPrefs.addPreferences((LoggingPreferences) capabilities.getCapability(LOGGING_PREFS));
if (!mergedLoggingPrefs.getEnabledLogTypes().contains(LogType.CLIENT) ||
mergedLoggingPrefs.getLevel(LogType.CLIENT) != Level.OFF) {
builder.add(LogType.CLIENT);
}
Set logTypesToInclude = builder.build();
LocalLogs performanceLogger = LocalLogs.getStoringLoggerInstance(logTypesToInclude);
LocalLogs clientLogs = LocalLogs.getHandlerBasedLoggerInstance(LoggingHandler.getInstance(),
logTypesToInclude);
localLogs = LocalLogs.getCombinedLogsHolder(clientLogs, performanceLogger);
remoteLogs = new RemoteLogs(executeMethod, localLogs);
}
/**
* Set the file detector to be used when sending keyboard input. By default, this is set to a file
* detector that does nothing.
*
* @param detector The detector to use. Must not be null.
* @see FileDetector
* @see LocalFileDetector
* @see UselessFileDetector
*/
public void setFileDetector(FileDetector detector) {
if (detector == null) {
throw new WebDriverException("You may not set a file detector that is null");
}
fileDetector = detector;
}
public SessionId getSessionId() {
return sessionId;
}
protected void setSessionId(String opaqueKey) {
sessionId = new SessionId(opaqueKey);
}
protected void startSession(Capabilities capabilities) {
Map parameters = ImmutableMap.of("desiredCapabilities", capabilities);
Response response = execute(DriverCommand.NEW_SESSION, parameters);
Map rawCapabilities = (Map) response.getValue();
MutableCapabilities returnedCapabilities = new MutableCapabilities();
for (Map.Entry entry : rawCapabilities.entrySet()) {
// Handle the platform later
if (PLATFORM.equals(entry.getKey()) || PLATFORM_NAME.equals(entry.getKey())) {
continue;
}
returnedCapabilities.setCapability(entry.getKey(), entry.getValue());
}
String platformString = (String) rawCapabilities.getOrDefault(PLATFORM,
rawCapabilities.get(PLATFORM_NAME));
Platform platform;
try {
if (platformString == null || "".equals(platformString)) {
platform = Platform.ANY;
} else {
platform = Platform.fromString(platformString);
}
} catch (WebDriverException e) {
// The server probably responded with a name matching the os.name
// system property. Try to recover and parse this.
platform = Platform.extractFromSysProperty(platformString);
}
returnedCapabilities.setCapability(PLATFORM, platform);
returnedCapabilities.setCapability(PLATFORM_NAME, platform);
if (rawCapabilities.containsKey(SUPPORTS_JAVASCRIPT)) {
Object raw = rawCapabilities.get(SUPPORTS_JAVASCRIPT);
if (raw instanceof String) {
returnedCapabilities.setCapability(SUPPORTS_JAVASCRIPT, Boolean.parseBoolean((String) raw));
} else if (raw instanceof Boolean) {
returnedCapabilities.setCapability(SUPPORTS_JAVASCRIPT, ((Boolean) raw).booleanValue());
}
} else {
returnedCapabilities.setCapability(SUPPORTS_JAVASCRIPT, true);
}
this.capabilities = returnedCapabilities;
sessionId = new SessionId(response.getSessionId());
}
public ErrorHandler getErrorHandler() {
return errorHandler;
}
public void setErrorHandler(ErrorHandler handler) {
this.errorHandler = handler;
}
public CommandExecutor getCommandExecutor() {
return executor;
}
protected void setCommandExecutor(CommandExecutor executor) {
this.executor = executor;
}
public Capabilities getCapabilities() {
return capabilities;
}
public void get(String url) {
execute(DriverCommand.GET, ImmutableMap.of("url", url));
}
public String getTitle() {
Response response = execute(DriverCommand.GET_TITLE);
Object value = response.getValue();
return value == null ? "" : value.toString();
}
public String getCurrentUrl() {
Response response = execute(DriverCommand.GET_CURRENT_URL);
if (response == null || response.getValue() == null) {
throw new WebDriverException("Remote browser did not respond to getCurrentUrl");
}
return response.getValue().toString();
}
public X getScreenshotAs(OutputType outputType) throws WebDriverException {
Response response = execute(DriverCommand.SCREENSHOT);
Object result = response.getValue();
if (result instanceof String) {
String base64EncodedPng = (String) result;
return outputType.convertFromBase64Png(base64EncodedPng);
} else if (result instanceof byte[]) {
String base64EncodedPng = new String((byte[]) result);
return outputType.convertFromBase64Png(base64EncodedPng);
} else {
throw new RuntimeException(String.format("Unexpected result for %s command: %s",
DriverCommand.SCREENSHOT,
result == null ? "null" : result.getClass().getName() + " instance"));
}
}
public List findElements(By by) {
return by.findElements(this);
}
public WebElement findElement(By by) {
return by.findElement(this);
}
protected WebElement findElement(String by, String using) {
if (using == null) {
throw new IllegalArgumentException("Cannot find elements when the selector is null.");
}
Response response = execute(DriverCommand.FIND_ELEMENT,
ImmutableMap.of("using", by, "value", using));
Object value = response.getValue();
if (value == null) { // see https://github.com/SeleniumHQ/selenium/issues/5809
throw new NoSuchElementException(String.format("Cannot locate an element using %s=%s", by, using));
}
WebElement element;
try {
element = (WebElement) value;
} catch (ClassCastException ex) {
throw new WebDriverException("Returned value cannot be converted to WebElement: " + value, ex);
}
setFoundBy(this, element, by, using);
return element;
}
protected void setFoundBy(SearchContext context, WebElement element, String by, String using) {
if (element instanceof RemoteWebElement) {
RemoteWebElement remoteElement = (RemoteWebElement) element;
remoteElement.setFoundBy(context, by, using);
remoteElement.setFileDetector(getFileDetector());
}
}
@SuppressWarnings("unchecked")
protected List findElements(String by, String using) {
if (using == null) {
throw new IllegalArgumentException("Cannot find elements when the selector is null.");
}
Response response = execute(DriverCommand.FIND_ELEMENTS,
ImmutableMap.of("using", by, "value", using));
Object value = response.getValue();
if (value == null) { // see https://github.com/SeleniumHQ/selenium/issues/4555
return Collections.emptyList();
}
List allElements;
try {
allElements = (List) value;
} catch (ClassCastException ex) {
throw new WebDriverException("Returned value cannot be converted to List: " + value, ex);
}
for (WebElement element : allElements) {
setFoundBy(this, element, by, using);
}
return allElements;
}
public WebElement findElementById(String using) {
return findElement("id", using);
}
public List findElementsById(String using) {
return findElements("id", using);
}
public WebElement findElementByLinkText(String using) {
return findElement("link text", using);
}
public List findElementsByLinkText(String using) {
return findElements("link text", using);
}
public WebElement findElementByPartialLinkText(String using) {
return findElement("partial link text", using);
}
public List findElementsByPartialLinkText(String using) {
return findElements("partial link text", using);
}
public WebElement findElementByTagName(String using) {
return findElement("tag name", using);
}
public List findElementsByTagName(String using) {
return findElements("tag name", using);
}
public WebElement findElementByName(String using) {
return findElement("name", using);
}
public List findElementsByName(String using) {
return findElements("name", using);
}
public WebElement findElementByClassName(String using) {
return findElement("class name", using);
}
public List findElementsByClassName(String using) {
return findElements("class name", using);
}
public WebElement findElementByCssSelector(String using) {
return findElement("css selector", using);
}
public List findElementsByCssSelector(String using) {
return findElements("css selector", using);
}
public WebElement findElementByXPath(String using) {
return findElement("xpath", using);
}
public List findElementsByXPath(String using) {
return findElements("xpath", using);
}
// Misc
public String getPageSource() {
return (String) execute(DriverCommand.GET_PAGE_SOURCE).getValue();
}
public void close() {
execute(DriverCommand.CLOSE);
}
public void quit() {
// no-op if session id is null. We're only going to make ourselves unhappy
if (sessionId == null) {
return;
}
try {
execute(DriverCommand.QUIT);
} finally {
sessionId = null;
}
}
@SuppressWarnings({"unchecked"})
public Set getWindowHandles() {
Response response = execute(DriverCommand.GET_WINDOW_HANDLES);
Object value = response.getValue();
try {
List returnedValues = (List) value;
return new LinkedHashSet<>(returnedValues);
} catch (ClassCastException ex) {
throw new WebDriverException(
"Returned value cannot be converted to List: " + value, ex);
}
}
public String getWindowHandle() {
return String.valueOf(execute(DriverCommand.GET_CURRENT_WINDOW_HANDLE).getValue());
}
public Object executeScript(String script, Object... args) {
if (!isJavascriptEnabled()) {
throw new UnsupportedOperationException(
"You must be using an underlying instance of WebDriver that supports executing javascript");
}
// Escape the quote marks
script = script.replaceAll("\"", "\\\"");
List