diff --git a/src/main/java/io/appium/java_client/pagefactory/AndroidFindBy.java b/src/main/java/io/appium/java_client/pagefactory/AndroidFindBy.java index 1dd3e4856..5569fe839 100644 --- a/src/main/java/io/appium/java_client/pagefactory/AndroidFindBy.java +++ b/src/main/java/io/appium/java_client/pagefactory/AndroidFindBy.java @@ -35,7 +35,11 @@ String uiAutomator() default ""; String accessibility() default ""; String id() default ""; - String name() default ""; + @Deprecated + /** + * By.name selector is not supported by Appium server node since 1.5.x. + * So this option is going to be removed further. Be careful. + */String name() default ""; String className() default ""; String tagName() default ""; String xpath() default ""; diff --git a/src/main/java/io/appium/java_client/pagefactory/DefaultElementByBuilder.java b/src/main/java/io/appium/java_client/pagefactory/DefaultElementByBuilder.java index a98259028..3e581a0e4 100644 --- a/src/main/java/io/appium/java_client/pagefactory/DefaultElementByBuilder.java +++ b/src/main/java/io/appium/java_client/pagefactory/DefaultElementByBuilder.java @@ -16,9 +16,6 @@ package io.appium.java_client.pagefactory; -import static io.appium.java_client.remote.MobilePlatform.*; -import static io.appium.java_client.remote.AutomationName.*; - import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.util.HashMap; @@ -117,8 +114,7 @@ protected By buildDefaultBy() { @Override protected By buildMobileNativeBy() { AnnotatedElement annotatedElement = annotatedElementContainer.getAnnotated(); - if (ANDROID.toUpperCase().equals(platform) - && SELENDROID.toUpperCase().equals(automation)) { + if (isSelendroidAutomation()) { SelendroidFindBy selendroidFindBy = annotatedElement.getAnnotation(SelendroidFindBy.class); SelendroidFindBys selendroidFindBys = annotatedElement.getAnnotation(SelendroidFindBys.class); SelendroidFindAll selendroidFindByAll = annotatedElement.getAnnotation(SelendroidFindAll.class); @@ -136,7 +132,7 @@ protected By buildMobileNativeBy() { } } - if (ANDROID.toUpperCase().equals(platform)) { + if (isAndroid()) { AndroidFindBy androidFindBy = annotatedElement.getAnnotation(AndroidFindBy.class); AndroidFindBys androidFindBys= annotatedElement.getAnnotation(AndroidFindBys.class); AndroidFindAll androidFindAll = annotatedElement.getAnnotation(AndroidFindAll.class); @@ -154,7 +150,7 @@ protected By buildMobileNativeBy() { } } - if (IOS.toUpperCase().equals(platform)) { + if (isIOS()) { iOSFindBy iOSFindBy = annotatedElement.getAnnotation(iOSFindBy.class); iOSFindBys iOSFindBys= annotatedElement.getAnnotation(iOSFindBys.class); iOSFindAll iOSFindAll = annotatedElement.getAnnotation(iOSFindAll.class); @@ -181,6 +177,13 @@ public boolean isLookupCached() { return (annotatedElement.getAnnotation(CacheLookup.class) != null); } + private By returnMappedBy(By byDefault, By nativeAppBy) { + Map contentMap = new HashMap<>(); + contentMap.put(ContentType.HTML_OR_DEFAULT, byDefault); + contentMap.put(ContentType.NATIVE_MOBILE_SPECIFIC, nativeAppBy); + return new ContentMappedBy(contentMap); + } + @Override public By buildBy() { assertValidAnnotations(); @@ -188,18 +191,24 @@ public By buildBy() { By defaultBy = buildDefaultBy(); By mobileNativeBy = buildMobileNativeBy(); - if (defaultBy == null) { + String idOrName = ((Field) annotatedElementContainer.getAnnotated()).getName(); + + if (defaultBy == null && mobileNativeBy == null) { defaultBy = new ByIdOrName(((Field) annotatedElementContainer.getAnnotated()).getName()); + mobileNativeBy = new By.ById(idOrName); + return returnMappedBy(defaultBy, mobileNativeBy); } + if (defaultBy == null) { + defaultBy = new ByIdOrName(((Field) annotatedElementContainer.getAnnotated()).getName()); + return returnMappedBy(defaultBy, mobileNativeBy); + } if (mobileNativeBy == null) { mobileNativeBy = defaultBy; + return returnMappedBy(defaultBy, mobileNativeBy); } - Map contentMap = new HashMap<>(); - contentMap.put(ContentType.HTML_OR_DEFAULT, defaultBy); - contentMap.put(ContentType.NATIVE_MOBILE_SPECIFIC, mobileNativeBy); - return new ContentMappedBy(contentMap); + return returnMappedBy(defaultBy, mobileNativeBy); } } diff --git a/src/main/java/io/appium/java_client/pagefactory/ThrowableUtil.java b/src/main/java/io/appium/java_client/pagefactory/ThrowableUtil.java index b7c71fe96..bcfb18bf2 100644 --- a/src/main/java/io/appium/java_client/pagefactory/ThrowableUtil.java +++ b/src/main/java/io/appium/java_client/pagefactory/ThrowableUtil.java @@ -16,6 +16,7 @@ package io.appium.java_client.pagefactory; +import org.openqa.selenium.InvalidSelectorException; import org.openqa.selenium.StaleElementReferenceException; import java.lang.reflect.InvocationTargetException; @@ -28,7 +29,11 @@ static boolean isInvalidSelectorRootCause(Throwable e) { return false; } - if (String.valueOf(e.getMessage()).contains(INVALID_SELECTOR_PATTERN)) { + if (InvalidSelectorException.class.isAssignableFrom(e.getClass())) { + return true; + } + + if (String.valueOf(e.getMessage()).contains(INVALID_SELECTOR_PATTERN) || String.valueOf(e.getMessage()).contains("Locator Strategy \\w+ is not supported")) { return true; } diff --git a/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java b/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java index f07c01781..5602331a7 100644 --- a/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java +++ b/src/main/java/io/appium/java_client/pagefactory/bys/builder/AppiumByBuilder.java @@ -24,6 +24,10 @@ import java.util.ArrayList; import java.util.List; +import static io.appium.java_client.remote.AutomationName.SELENDROID; +import static io.appium.java_client.remote.MobilePlatform.ANDROID; +import static io.appium.java_client.remote.MobilePlatform.IOS; + /** * It is the basic handler of Appium-specific page object annotations * About the Page Object design pattern please read these documents: @@ -163,6 +167,18 @@ public void setAnnotated(AnnotatedElement annotated) { this.annotatedElementContainer.setAnnotated(annotated); } + protected boolean isAndroid() { + return ANDROID.toUpperCase().equals(platform); + } + + protected boolean isSelendroidAutomation() { + return isAndroid() && SELENDROID.toUpperCase().equals(automation); + } + + protected boolean isIOS() { + return IOS.toUpperCase().equals(platform); + } + /** * Defines how to transform given object (field, class, etc) * into {@link org.openqa.selenium.By} class used by webdriver to locate elements. diff --git a/src/main/java/io/appium/java_client/pagefactory/iOSFindBy.java b/src/main/java/io/appium/java_client/pagefactory/iOSFindBy.java index b666df94c..6f38ed2a5 100644 --- a/src/main/java/io/appium/java_client/pagefactory/iOSFindBy.java +++ b/src/main/java/io/appium/java_client/pagefactory/iOSFindBy.java @@ -35,7 +35,11 @@ String uiAutomator() default ""; String accessibility() default ""; String id() default ""; - String name() default ""; + @Deprecated + /** + * By.name selector is not supported by Appium server node since 1.5.x. + * So this option is going to be removed further. Be careful. + */String name() default ""; String className() default ""; String tagName() default ""; String xpath() default ""; diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java index dee99a560..3fe6773be 100644 --- a/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java +++ b/src/test/java/io/appium/java_client/pagefactory_tests/MobileBrowserCompatibilityTest.java @@ -41,18 +41,18 @@ public class MobileBrowserCompatibilityTest { private WebDriver driver; - - @FindBy(name = "q") - @AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/someId\")") - private WebElement searchTextField; + private AppiumDriverLocalService service; @AndroidFindBys({ @AndroidFindBy(className = "someClass"), @AndroidFindBy(xpath = "//someTag")}) - @FindBy(name="btnG") - private RemoteWebElement searchButton; - + private RemoteWebElement btnG; //this element should be found by id = 'btnG' or name = 'btnG' + + @FindBy(name = "q") + @AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/someId\")") + private WebElement searchTextField; + @AndroidFindBy(className = "someClass") @FindBys({@FindBy(className = "r"), @FindBy(tagName = "a")}) private List foundLinks; @@ -84,7 +84,7 @@ public void test() { driver.get("https://www.google.com"); searchTextField.sendKeys("Hello"); - searchButton.click(); + btnG.click(); Assert.assertNotEquals(0, foundLinks.size()); } diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java index b3129e678..fd15db3fb 100644 --- a/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java +++ b/src/test/java/io/appium/java_client/pagefactory_tests/SelendroidModeTest.java @@ -17,6 +17,7 @@ package io.appium.java_client.pagefactory_tests; import io.appium.java_client.android.AndroidDriver; +import io.appium.java_client.android.AndroidElement; import io.appium.java_client.pagefactory.*; import io.appium.java_client.remote.AutomationName; import io.appium.java_client.remote.MobileCapabilityType; @@ -37,7 +38,7 @@ import static org.junit.Assert.*; public class SelendroidModeTest { - private static int SELENDROID_PORT = 9999; + private static int SELENDROID_PORT = 9999; private static WebDriver driver; private static AppiumDriverLocalService service; @@ -63,15 +64,15 @@ public class SelendroidModeTest { private WebElement textXpath; @SelendroidFindBys({ - @SelendroidFindBy(id = "text1")}) + @SelendroidFindBy(id = "text1")}) private WebElement textIds; @SelendroidFindAll({ - @SelendroidFindBy(id = "text1")}) + @SelendroidFindBy(id = "text1")}) private WebElement textAll; @SelendroidFindAll({ - @SelendroidFindBy(id = "text1")}) + @SelendroidFindBy(id = "text1")}) private List textsAll; @SelendroidFindBy(className = "android.widget.TextView") @@ -79,14 +80,14 @@ public class SelendroidModeTest { @SelendroidFindBy(tagName = "TextView") private WebElement textTag; - + @SelendroidFindBy(linkText = "Accessibility") private WebElement textLink; - + @SelendroidFindBy(partialLinkText = "ccessibilit") private WebElement textPartialLink; - @BeforeClass + @BeforeClass public static void beforeClass() throws Exception { AppiumServiceBuilder builder = new AppiumServiceBuilder().withArgument(GeneralServerFlag.AUTOMATION_NAME, AutomationName.SELENDROID); service = builder.build(); @@ -123,8 +124,8 @@ public static void afterClass() throws Exception { public void findByIdElementTest() { assertNotEquals(null, textId.getAttribute("text")); } - - @Test + + @Test public void findBySelendroidSelectorTest() { assertNotEquals(null, textSelendroidId.getAttribute("text")); } @@ -173,15 +174,15 @@ public void findByElementByCalssTest() { public void findByElementByTagTest() { assertNotEquals(null, textTag.getAttribute("text")); } - + @Test public void findBySelendroidAnnotationOnlyTest() { assertNotEquals(null, textSelendroidId.getAttribute("text")); } - + @Test public void findBySelendroidLinkTextTest() { assertEquals("Accessibility", textLink.getText()); } -} +} \ No newline at end of file diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java index ac7c04d16..5805b7369 100644 --- a/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java +++ b/src/test/java/io/appium/java_client/pagefactory_tests/iOSPageObjectTest.java @@ -37,9 +37,9 @@ public class iOSPageObjectTest { - private static WebDriver driver; - private static AppiumDriverLocalService service; - private boolean populated = false; + private static WebDriver driver; + private static AppiumDriverLocalService service; + private boolean populated = false; @FindBy(className = "UIAButton") private List uiButtons; @@ -67,9 +67,9 @@ public class iOSPageObjectTest { private List remoteElementViews; @AndroidFindBys({ - @AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/list\")"), - @AndroidFindBy(className = "android.widget.TextView") - }) + @AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/list\")"), + @AndroidFindBy(className = "android.widget.TextView") + }) private List chainElementViews; @@ -92,11 +92,11 @@ public class iOSPageObjectTest { @iOSFindBy(uiAutomator = ".elements()[0]") private MobileElement mobileButton; - @iOSFindBy(uiAutomator = ".elements()[0]") - private TouchableElement touchableButton; + @iOSFindBy(uiAutomator = ".elements()[0]") + private TouchableElement touchableButton; - @iOSFindBy(uiAutomator = ".elements()[0]") - private List touchableButtons; + @iOSFindBy(uiAutomator = ".elements()[0]") + private List touchableButtons; @FindBy(className = "UIAButton") private MobileElement mobiletFindBy_Button; @@ -105,69 +105,70 @@ public class iOSPageObjectTest { private RemoteWebElement remotetextVieW; @AndroidFindBys({ - @AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/list\")"), - @AndroidFindBy(className = "android.widget.TextView") - }) + @AndroidFindBy(uiAutomator = "new UiSelector().resourceId(\"android:id/list\")"), + @AndroidFindBy(className = "android.widget.TextView") + }) private WebElement chainElementView; - + @iOSFindBy(uiAutomator = ".elements()[0]") private IOSElement iosButton; - + @iOSFindBy(uiAutomator = ".elements()[0]") private List iosButtons; - + @iOSFindAll({ - @iOSFindBy(xpath = "ComputeSumButton_Test"), - @iOSFindBy(name = "ComputeSumButton") //it is real locator + @iOSFindBy(id = "ComputeSumButton_Test"), + @iOSFindBy(xpath = "//*[@name = \"ComputeSumButton\"]") //it is real locator }) private WebElement findAllElement; - + @iOSFindAll({ - @iOSFindBy(xpath = "ComputeSumButton_Test"), - @iOSFindBy(name = "ComputeSumButton") //it is real locator + @iOSFindBy(id = "ComputeSumButton_Test"), + @iOSFindBy(xpath = "//*[@name = \"ComputeSumButton\"]") //it is real locator }) private List findAllElements; - @AndroidFindBy(className = "android.widget.TextView") - @FindBy(css = "e.e1.e2") - private List elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy; - - @AndroidFindBy(className = "android.widget.TextView") - @FindBy(css = "e.e1.e2") - private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy; - - - @BeforeClass - public static void beforeClass() throws Exception { - service = AppiumDriverLocalService.buildDefaultService(); - service.start(); + @AndroidFindBy(className = "android.widget.TextView") + @FindBy(css = "e.e1.e2") + private List elementsWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy; - File appDir = new File("src/test/java/io/appium/java_client"); - File app = new File(appDir, "TestApp.app.zip"); - DesiredCapabilities capabilities = new DesiredCapabilities(); - capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, ""); - capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "8.4"); - capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator"); - capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); - driver = new IOSDriver<>(service.getUrl(), capabilities); - } + @AndroidFindBy(className = "android.widget.TextView") + @FindBy(css = "e.e1.e2") + private WebElement elementWhenAndroidLocatorIsNotDefinedAndThereIsInvalidFindBy; + + + @BeforeClass + public static void beforeClass() throws Exception { + service = AppiumDriverLocalService.buildDefaultService(); + service.start(); + + File appDir = new File("src/test/java/io/appium/java_client"); + File app = new File(appDir, "TestApp.app.zip"); + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, ""); + capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1"); + capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator"); + capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath()); + driver = new IOSDriver(service.getUrl(), capabilities); + } + @SuppressWarnings("rawtypes") @Before public void setUp() throws Exception { - if (!populated) - PageFactory.initElements(new AppiumFieldDecorator(driver), this); + if (!populated) + PageFactory.initElements(new AppiumFieldDecorator(driver), this); - populated = true; + populated = true; } - @AfterClass - public static void afterClass() throws Exception { - if (driver != null) - driver.quit(); + @AfterClass + public static void afterClass() throws Exception { + if (driver != null) + driver.quit(); - if (service != null) - service.stop(); - } + if (service != null) + service.stop(); + } @Test public void findByElementsTest() { @@ -273,7 +274,7 @@ public void checkThatElementWasNotFoundByAndroidUIAutomator_Chain(){ } Assert.assertNotNull(nsee); } - + @Test public void isIOSElementTest(){ Assert.assertNotEquals(null, iosButton.getText()); @@ -294,38 +295,38 @@ public void findAllElementTest(){ Assert.assertNotEquals(null, findAllElement.getText()); } - @Test - public void isTouchAbleElement(){ - Assert.assertNotEquals(null, touchableButton.getText()); - } + @Test + public void isTouchAbleElement(){ + Assert.assertNotEquals(null, touchableButton.getText()); + } - @Test - public void areTouchAbleElements(){ - Assert.assertNotEquals(0, touchableButtons.size()); - } + @Test + public void areTouchAbleElements(){ + Assert.assertNotEquals(0, touchableButtons.size()); + } - @Test - @SuppressWarnings("unused") - public void isTheFieldIOSElement(){ + @Test + public void isTheFieldIOSElement(){ + @SuppressWarnings("unused") IOSElement iOSElement = (IOSElement) mobileButton; //declared as MobileElement - iOSElement = (IOSElement) iosUIAutomatorButton; //declared as WebElement - 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()); - } -} + iOSElement = (IOSElement) iosUIAutomatorButton; //declared as WebElement + 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()); + } +} \ No newline at end of file