Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#846 and #742 FIX #863

Merged
merged 10 commits into from
Apr 10, 2018
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ compileJava {
]
}

ext.seleniumVersion = '3.9.1'
ext.seleniumVersion = '3.11.0'

dependencies {
compile ("org.seleniumhq.selenium:selenium-java:${seleniumVersion}") {
Expand Down
13 changes: 7 additions & 6 deletions src/main/java/io/appium/java_client/AppiumFluentWait.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@

package io.appium.java_client;

import static java.time.Duration.ofMillis;

import com.google.common.base.Throwables;

import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.support.ui.Clock;
import org.openqa.selenium.support.ui.Duration;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Sleeper;

import java.lang.reflect.Field;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;

Expand Down Expand Up @@ -167,7 +168,7 @@ protected T getInput() {
/**
* Sets the strategy for polling. The default strategy is null,
* which means, that polling interval is always a constant value and is
* set by {@link #pollingEvery(long, TimeUnit)} method. Otherwise the value set by that
* set by {@link #pollingEvery(Duration)} method. Otherwise the value set by that
* method might be just a helper to calculate the actual interval.
* Although, by setting an alternative polling strategy you may flexibly control
* the duration of this interval for each polling round.
Expand Down Expand Up @@ -228,7 +229,7 @@ public AppiumFluentWait<T> withPollingStrategy(Function<IterationInfo, Duration>
@Override
public <V> V until(Function<? super T, V> isTrue) {
final long start = getClock().now();
final long end = getClock().laterBy(getTimeout().in(TimeUnit.MILLISECONDS));
final long end = getClock().laterBy(getTimeout().toMillis());
long iterationNumber = 1;
Throwable lastException;
while (true) {
Expand All @@ -254,15 +255,15 @@ public <V> V until(Function<? super T, V> isTrue) {
String timeoutMessage = String.format(
"Expected condition failed: %s (tried for %d second(s) with %s interval)",
message == null ? "waiting for " + isTrue : message,
getTimeout().in(TimeUnit.SECONDS), getInterval());
getTimeout().getSeconds(), getInterval());
throw timeoutException(timeoutMessage, lastException);
}

try {
Duration interval = getInterval();
if (pollingStrategy != null) {
final IterationInfo info = new IterationInfo(iterationNumber,
new Duration(getClock().now() - start, TimeUnit.MILLISECONDS), getTimeout(),
ofMillis(getClock().now() - start), getTimeout(),
interval);
interval = pollingStrategy.apply(info);
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/io/appium/java_client/events/DefaultAspect.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class DefaultAspect {
+ ".rotate(..))";
private static final String EXECUTION_CONTEXT = "execution(* org.openqa.selenium.ContextAware."
+ "context(..))";
private static final String EXECUTION_SWITCH_TO_WINDOW = "execution(* org.openqa.selenium.WebDriver.TargetLocator"
+ ".window(..))";
private static final String AROUND = "execution(* org.openqa.selenium.WebDriver.*(..)) || "
+ "execution(* org.openqa.selenium.WebElement.*(..)) || "
+ "execution(* org.openqa.selenium.WebDriver.Navigation.*(..)) || "
Expand Down Expand Up @@ -463,6 +465,24 @@ public void afterMaximization(JoinPoint joinPoint) throws Throwable {
}
}

@Before(EXECUTION_SWITCH_TO_WINDOW)
public void beforeSwitchToWindow(JoinPoint joinPoint) throws Throwable {
try {
listener.beforeSwitchToWindow(castArgument(joinPoint, 0), driver);
} catch (Throwable t) {
throw getRootCause(t);
}
}

@After(EXECUTION_SWITCH_TO_WINDOW)
public void afterSwitchToWindow(JoinPoint joinPoint) throws Throwable {
try {
listener.afterSwitchToWindow(castArgument(joinPoint, 0), driver);
} catch (Throwable t) {
throw getRootCause(t);
}
}

@Before(EXECUTION_ROTATE)
public void beforeRotation(JoinPoint joinPoint) throws Throwable {
try {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/appium/java_client/events/DefaultListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ public void afterWindowIsMoved(WebDriver driver, WebDriver.Window window, Point
((WindowEventListener) dispatcher).afterWindowIsMaximized(driver, window);
}

@Override
public void beforeSwitchToWindow(String windowName, WebDriver driver) {
((WebDriverEventListener) dispatcher).beforeSwitchToWindow(windowName, driver);
}

@Override
public void afterSwitchToWindow(String windowName, WebDriver driver) {
((WebDriverEventListener) dispatcher).afterSwitchToWindow(windowName, driver);
}

@Override public void beforeSwitchingToContext(WebDriver driver, String context) {
((ContextEventListener) dispatcher).beforeSwitchingToContext(driver, context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,20 @@ void afterWindowIsMoved(WebDriver driver, WebDriver.Window window,
* @param window is the window which has been maximized
*/
void afterWindowIsMaximized(WebDriver driver, WebDriver.Window window);

/**
* This action will be performed each time before
* {@link org.openqa.selenium.WebDriver.TargetLocator#window(java.lang.String)}.
*
* @param driver WebDriver
*/
void beforeSwitchToWindow(String windowName, WebDriver driver);

/**
* This action will be performed each time after
* {@link org.openqa.selenium.WebDriver.TargetLocator#window(java.lang.String)}.
*
* @param driver WebDriver
*/
void afterSwitchToWindow(String windowName, WebDriver driver);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import static io.appium.java_client.pagefactory.ThrowableUtil.isStaleElementReferenceException;
import static io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.getCurrentContentType;
import static java.lang.String.format;
import static java.time.Duration.ofMillis;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import io.appium.java_client.pagefactory.bys.ContentMappedBy;
import io.appium.java_client.pagefactory.locator.CacheableLocator;
Expand All @@ -34,6 +36,7 @@
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
Expand All @@ -45,7 +48,7 @@ class AppiumElementLocator implements CacheableLocator {

private final boolean shouldCache;
private final By by;
private final TimeOutDuration duration;
private final Duration duration;
private final SearchContext searchContext;
private WebElement cachedElement;
private List<WebElement> cachedElementList;
Expand All @@ -59,11 +62,31 @@ class AppiumElementLocator implements CacheableLocator {
* @param by a By locator strategy
* @param shouldCache is the flag that signalizes that elements which
* are found once should be cached
* @param duration is a POJO which contains timeout parameters for the element to be searched
* @param duration is a POJO which contains timeout parameters for the element to be found
* @deprecated This constructor is going to be removed. Use {@link #AppiumElementLocator(SearchContext, By,
* boolean, Duration)} instead.
*/

@Deprecated
public AppiumElementLocator(SearchContext searchContext, By by, boolean shouldCache,
TimeOutDuration duration) {
this(searchContext, by, shouldCache,
ofMillis(MILLISECONDS.convert(duration.getTime(), duration.getTimeUnit())));
}

/**
* Creates a new mobile element locator. It instantiates {@link WebElement}
* using @AndroidFindBy (-s), @iOSFindBy (-s) and @FindBy (-s) annotation
* sets
*
* @param searchContext The context to use when finding the element
* @param by a By locator strategy
* @param shouldCache is the flag that signalizes that elements which
* are found once should be cached
* @param duration timeout parameter for the element to be found
*/

public AppiumElementLocator(SearchContext searchContext, By by, boolean shouldCache,
Duration duration) {
this.searchContext = searchContext;
this.shouldCache = shouldCache;
this.duration = duration;
Expand Down Expand Up @@ -94,7 +117,7 @@ private <T> T waitFor(Supplier<T> supplier) {
try {
FluentWait<Supplier<T>> wait = new FluentWait<>(supplier)
.ignoring(NoSuchElementException.class);
wait.withTimeout(duration.getTime(), duration.getTimeUnit());
wait.withTimeout(duration);
return wait.until(function);
} catch (TimeoutException e) {
if (function.foundStaleElementReferenceException != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package io.appium.java_client.pagefactory;

import static io.appium.java_client.pagefactory.WithTimeout.DurationBuilder.build;
import static java.time.Duration.ofMillis;
import static java.util.Optional.ofNullable;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import io.appium.java_client.pagefactory.bys.builder.AppiumByBuilder;
import io.appium.java_client.pagefactory.locator.CacheableElementLocatorFactory;
Expand All @@ -26,23 +29,38 @@

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.time.Duration;
import javax.annotation.Nullable;

public class AppiumElementLocatorFactory implements CacheableElementLocatorFactory {
private final SearchContext searchContext;
private final TimeOutDuration duration;
private final Duration duration;
private final AppiumByBuilder builder;

/**
* Creates a new mobile element locator factory.
*
* @param searchContext The context to use when finding the element
* @param duration is a POJO which contains timeout parameters for the element to be searched
* @param duration is a POJO which contains timeout parameters for the elements to be found
* @param builder is handler of Appium-specific page object annotations
* @deprecated This constructor is going to be
* removed. Use {@link #AppiumElementLocatorFactory(SearchContext, Duration, AppiumByBuilder)} instead.
*/

@Deprecated
public AppiumElementLocatorFactory(SearchContext searchContext, TimeOutDuration duration,
AppiumByBuilder builder) {
this(searchContext, ofMillis(MILLISECONDS.convert(duration.getTime(), duration.getTimeUnit())), builder);
}

/**
* Creates a new mobile element locator factory.
*
* @param searchContext The context to use when finding the element
* @param duration timeout parameters for the elements to be found
* @param builder is handler of Appium-specific page object annotations
*/
public AppiumElementLocatorFactory(SearchContext searchContext, Duration duration,
AppiumByBuilder builder) {
this.searchContext = searchContext;
this.duration = duration;
this.builder = builder;
Expand All @@ -53,10 +71,10 @@ public AppiumElementLocatorFactory(SearchContext searchContext, TimeOutDuration
}

@Override public @Nullable CacheableLocator createLocator(AnnotatedElement annotatedElement) {
TimeOutDuration customDuration;
Duration customDuration;
if (annotatedElement.isAnnotationPresent(WithTimeout.class)) {
WithTimeout withTimeout = annotatedElement.getAnnotation(WithTimeout.class);
customDuration = new TimeOutDuration(withTimeout.time(), withTimeout.unit());
customDuration = build(withTimeout);
} else {
customDuration = duration;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import static io.appium.java_client.internal.ElementMap.getElementClass;
import static io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy;
import static io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.unpackWebDriverFromSearchContext;
import static java.time.Duration.ofMillis;
import static java.time.Duration.ofSeconds;
import static java.util.Optional.ofNullable;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import com.google.common.collect.ImmutableList;

Expand All @@ -42,6 +45,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -62,16 +66,20 @@ public class AppiumFieldDecorator implements FieldDecorator {
private static final List<Class<? extends WebElement>> availableElementClasses = ImmutableList.of(WebElement.class,
RemoteWebElement.class, MobileElement.class, AndroidElement.class,
IOSElement.class, WindowsElement.class);
public static long DEFAULT_TIMEOUT = 1;
public static TimeUnit DEFAULT_TIMEUNIT = TimeUnit.SECONDS;
public static final Duration DEFAULT_WAITING_TIMEOUT = ofSeconds(1);
@Deprecated
public static final long DEFAULT_TIMEOUT = 1;
@Deprecated
public static final TimeUnit DEFAULT_TIMEUNIT = TimeUnit.SECONDS;
private final WebDriver webDriver;
private final DefaultFieldDecorator defaultElementFieldDecoracor;
private final AppiumElementLocatorFactory widgetLocatorFactory;
private final String platform;
private final String automation;
private final TimeOutDuration duration;
private final Duration duration;


@Deprecated
public AppiumFieldDecorator(SearchContext context, long timeout,
TimeUnit timeUnit) {
this(context, new TimeOutDuration(timeout, timeUnit));
Expand All @@ -84,8 +92,23 @@ public AppiumFieldDecorator(SearchContext context, long timeout,
* It may be the instance of {@link WebDriver} or {@link WebElement} or
* {@link Widget} or some other user's extension/implementation.
* @param duration is a desired duration of the waiting for an element presence.
* @deprecated This constructor is going to be removed. Use {@link #AppiumFieldDecorator(SearchContext, Duration)}
* instead.
*/
@Deprecated
public AppiumFieldDecorator(SearchContext context, TimeOutDuration duration) {
this(context, ofMillis(MILLISECONDS.convert(duration.getTime(), duration.getTimeUnit())));
}

/**
* Creates field decorator based on {@link SearchContext} and timeout {@code duration}.
*
* @param context is an instance of {@link SearchContext}
* It may be the instance of {@link WebDriver} or {@link WebElement} or
* {@link Widget} or some other user's extension/implementation.
* @param duration is a desired duration of the waiting for an element presence.
*/
public AppiumFieldDecorator(SearchContext context, Duration duration) {
this.webDriver = unpackWebDriverFromSearchContext(context);
HasSessionDetails hasSessionDetails = ofNullable(this.webDriver).map(webDriver -> {
if (!HasSessionDetails.class.isAssignableFrom(webDriver.getClass())) {
Expand All @@ -105,8 +128,8 @@ public AppiumFieldDecorator(SearchContext context, TimeOutDuration duration) {
this.duration = duration;

defaultElementFieldDecoracor = new DefaultFieldDecorator(
new AppiumElementLocatorFactory(context, duration,
new DefaultElementByBuilder(platform, automation))) {
new AppiumElementLocatorFactory(context, duration,
new DefaultElementByBuilder(platform, automation))) {
@Override
protected WebElement proxyForLocator(ClassLoader ignored, ElementLocator locator) {
return proxyForAnElement(locator);
Expand All @@ -115,7 +138,7 @@ protected WebElement proxyForLocator(ClassLoader ignored, ElementLocator locator
@Override
@SuppressWarnings("unchecked")
protected List<WebElement> proxyForListLocator(ClassLoader ignored,
ElementLocator locator) {
ElementLocator locator) {
ElementListInterceptor elementInterceptor = new ElementListInterceptor(locator);
return getEnhancedProxy(ArrayList.class, elementInterceptor);
}
Expand All @@ -142,11 +165,11 @@ protected List<WebElement> proxyForListLocator(ClassLoader ignored,
};

widgetLocatorFactory =
new AppiumElementLocatorFactory(context, duration, new WidgetByBuilder(platform, automation));
new AppiumElementLocatorFactory(context, duration, new WidgetByBuilder(platform, automation));
}

public AppiumFieldDecorator(SearchContext context) {
this(context, DEFAULT_TIMEOUT, DEFAULT_TIMEUNIT);
this(context, DEFAULT_WAITING_TIMEOUT);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@

/**
* Represents an duration of waiting for element rendering.
*
* @deprecated this class is going to be removed in favour of {@link java.time.Duration}
* usage.
*/
@Deprecated
public class TimeOutDuration {

private long time;
Expand Down
Loading