Skip to content

Commit 0936596

Browse files
committed
Merge pull request #213 from TikhomirovSergey/#211_#184-fix
Fix #184 Fix #211
2 parents ddac8ff + 3628627 commit 0936596

File tree

7 files changed

+132
-21
lines changed

7 files changed

+132
-21
lines changed

src/main/java/io/appium/java_client/pagefactory/AppiumAnnotations.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.appium.java_client.pagefactory;
22

33
import static io.appium.java_client.remote.MobilePlatform.*;
4+
import static io.appium.java_client.remote.AutomationName.*;
45
import io.appium.java_client.MobileBy;
56

67
import java.lang.annotation.Annotation;
@@ -300,7 +301,7 @@ public By buildBy() {
300301
SelendroidFindBy selendroidBy = mobileField
301302
.getAnnotation(SelendroidFindBy.class);
302303
if (selendroidBy != null && ANDROID.toUpperCase().equals(platform)
303-
&& "Selendroid".toUpperCase().equals(automation)) {
304+
&& SELENDROID.toUpperCase().equals(automation)) {
304305
return setByForTheNativeContentAndReturn(
305306
getMobileBy(selendroidBy, getFilledValue(selendroidBy)),
306307
contentMap);
@@ -309,7 +310,7 @@ public By buildBy() {
309310
SelendroidFindBys selendroidBys = mobileField
310311
.getAnnotation(SelendroidFindBys.class);
311312
if (selendroidBys != null && ANDROID.toUpperCase().equals(platform)
312-
&& "Selendroid".toUpperCase().equals(automation)) {
313+
&& SELENDROID.toUpperCase().equals(automation)) {
313314
return setByForTheNativeContentAndReturn(
314315
getComplexMobileBy(selendroidBys.value(), ByChained.class),
315316
contentMap);
@@ -318,7 +319,7 @@ public By buildBy() {
318319
SelendroidFindAll selendroidAll = mobileField
319320
.getAnnotation(SelendroidFindAll.class);
320321
if (selendroidAll != null && ANDROID.toUpperCase().equals(platform)
321-
&& "Selendroid".toUpperCase().equals(automation)) {
322+
&& SELENDROID.toUpperCase().equals(automation)) {
322323
return setByForTheNativeContentAndReturn(
323324
getComplexMobileBy(selendroidAll.value(), ByAll.class),
324325
contentMap);

src/main/java/io/appium/java_client/pagefactory/AppiumElementLocator.java

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
package io.appium.java_client.pagefactory;
22

3+
import io.appium.java_client.android.AndroidDriver;
4+
import io.appium.java_client.ios.IOSDriver;
35
import io.appium.java_client.remote.MobileCapabilityType;
46

57
import java.lang.reflect.Field;
68
import java.util.ArrayList;
79
import java.util.List;
810
import java.util.concurrent.TimeUnit;
911

10-
import org.openqa.selenium.By;
11-
import org.openqa.selenium.Capabilities;
12-
import org.openqa.selenium.HasCapabilities;
13-
import org.openqa.selenium.NoSuchElementException;
14-
import org.openqa.selenium.SearchContext;
15-
import org.openqa.selenium.StaleElementReferenceException;
16-
import org.openqa.selenium.TimeoutException;
17-
import org.openqa.selenium.WebElement;
12+
import io.appium.java_client.remote.MobilePlatform;
13+
import org.openqa.selenium.*;
1814
import org.openqa.selenium.support.pagefactory.ElementLocator;
1915
import org.openqa.selenium.support.ui.FluentWait;
2016

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

3027
private WaitingFunction(SearchContext searchContext) {
3128
this.searchContext = searchContext;
@@ -37,12 +34,26 @@ public List<WebElement> apply(By by) {
3734
result.addAll(searchContext.findElements(by));
3835
} catch (StaleElementReferenceException ignored) {
3936
}
37+
catch (RuntimeException e){
38+
if (!isInvalidSelectorRootCause(e))
39+
throw e;
40+
}
4041
if (result.size() > 0) {
4142
return result;
4243
} else {
4344
return null;
4445
}
4546
}
47+
48+
private static boolean isInvalidSelectorRootCause(Throwable e){
49+
if (e == null)
50+
return false;
51+
52+
if (String.valueOf(e.getMessage()).contains(INVALID_SELECTOR_PATTERN))
53+
return true;
54+
55+
return isInvalidSelectorRootCause(e.getCause());
56+
}
4657
}
4758

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

74-
String platform = String.valueOf(capabilities
75-
.getCapability(MobileCapabilityType.PLATFORM_NAME));
76-
String automation = String.valueOf(capabilities
77-
.getCapability(MobileCapabilityType.AUTOMATION_NAME));
81+
String platform = getPlatform();
82+
String automation = getAutomation();
7883

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

96+
private String getPlatform(){
97+
WebDriver d = WebDriverUnpackUtility.
98+
unpackWebDriverFromSearchContext(this.searchContext);
99+
if (d == null)
100+
return null;
101+
102+
Class<?> driverClass = d.getClass();
103+
if (AndroidDriver.class.isAssignableFrom(driverClass))
104+
return MobilePlatform.ANDROID;
105+
106+
if (IOSDriver.class.isAssignableFrom(driverClass))
107+
return MobilePlatform.IOS;
108+
109+
//it is possible that somebody uses RemoteWebDriver or their
110+
//own WebDriver implementation. At this case capabilities are used
111+
//to detect platform
112+
if (HasCapabilities.class.isAssignableFrom(driverClass))
113+
return String.valueOf(((HasCapabilities) d).getCapabilities().
114+
getCapability(MobileCapabilityType.PLATFORM_NAME));
115+
116+
return null;
117+
}
118+
119+
private String getAutomation(){
120+
WebDriver d = WebDriverUnpackUtility.
121+
unpackWebDriverFromSearchContext(this.searchContext);
122+
if (d == null)
123+
return null;
124+
125+
if (HasCapabilities.class.isAssignableFrom(d.getClass()))
126+
return String.valueOf(((HasCapabilities) d).getCapabilities().
127+
getCapability(MobileCapabilityType.AUTOMATION_NAME));
128+
129+
return null;
130+
}
131+
91132
private void changeImplicitlyWaitTimeOut(long newTimeOut,
92133
TimeUnit newTimeUnit) {
93134
WebDriverUnpackUtility.unpackWebDriverFromSearchContext(searchContext)

src/main/java/io/appium/java_client/pagefactory/ContentMappedBy.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ private By returnRelevantBy(SearchContext context){
2222
if (!ContextAware.class.isAssignableFrom(driver.getClass())){ //it is desktop browser
2323
return map.get(ContentType.HTML);
2424
}
25-
25+
2626
ContextAware contextAware = ContextAware.class.cast(driver);
2727
String currentContext = contextAware.getContext();
2828
if (currentContext.contains(NATIVE_APP_PATTERN))
@@ -35,4 +35,17 @@ public List<WebElement> findElements(SearchContext context) {
3535
return context.findElements(returnRelevantBy(context));
3636
}
3737

38+
@Override
39+
public String toString(){
40+
By defaultBy = map.get(ContentType.HTML);
41+
By nativeBy = map.get(ContentType.NATIVE);
42+
43+
if (defaultBy.equals(nativeBy))
44+
return defaultBy.toString();
45+
46+
return "Locator map: " + "\n" +
47+
"- native content: \"" + nativeBy.toString() + "\" \n" +
48+
"- html content: \"" + defaultBy.toString() + "\"";
49+
}
50+
3851
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package io.appium.java_client.remote;
2+
3+
4+
public interface AutomationName {
5+
String APPIUM = "Appium";
6+
String SELENDROID = "Selendroid";
7+
}

src/test/java/io/appium/java_client/pagefactory_tests/AndroidPageObjectTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,14 @@ public class AndroidPageObjectTest {
160160

161161
@AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/text1\")")
162162
private TouchableElement touchabletextVieW;
163+
164+
@iOSFindBy(uiAutomator = ".elements()[0]")
165+
@FindBy(css = "e.e1.e2")
166+
private List<WebElement> elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;
167+
168+
@iOSFindBy(uiAutomator = ".elements()[0]")
169+
@FindBy(css = "e.e1.e2")
170+
private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;
163171

164172
@SuppressWarnings("rawtypes")
165173
@Before
@@ -348,4 +356,20 @@ public void isTheFieldAndroidElement(){
348356
androidElement = (AndroidElement) remotetextVieW; //declared as RemoteWedElement
349357
androidElement = (AndroidElement) touchabletextVieW; //declared as TouchABLEElement
350358
}
359+
360+
@Test
361+
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy(){
362+
try {
363+
Assert.assertNotEquals(null, elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.getAttribute("text"));
364+
}
365+
catch (NoSuchElementException ignored){
366+
return;
367+
}
368+
throw new RuntimeException(NoSuchElementException.class.getName() + " has been expected.");
369+
}
370+
371+
@Test
372+
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy_List(){
373+
Assert.assertEquals(0, elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.size());
374+
}
351375
}

src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.appium.java_client.pagefactory.SelendroidFindAll;
77
import io.appium.java_client.pagefactory.SelendroidFindBy;
88
import io.appium.java_client.pagefactory.SelendroidFindBys;
9+
import io.appium.java_client.remote.AutomationName;
910
import io.appium.java_client.remote.MobileCapabilityType;
1011

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

src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,14 @@ public class iOSPageObjectTest {
117117
})
118118
private List<WebElement> findAllElements;
119119

120+
@AndroidFindBy(className = "android.widget.TextView")
121+
@FindBy(css = "e.e1.e2")
122+
private List<WebElement> elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;
123+
124+
@AndroidFindBy(className = "android.widget.TextView")
125+
@FindBy(css = "e.e1.e2")
126+
private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy;
127+
120128
@SuppressWarnings("rawtypes")
121129
@Before
122130
public void setUp() throws Exception {
@@ -280,4 +288,20 @@ public void isTheFieldIOSElement(){
280288
iOSElement = (IOSElement) remotetextVieW; //declared as RemoteWebElement
281289
iOSElement = (IOSElement) touchableButton; //declared as TouchABLEElement
282290
}
291+
292+
@Test
293+
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy(){
294+
try {
295+
Assert.assertNotEquals(null, elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.getAttribute("text"));
296+
}
297+
catch (NoSuchElementException ignored){
298+
return;
299+
}
300+
throw new RuntimeException(NoSuchElementException.class.getName() + " has been expected.");
301+
}
302+
303+
@Test
304+
public void checkThatTestWillNotBeFailedBecauseOfInvalidFindBy_List(){
305+
Assert.assertEquals(0, elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy.size());
306+
}
283307
}

0 commit comments

Comments
 (0)