Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.openqa.selenium.support.events.EventFiringWebDriver Maven / Gradle / Ivy
// 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.support.events;
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.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.Rectangle;
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.HasTouchScreen;
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.interactions.TouchScreen;
import org.openqa.selenium.interactions.internal.Coordinates;
import org.openqa.selenium.interactions.internal.Locatable;
import org.openqa.selenium.WrapsDriver;
import org.openqa.selenium.WrapsElement;
import org.openqa.selenium.logging.Logs;
import org.openqa.selenium.support.events.internal.EventFiringKeyboard;
import org.openqa.selenium.support.events.internal.EventFiringMouse;
import org.openqa.selenium.support.events.internal.EventFiringTouch;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* A wrapper around an arbitrary {@link WebDriver} instance which supports registering of a
* {@link WebDriverEventListener}, e.g. for logging purposes.
*/
public class EventFiringWebDriver implements WebDriver, JavascriptExecutor, TakesScreenshot,
WrapsDriver, HasInputDevices, HasTouchScreen,
Interactive, HasCapabilities {
private final WebDriver driver;
private final List eventListeners =
new ArrayList<>();
private final WebDriverEventListener dispatcher = (WebDriverEventListener) Proxy
.newProxyInstance(
WebDriverEventListener.class.getClassLoader(),
new Class[] {WebDriverEventListener.class},
(proxy, method, args) -> {
try {
for (WebDriverEventListener eventListener : eventListeners) {
method.invoke(eventListener, args);
}
return null;
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
);
public EventFiringWebDriver(final WebDriver driver) {
Class>[] allInterfaces = extractInterfaces(driver);
this.driver = (WebDriver) Proxy.newProxyInstance(
WebDriverEventListener.class.getClassLoader(),
allInterfaces,
(proxy, method, args) -> {
if ("getWrappedDriver".equals(method.getName())) {
return driver;
}
try {
return method.invoke(driver, args);
} catch (InvocationTargetException e) {
dispatcher.onException(e.getTargetException(), driver);
throw e.getTargetException();
}
}
);
}
private Class>[] extractInterfaces(Object object) {
Set> allInterfaces = new HashSet<>();
allInterfaces.add(WrapsDriver.class);
if (object instanceof WebElement) {
allInterfaces.add(WrapsElement.class);
}
extractInterfaces(allInterfaces, object.getClass());
return allInterfaces.toArray(new Class>[allInterfaces.size()]);
}
private void extractInterfaces(Set> addTo, Class> clazz) {
if (Object.class.equals(clazz)) {
return; // Done
}
Class>[] classes = clazz.getInterfaces();
addTo.addAll(Arrays.asList(classes));
extractInterfaces(addTo, clazz.getSuperclass());
}
/**
* @param eventListener the event listener to register
* @return this for method chaining.
*/
public EventFiringWebDriver register(WebDriverEventListener eventListener) {
eventListeners.add(eventListener);
return this;
}
/**
* @param eventListener the event listener to unregister
* @return this for method chaining.
*/
public EventFiringWebDriver unregister(WebDriverEventListener eventListener) {
eventListeners.remove(eventListener);
return this;
}
@Override
public WebDriver getWrappedDriver() {
if (driver instanceof WrapsDriver) {
return ((WrapsDriver) driver).getWrappedDriver();
}
return driver;
}
@Override
public void get(String url) {
dispatcher.beforeNavigateTo(url, driver);
driver.get(url);
dispatcher.afterNavigateTo(url, driver);
}
@Override
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
@Override
public String getTitle() {
return driver.getTitle();
}
@Override
public List findElements(By by) {
dispatcher.beforeFindBy(by, null, driver);
List temp = driver.findElements(by);
dispatcher.afterFindBy(by, null, driver);
List result = new ArrayList<>(temp.size());
for (WebElement element : temp) {
result.add(createWebElement(element));
}
return result;
}
@Override
public WebElement findElement(By by) {
dispatcher.beforeFindBy(by, null, driver);
WebElement temp = driver.findElement(by);
dispatcher.afterFindBy(by, temp, driver);
return createWebElement(temp);
}
@Override
public String getPageSource() {
return driver.getPageSource();
}
@Override
public void close() {
driver.close();
}
@Override
public void quit() {
driver.quit();
}
@Override
public Set getWindowHandles() {
return driver.getWindowHandles();
}
@Override
public String getWindowHandle() {
return driver.getWindowHandle();
}
@Override
public Object executeScript(String script, Object... args) {
if (driver instanceof JavascriptExecutor) {
dispatcher.beforeScript(script, driver);
Object[] usedArgs = unpackWrappedArgs(args);
Object result = ((JavascriptExecutor) driver).executeScript(script, usedArgs);
dispatcher.afterScript(script, driver);
return wrapResult(result);
}
throw new UnsupportedOperationException(
"Underlying driver instance does not support executing javascript");
}
@Override
public Object executeAsyncScript(String script, Object... args) {
if (driver instanceof JavascriptExecutor) {
dispatcher.beforeScript(script, driver);
Object[] usedArgs = unpackWrappedArgs(args);
Object result = ((JavascriptExecutor) driver).executeAsyncScript(script, usedArgs);
dispatcher.afterScript(script, driver);
return result;
}
throw new UnsupportedOperationException(
"Underlying driver instance does not support executing javascript");
}
private Object[] unpackWrappedArgs(Object... args) {
// Walk the args: the various drivers expect unpacked versions of the elements
Object[] usedArgs = new Object[args.length];
for (int i = 0; i < args.length; i++) {
usedArgs[i] = unpackWrappedElement(args[i]);
}
return usedArgs;
}
private Object unpackWrappedElement(Object arg) {
if (arg instanceof List>) {
List> aList = (List>) arg;
List toReturn = new ArrayList<>();
for (Object anAList : aList) {
toReturn.add(unpackWrappedElement(anAList));
}
return toReturn;
} else if (arg instanceof Map, ?>) {
Map, ?> aMap = (Map, ?>) arg;
Map toReturn = new HashMap<>();
for (Object key : aMap.keySet()) {
toReturn.put(key, unpackWrappedElement(aMap.get(key)));
}
return toReturn;
} else if (arg instanceof EventFiringWebElement) {
return ((EventFiringWebElement) arg).getWrappedElement();
} else {
return arg;
}
}
private Object wrapResult(Object result) {
if (result instanceof WebElement) {
return new EventFiringWebElement((WebElement) result);
}
if (result instanceof List) {
return ((List>) result).stream().map(this::wrapResult).collect(Collectors.toList());
}
if (result instanceof Map) {
return ((Map, ?>) result).entrySet().stream().collect(
HashMap::new,
(m, e) -> m.put(e.getKey(), e.getValue()),
Map::putAll);
}
return result;
}
@Override
public X getScreenshotAs(OutputType target) throws WebDriverException {
if (driver instanceof TakesScreenshot) {
dispatcher.beforeGetScreenshotAs(target);
X screenshot = ((TakesScreenshot) driver).getScreenshotAs(target);
dispatcher.afterGetScreenshotAs(target, screenshot);
return screenshot;
}
throw new UnsupportedOperationException(
"Underlying driver instance does not support taking screenshots");
}
@Override
public TargetLocator switchTo() {
return new EventFiringTargetLocator(driver.switchTo());
}
@Override
public Navigation navigate() {
return new EventFiringNavigation(driver.navigate());
}
@Override
public Options manage() {
return new EventFiringOptions(driver.manage());
}
private WebElement createWebElement(WebElement from) {
return new EventFiringWebElement(from);
}
@Override
public Keyboard getKeyboard() {
if (driver instanceof HasInputDevices) {
return new EventFiringKeyboard(driver, dispatcher);
}
throw new UnsupportedOperationException("Underlying driver does not implement advanced"
+ " user interactions yet.");
}
@Override
public Mouse getMouse() {
if (driver instanceof HasInputDevices) {
return new EventFiringMouse(driver, dispatcher);
}
throw new UnsupportedOperationException("Underlying driver does not implement advanced"
+ " user interactions yet.");
}
@Override
public TouchScreen getTouch() {
if (driver instanceof HasTouchScreen) {
return new EventFiringTouch(driver, dispatcher);
}
throw new UnsupportedOperationException("Underlying driver does not implement advanced"
+ " user interactions yet.");
}
@Override
public void perform(Collection actions) {
if (driver instanceof Interactive) {
((Interactive) driver).perform(actions);
return;
}
throw new UnsupportedOperationException("Underlying driver does not implement advanced"
+ " user interactions yet.");
}
@Override
public void resetInputState() {
if (driver instanceof Interactive) {
((Interactive) driver).resetInputState();
return;
}
throw new UnsupportedOperationException("Underlying driver does not implement advanced"
+ " user interactions yet.");
}
@Override
public Capabilities getCapabilities() {
if (driver instanceof HasCapabilities) {
return ((HasCapabilities) driver).getCapabilities();
}
throw new UnsupportedOperationException(
"Underlying driver does not implement getting capabilities yet.");
}
private class EventFiringWebElement implements WebElement, WrapsElement, WrapsDriver, Locatable {
private final WebElement element;
private final WebElement underlyingElement;
private EventFiringWebElement(final WebElement element) {
this.element = (WebElement) Proxy.newProxyInstance(
WebDriverEventListener.class.getClassLoader(),
extractInterfaces(element),
(proxy, method, args) -> {
if (method.getName().equals("getWrappedElement")) {
return element;
}
try {
return method.invoke(element, args);
} catch (InvocationTargetException e) {
dispatcher.onException(e.getTargetException(), driver);
throw e.getTargetException();
}
}
);
this.underlyingElement = element;
}
@Override
public void click() {
dispatcher.beforeClickOn(element, driver);
element.click();
dispatcher.afterClickOn(element, driver);
}
@Override
public void submit() {
element.submit();
}
@Override
public void sendKeys(CharSequence... keysToSend) {
dispatcher.beforeChangeValueOf(element, driver, keysToSend);
element.sendKeys(keysToSend);
dispatcher.afterChangeValueOf(element, driver, keysToSend);
}
@Override
public void clear() {
dispatcher.beforeChangeValueOf(element, driver, null);
element.clear();
dispatcher.afterChangeValueOf(element, driver, null);
}
@Override
public String getTagName() {
return element.getTagName();
}
@Override
public String getAttribute(String name) {
return element.getAttribute(name);
}
@Override
public boolean isSelected() {
return element.isSelected();
}
@Override
public boolean isEnabled() {
return element.isEnabled();
}
@Override
public String getText() {
dispatcher.beforeGetText(element, driver);
String text = element.getText();
dispatcher.afterGetText(element, driver, text);
return text;
}
@Override
public boolean isDisplayed() {
return element.isDisplayed();
}
@Override
public Point getLocation() {
return element.getLocation();
}
@Override
public Dimension getSize() {
return element.getSize();
}
@Override
public Rectangle getRect() {
return element.getRect();
}
@Override
public String getCssValue(String propertyName) {
return element.getCssValue(propertyName);
}
@Override
public WebElement findElement(By by) {
dispatcher.beforeFindBy(by, element, driver);
WebElement temp = element.findElement(by);
dispatcher.afterFindBy(by, element, driver);
return createWebElement(temp);
}
@Override
public List findElements(By by) {
dispatcher.beforeFindBy(by, element, driver);
List temp = element.findElements(by);
dispatcher.afterFindBy(by, element, driver);
List result = new ArrayList<>(temp.size());
for (WebElement element : temp) {
result.add(createWebElement(element));
}
return result;
}
@Override
public WebElement getWrappedElement() {
return underlyingElement;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WebElement)) {
return false;
}
WebElement other = (WebElement) obj;
if (other instanceof WrapsElement) {
other = ((WrapsElement) other).getWrappedElement();
}
return underlyingElement.equals(other);
}
@Override
public int hashCode() {
return underlyingElement.hashCode();
}
@Override
public String toString() {
return underlyingElement.toString();
}
@Override
public WebDriver getWrappedDriver() {
return driver;
}
@Override
public Coordinates getCoordinates() {
return ((Locatable) underlyingElement).getCoordinates();
}
@Override
public X getScreenshotAs(OutputType outputType) throws WebDriverException {
return element.getScreenshotAs(outputType);
}
}
private class EventFiringNavigation implements Navigation {
private final WebDriver.Navigation navigation;
EventFiringNavigation(Navigation navigation) {
this.navigation = navigation;
}
@Override
public void to(String url) {
dispatcher.beforeNavigateTo(url, driver);
navigation.to(url);
dispatcher.afterNavigateTo(url, driver);
}
@Override
public void to(URL url) {
to(String.valueOf(url));
}
@Override
public void back() {
dispatcher.beforeNavigateBack(driver);
navigation.back();
dispatcher.afterNavigateBack(driver);
}
@Override
public void forward() {
dispatcher.beforeNavigateForward(driver);
navigation.forward();
dispatcher.afterNavigateForward(driver);
}
@Override
public void refresh() {
dispatcher.beforeNavigateRefresh(driver);
navigation.refresh();
dispatcher.afterNavigateRefresh(driver);
}
}
private class EventFiringOptions implements Options {
private Options options;
private EventFiringOptions(Options options) {
this.options = options;
}
@Override
public Logs logs() {
return options.logs();
}
@Override
public void addCookie(Cookie cookie) {
options.addCookie(cookie);
}
@Override
public void deleteCookieNamed(String name) {
options.deleteCookieNamed(name);
}
@Override
public void deleteCookie(Cookie cookie) {
options.deleteCookie(cookie);
}
@Override
public void deleteAllCookies() {
options.deleteAllCookies();
}
@Override
public Set getCookies() {
return options.getCookies();
}
@Override
public Cookie getCookieNamed(String name) {
return options.getCookieNamed(name);
}
@Override
public Timeouts timeouts() {
return new EventFiringTimeouts(options.timeouts());
}
@Override
public ImeHandler ime() {
return options.ime();
}
@Override
@Beta
public Window window() {
return new EventFiringWindow(options.window());
}
}
private class EventFiringTimeouts implements Timeouts {
private final Timeouts timeouts;
EventFiringTimeouts(Timeouts timeouts) {
this.timeouts = timeouts;
}
@Override
public Timeouts implicitlyWait(long time, TimeUnit unit) {
timeouts.implicitlyWait(time, unit);
return this;
}
@Override
public Timeouts setScriptTimeout(long time, TimeUnit unit) {
timeouts.setScriptTimeout(time, unit);
return this;
}
@Override
public Timeouts pageLoadTimeout(long time, TimeUnit unit) {
timeouts.pageLoadTimeout(time, unit);
return this;
}
}
private class EventFiringTargetLocator implements TargetLocator {
private TargetLocator targetLocator;
private EventFiringTargetLocator(TargetLocator targetLocator) {
this.targetLocator = targetLocator;
}
@Override
public WebDriver frame(int frameIndex) {
return targetLocator.frame(frameIndex);
}
@Override
public WebDriver frame(String frameName) {
return targetLocator.frame(frameName);
}
@Override
public WebDriver frame(WebElement frameElement) {
return targetLocator.frame(frameElement);
}
@Override
public WebDriver parentFrame() {
return targetLocator.parentFrame();
}
@Override
public WebDriver window(String windowName) {
dispatcher.beforeSwitchToWindow(windowName, driver);
WebDriver driverToReturn = targetLocator.window(windowName);
dispatcher.afterSwitchToWindow(windowName, driver);
return driverToReturn;
}
@Override
public WebDriver defaultContent() {
return targetLocator.defaultContent();
}
@Override
public WebElement activeElement() {
return targetLocator.activeElement();
}
@Override
public Alert alert() {
return new EventFiringAlert(this.targetLocator.alert());
}
}
@Beta
private class EventFiringWindow implements Window {
private final Window window;
EventFiringWindow(Window window) {
this.window = window;
}
@Override
public void setSize(Dimension targetSize) {
window.setSize(targetSize);
}
@Override
public void setPosition(Point targetLocation) {
window.setPosition(targetLocation);
}
@Override
public Dimension getSize() {
return window.getSize();
}
@Override
public Point getPosition() {
return window.getPosition();
}
@Override
public void maximize() {
window.maximize();
}
@Override
public void fullscreen() {
window.fullscreen();
}
}
private class EventFiringAlert implements Alert {
private final Alert alert;
private EventFiringAlert(Alert alert) {
this.alert = alert;
}
@Override
public void dismiss() {
dispatcher.beforeAlertDismiss(driver);
alert.dismiss();
dispatcher.afterAlertDismiss(driver);
}
@Override
public void accept() {
dispatcher.beforeAlertAccept(driver);
alert.accept();
dispatcher.afterAlertAccept(driver);
}
@Override
public String getText() {
return alert.getText();
}
@Override
public void sendKeys(String keysToSend) {
alert.sendKeys(keysToSend);
}
}
}