diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java index 97b05d27b..854d76239 100644 --- a/src/main/java/io/appium/java_client/AppiumDriver.java +++ b/src/main/java/io/appium/java_client/AppiumDriver.java @@ -64,7 +64,7 @@ */ @SuppressWarnings("unchecked") public class AppiumDriver - extends DefaultGenericMobileDriver implements ComparesImages, FindsByImage { + extends DefaultGenericMobileDriver implements ComparesImages, FindsByImage, FindsByCustom { private static final ErrorHandler errorHandler = new ErrorHandler(new ErrorCodesMobile(), true); // frequently used command parameters diff --git a/src/main/java/io/appium/java_client/FindsByCustom.java b/src/main/java/io/appium/java_client/FindsByCustom.java new file mode 100644 index 000000000..f908fc424 --- /dev/null +++ b/src/main/java/io/appium/java_client/FindsByCustom.java @@ -0,0 +1,55 @@ +/* + * 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.NoSuchElementException; +import org.openqa.selenium.WebElement; + +import java.util.List; + +public interface FindsByCustom extends FindsByFluentSelector { + /** + * Performs the lookup for a single element by sending a selector to a custom element finding + * plugin. This type of locator requires the use of the 'customFindModules' capability and a + * separately-installed element finding plugin. + * + * @param selector selector to pass to the custom element finding plugin + * @return The first element that matches the given selector + * @see + * The documentation on custom element finding plugins and their use + * @throws NoSuchElementException when no element is found + * @since Appium 1.9.2 + */ + default T findElementByCustom(String selector) { + return findElement(MobileSelector.CUSTOM.toString(), selector); + } + + /** + * Performs the lookup for a single element by sending a selector to a custom element finding + * plugin. This type of locator requires the use of the 'customFindModules' capability and a + * separately-installed element finding plugin. + * + * @param selector selector to pass to the custom element finding plugin + * @return a list of elements that match the given selector or an empty list + * @see + * The documentation on custom element finding plugins and their use + * @since Appium 1.9.2 + */ + default List findElementsByCustom(String selector) { + return findElements(MobileSelector.CUSTOM.toString(), selector); + } +} \ No newline at end of file diff --git a/src/main/java/io/appium/java_client/MobileBy.java b/src/main/java/io/appium/java_client/MobileBy.java index 6a65034a3..1fd80ea15 100644 --- a/src/main/java/io/appium/java_client/MobileBy.java +++ b/src/main/java/io/appium/java_client/MobileBy.java @@ -147,6 +147,18 @@ public static By AndroidViewTag(final String tag) { public static By image(final String b64Template) { return new ByImage(b64Template); } + + /** + * This type of locator requires the use of the 'customFindModules' capability and a + * separately-installed element finding plugin. + * + * @param selector selector to pass to the custom element finding plugin + * @return an instance of {@link ByCustom} + * @since Appium 1.9.2 + */ + public static By custom(final String selector) { + return new ByCustom(selector); + } public static class ByIosUIAutomation extends MobileBy implements Serializable { @@ -572,6 +584,62 @@ protected ByImage(String b64Template) { } } + public static class ByCustom extends MobileBy implements Serializable { + + protected ByCustom(String selector) { + super(MobileSelector.CUSTOM, selector); + } + + /** + * {@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 (FindsByCustom.class.isAssignableFrom(contextClass)) { + return FindsByCustom.class.cast(context).findElementsByCustom(getLocatorString()); + } + + if (FindsByFluentSelector.class.isAssignableFrom(contextClass)) { + return super.findElements(context); + } + + throw formIllegalArgumentException(contextClass, FindsByCustom.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 (FindsByCustom.class.isAssignableFrom(contextClass)) { + return FindsByCustom.class.cast(context).findElementByCustom(getLocatorString()); + } + + if (FindsByFluentSelector.class.isAssignableFrom(contextClass)) { + return super.findElement(context); + } + + throw formIllegalArgumentException(contextClass, FindsByCustom.class, FindsByFluentSelector.class); + } + + @Override public String toString() { + return "By.Custom: " + getLocatorString(); + } + } + public static class ByAndroidViewTag extends MobileBy implements Serializable { public ByAndroidViewTag(String tag) { diff --git a/src/main/java/io/appium/java_client/MobileSelector.java b/src/main/java/io/appium/java_client/MobileSelector.java index f7d7bbb49..3ecb28461 100644 --- a/src/main/java/io/appium/java_client/MobileSelector.java +++ b/src/main/java/io/appium/java_client/MobileSelector.java @@ -24,7 +24,8 @@ public enum MobileSelector { IOS_CLASS_CHAIN("-ios class chain"), WINDOWS_UI_AUTOMATION("-windows uiautomation"), IMAGE("-image"), - ANDROID_VIEWTAG("-android viewtag"); + ANDROID_VIEWTAG("-android viewtag"), + CUSTOM("-custom"); private final String selector;