Skip to content

Commit

Permalink
Merge pull request #213 from TikhomirovSergey/#211_#184-fix
Browse files Browse the repository at this point in the history
Fix #184 Fix #211
  • Loading branch information
Jonahss committed Jul 6, 2015
2 parents ddac8ff + 3628627 commit 0936596
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 21 deletions.
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());
}
}

0 comments on commit 0936596

Please sign in to comment.