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

Fix #184 Fix #211 #213

Merged
merged 2 commits into from
Jul 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.appium.java_client.pagefactory;

import static io.appium.java_client.remote.MobilePlatform.*;
import static io.appium.java_client.remote.AutomationName.*;
import io.appium.java_client.MobileBy;

import java.lang.annotation.Annotation;
Expand Down Expand Up @@ -300,7 +301,7 @@ public By buildBy() {
SelendroidFindBy selendroidBy = mobileField
.getAnnotation(SelendroidFindBy.class);
if (selendroidBy != null && ANDROID.toUpperCase().equals(platform)
&& "Selendroid".toUpperCase().equals(automation)) {
&& SELENDROID.toUpperCase().equals(automation)) {
return setByForTheNativeContentAndReturn(
getMobileBy(selendroidBy, getFilledValue(selendroidBy)),
contentMap);
Expand All @@ -309,7 +310,7 @@ public By buildBy() {
SelendroidFindBys selendroidBys = mobileField
.getAnnotation(SelendroidFindBys.class);
if (selendroidBys != null && ANDROID.toUpperCase().equals(platform)
&& "Selendroid".toUpperCase().equals(automation)) {
&& SELENDROID.toUpperCase().equals(automation)) {
return setByForTheNativeContentAndReturn(
getComplexMobileBy(selendroidBys.value(), ByChained.class),
contentMap);
Expand All @@ -318,7 +319,7 @@ public By buildBy() {
SelendroidFindAll selendroidAll = mobileField
.getAnnotation(SelendroidFindAll.class);
if (selendroidAll != null && ANDROID.toUpperCase().equals(platform)
&& "Selendroid".toUpperCase().equals(automation)) {
&& SELENDROID.toUpperCase().equals(automation)) {
return setByForTheNativeContentAndReturn(
getComplexMobileBy(selendroidAll.value(), ByAll.class),
contentMap);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package io.appium.java_client.pagefactory;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.remote.MobileCapabilityType;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import io.appium.java_client.remote.MobilePlatform;
import org.openqa.selenium.*;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import org.openqa.selenium.support.ui.FluentWait;

Expand All @@ -26,6 +22,7 @@ class AppiumElementLocator implements ElementLocator {
private static class WaitingFunction implements
Function<By, List<WebElement>> {
private final SearchContext searchContext;
private final static String INVALID_SELECTOR_PATTERN = "Invalid locator strategy:";

private WaitingFunction(SearchContext searchContext) {
this.searchContext = searchContext;
Expand All @@ -37,12 +34,26 @@ public List<WebElement> apply(By by) {
result.addAll(searchContext.findElements(by));
} catch (StaleElementReferenceException ignored) {
}
catch (RuntimeException e){
if (!isInvalidSelectorRootCause(e))
throw e;
}
if (result.size() > 0) {
return result;
} else {
return null;
}
}

private static boolean isInvalidSelectorRootCause(Throwable e){
if (e == null)
return false;

if (String.valueOf(e.getMessage()).contains(INVALID_SELECTOR_PATTERN))
return true;

return isInvalidSelectorRootCause(e.getCause());
}
}

private final SearchContext searchContext;
Expand All @@ -66,15 +77,9 @@ public List<WebElement> apply(By by) {
AppiumElementLocator(SearchContext searchContext, Field field,
TimeOutDuration timeOutDuration) {
this.searchContext = searchContext;
// All known webdrivers implement HasCapabilities
Capabilities capabilities = ((HasCapabilities) WebDriverUnpackUtility.
unpackWebDriverFromSearchContext(this.searchContext))
.getCapabilities();

String platform = String.valueOf(capabilities
.getCapability(MobileCapabilityType.PLATFORM_NAME));
String automation = String.valueOf(capabilities
.getCapability(MobileCapabilityType.AUTOMATION_NAME));
String platform = getPlatform();
String automation = getAutomation();

AppiumAnnotations annotations = new AppiumAnnotations(field, platform,
automation);
Expand All @@ -88,6 +93,42 @@ public List<WebElement> apply(By by) {
by = annotations.buildBy();
}

private String getPlatform(){
WebDriver d = WebDriverUnpackUtility.
unpackWebDriverFromSearchContext(this.searchContext);
if (d == null)
return null;

Class<?> driverClass = d.getClass();
if (AndroidDriver.class.isAssignableFrom(driverClass))
return MobilePlatform.ANDROID;

if (IOSDriver.class.isAssignableFrom(driverClass))
return MobilePlatform.IOS;

//it is possible that somebody uses RemoteWebDriver or their
//own WebDriver implementation. At this case capabilities are used
//to detect platform
if (HasCapabilities.class.isAssignableFrom(driverClass))
return String.valueOf(((HasCapabilities) d).getCapabilities().
getCapability(MobileCapabilityType.PLATFORM_NAME));

return null;
}

private String getAutomation(){
WebDriver d = WebDriverUnpackUtility.
unpackWebDriverFromSearchContext(this.searchContext);
if (d == null)
return null;

if (HasCapabilities.class.isAssignableFrom(d.getClass()))
return String.valueOf(((HasCapabilities) d).getCapabilities().
getCapability(MobileCapabilityType.AUTOMATION_NAME));

return null;
}

private void changeImplicitlyWaitTimeOut(long newTimeOut,
TimeUnit newTimeUnit) {
WebDriverUnpackUtility.unpackWebDriverFromSearchContext(searchContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private By returnRelevantBy(SearchContext context){
if (!ContextAware.class.isAssignableFrom(driver.getClass())){ //it is desktop browser
return map.get(ContentType.HTML);
}

ContextAware contextAware = ContextAware.class.cast(driver);
String currentContext = contextAware.getContext();
if (currentContext.contains(NATIVE_APP_PATTERN))
Expand All @@ -35,4 +35,17 @@ public List<WebElement> findElements(SearchContext context) {
return context.findElements(returnRelevantBy(context));
}

@Override
public String toString(){
By defaultBy = map.get(ContentType.HTML);
By nativeBy = map.get(ContentType.NATIVE);

if (defaultBy.equals(nativeBy))
return defaultBy.toString();

return "Locator map: " + "\n" +
"- native content: \"" + nativeBy.toString() + "\" \n" +
"- html content: \"" + defaultBy.toString() + "\"";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.appium.java_client.remote;


public interface AutomationName {
String APPIUM = "Appium";
String SELENDROID = "Selendroid";
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ public class AndroidPageObjectTest {

@AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/text1\")")
private TouchableElement touchabletextVieW;

@iOSFindBy(uiAutomator = ".elements()[0]")
@FindBy(css = "e.e1.e2")
private List<WebElement> elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;

@iOSFindBy(uiAutomator = ".elements()[0]")
@FindBy(css = "e.e1.e2")
private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;

@SuppressWarnings("rawtypes")
@Before
Expand Down Expand Up @@ -348,4 +356,20 @@ public void isTheFieldAndroidElement(){
androidElement = (AndroidElement) remotetextVieW; //declared as RemoteWedElement
androidElement = (AndroidElement) touchabletextVieW; //declared as TouchABLEElement
}

@Test
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy(){
try {
Assert.assertNotEquals(null, elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.getAttribute("text"));
}
catch (NoSuchElementException ignored){
return;
}
throw new RuntimeException(NoSuchElementException.class.getName() + " has been expected.");
}

@Test
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy_List(){
Assert.assertEquals(0, elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.size());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.appium.java_client.pagefactory.SelendroidFindAll;
import io.appium.java_client.pagefactory.SelendroidFindBy;
import io.appium.java_client.pagefactory.SelendroidFindBys;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;

import org.openqa.selenium.WebElement;
Expand Down Expand Up @@ -79,7 +80,7 @@ public void setUp() throws Exception {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Selendroid");
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.SELENDROID);
capabilities.setCapability(MobileCapabilityType.SELENDROID_PORT, SELENDROID_PORT);
driver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ public class iOSPageObjectTest {
})
private List<WebElement> findAllElements;

@AndroidFindBy(className = "android.widget.TextView")
@FindBy(css = "e.e1.e2")
private List<WebElement> elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;

@AndroidFindBy(className = "android.widget.TextView")
@FindBy(css = "e.e1.e2")
private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;

@SuppressWarnings("rawtypes")
@Before
public void setUp() throws Exception {
Expand Down Expand Up @@ -280,4 +288,20 @@ public void isTheFieldIOSElement(){
iOSElement = (IOSElement) remotetextVieW; //declared as RemoteWebElement
iOSElement = (IOSElement) touchableButton; //declared as TouchABLEElement
}

@Test
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy(){
try {
Assert.assertNotEquals(null, elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.getAttribute("text"));
}
catch (NoSuchElementException ignored){
return;
}
throw new RuntimeException(NoSuchElementException.class.getName() + " has been expected.");
}

@Test
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy_List(){
Assert.assertEquals(0, elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.size());
}
}