From 86e1efe96fe8c3c9760fb944c104160e8b1cfeb1 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Tue, 12 Feb 2019 07:51:59 +0100 Subject: [PATCH] Add Espresso data-matcher-based location strategy --- .../FindsByAndroidDataMatcher.java | 32 +++++++++ .../java/io/appium/java_client/MobileBy.java | 71 +++++++++++++++++++ .../io/appium/java_client/MobileSelector.java | 1 + .../java_client/android/AndroidDriver.java | 3 +- .../java_client/android/AndroidElement.java | 5 +- .../pagefactory/AndroidFindBy.java | 7 ++ .../pagefactory/bys/builder/Strategies.java | 6 ++ 7 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/appium/java_client/FindsByAndroidDataMatcher.java diff --git a/src/main/java/io/appium/java_client/FindsByAndroidDataMatcher.java b/src/main/java/io/appium/java_client/FindsByAndroidDataMatcher.java new file mode 100644 index 000000000..a60477870 --- /dev/null +++ b/src/main/java/io/appium/java_client/FindsByAndroidDataMatcher.java @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client; + +import org.openqa.selenium.WebElement; + +import java.util.List; + +public interface FindsByAndroidDataMatcher extends FindsByFluentSelector { + + default T findElementByAndroidDataMatcher(String using) { + return findElement(MobileSelector.ANDROID_DATA_MATCHER.toString(), using); + } + + default List findElementsByAndroidDataMatcher(String using) { + return findElements(MobileSelector.ANDROID_DATA_MATCHER.toString(), using); + } +} diff --git a/src/main/java/io/appium/java_client/MobileBy.java b/src/main/java/io/appium/java_client/MobileBy.java index e26a320b4..cd7b49f5c 100644 --- a/src/main/java/io/appium/java_client/MobileBy.java +++ b/src/main/java/io/appium/java_client/MobileBy.java @@ -97,6 +97,17 @@ public static By iOSClassChain(final String iOSClassChainString) { return new ByIosClassChain(iOSClassChainString); } + /** + * This locator strategy is only available in Espresso Driver mode. + * @param dataMatcherString is a valid class chain locator string. + * See + * the documentation for more details + * @return an instance of {@link io.appium.java_client.MobileBy.ByAndroidDataMatcher} + */ + public static By androidDataMatcher(final String dataMatcherString) { + return new ByAndroidDataMatcher(dataMatcherString); + } + /** * This locator strategy is available in XCUITest Driver mode. * @param iOSNsPredicateString is an an iOS NsPredicate String @@ -338,6 +349,66 @@ protected ByIosClassChain(String locatorString) { } } + public static class ByAndroidDataMatcher extends MobileBy implements Serializable { + + protected ByAndroidDataMatcher(String locatorString) { + super(MobileSelector.ANDROID_DATA_MATCHER, locatorString); + } + + /** + * {@inheritDoc} + * + * @throws WebDriverException when current session doesn't support the given selector or when + * value of the selector is not consistent. + * @throws IllegalArgumentException when it is impossible to find something on the given + * {@link SearchContext} instance + */ + @SuppressWarnings("unchecked") + @Override public List findElements(SearchContext context) { + Class contextClass = context.getClass(); + + if (FindsByAndroidDataMatcher.class.isAssignableFrom(contextClass)) { + return FindsByAndroidDataMatcher.class.cast(context) + .findElementsByAndroidDataMatcher(getLocatorString()); + } + + if (FindsByFluentSelector.class.isAssignableFrom(contextClass)) { + return super.findElements(context); + } + + throw formIllegalArgumentException(contextClass, FindsByAndroidDataMatcher.class, + FindsByFluentSelector.class); + } + + /** + * {@inheritDoc} + * + * @throws WebDriverException when current session doesn't support the given selector or when + * value of the selector is not consistent. + * @throws IllegalArgumentException when it is impossible to find something on the given + * {@link SearchContext} instance + */ + @Override public WebElement findElement(SearchContext context) { + Class contextClass = context.getClass(); + + if (FindsByAndroidDataMatcher.class.isAssignableFrom(contextClass)) { + return FindsByAndroidDataMatcher.class.cast(context) + .findElementByAndroidDataMatcher(getLocatorString()); + } + + if (FindsByFluentSelector.class.isAssignableFrom(contextClass)) { + return super.findElement(context); + } + + throw formIllegalArgumentException(contextClass, FindsByAndroidDataMatcher.class, + FindsByFluentSelector.class); + } + + @Override public String toString() { + return "By.FindsByAndroidDataMatcher: " + getLocatorString(); + } + } + public static class ByIosNsPredicate extends MobileBy implements Serializable { protected ByIosNsPredicate(String locatorString) { diff --git a/src/main/java/io/appium/java_client/MobileSelector.java b/src/main/java/io/appium/java_client/MobileSelector.java index 3ecb28461..4b01d38a3 100644 --- a/src/main/java/io/appium/java_client/MobileSelector.java +++ b/src/main/java/io/appium/java_client/MobileSelector.java @@ -25,6 +25,7 @@ public enum MobileSelector { WINDOWS_UI_AUTOMATION("-windows uiautomation"), IMAGE("-image"), ANDROID_VIEWTAG("-android viewtag"), + ANDROID_DATA_MATCHER("-android datamatcher"), CUSTOM("-custom"); private final String selector; diff --git a/src/main/java/io/appium/java_client/android/AndroidDriver.java b/src/main/java/io/appium/java_client/android/AndroidDriver.java index eb6517101..b1d9a454d 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -26,6 +26,7 @@ import io.appium.java_client.AppiumDriver; import io.appium.java_client.CommandExecutionHelper; +import io.appium.java_client.FindsByAndroidDataMatcher; import io.appium.java_client.FindsByAndroidUIAutomator; import io.appium.java_client.FindsByAndroidViewTag; import io.appium.java_client.HasOnScreenKeyboard; @@ -63,7 +64,7 @@ public class AndroidDriver extends AppiumDriver implements PressesKey, HasNetworkConnection, PushesFiles, StartsActivity, - FindsByAndroidUIAutomator, FindsByAndroidViewTag, + FindsByAndroidUIAutomator, FindsByAndroidViewTag, FindsByAndroidDataMatcher, LocksDevice, HasAndroidSettings, HasAndroidDeviceDetails, HasSupportedPerformanceDataType, AuthenticatesByFinger, HasOnScreenKeyboard, CanRecordScreen, SupportsSpecialEmulatorCommands, diff --git a/src/main/java/io/appium/java_client/android/AndroidElement.java b/src/main/java/io/appium/java_client/android/AndroidElement.java index 4aad95314..0a68124e1 100644 --- a/src/main/java/io/appium/java_client/android/AndroidElement.java +++ b/src/main/java/io/appium/java_client/android/AndroidElement.java @@ -19,11 +19,14 @@ import static io.appium.java_client.android.AndroidMobileCommandHelper.replaceElementValueCommand; import io.appium.java_client.CommandExecutionHelper; +import io.appium.java_client.FindsByAndroidDataMatcher; import io.appium.java_client.FindsByAndroidUIAutomator; +import io.appium.java_client.FindsByAndroidViewTag; import io.appium.java_client.MobileElement; public class AndroidElement extends MobileElement - implements FindsByAndroidUIAutomator { + implements FindsByAndroidUIAutomator, FindsByAndroidDataMatcher, + FindsByAndroidViewTag { /** * This method replace current text value. * @param value a new value 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 c15226ec2..9d84b324d 100644 --- a/src/main/java/io/appium/java_client/pagefactory/AndroidFindBy.java +++ b/src/main/java/io/appium/java_client/pagefactory/AndroidFindBy.java @@ -74,6 +74,13 @@ */ String tagName() default ""; + /** + * It is a desired data matcher expression. + * + * @return a desired data matcher expression + */ + String androidDataMatcher() default ""; + /** * It is a xpath to the target element. * diff --git a/src/main/java/io/appium/java_client/pagefactory/bys/builder/Strategies.java b/src/main/java/io/appium/java_client/pagefactory/bys/builder/Strategies.java index a0e48eecd..104448bb9 100644 --- a/src/main/java/io/appium/java_client/pagefactory/bys/builder/Strategies.java +++ b/src/main/java/io/appium/java_client/pagefactory/bys/builder/Strategies.java @@ -96,6 +96,12 @@ enum Strategies { .iOSClassChain(getValue(annotation, this)); } }, + BY_DATA_MATCHER("androidDataMatcher") { + @Override By getBy(Annotation annotation) { + return MobileBy + .androidDataMatcher(getValue(annotation, this)); + } + }, BY_NS_PREDICATE("iOSNsPredicate") { @Override By getBy(Annotation annotation) { return MobileBy