Skip to content

Commit

Permalink
add custom locator strategy (#1041)
Browse files Browse the repository at this point in the history
* add custom locator strategy

* use correct strategy constant

* fix lint issues

* add doc links
  • Loading branch information
jlipps authored Oct 18, 2018
1 parent 18eba21 commit f10393a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/main/java/io/appium/java_client/AppiumDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
*/
@SuppressWarnings("unchecked")
public class AppiumDriver<T extends WebElement>
extends DefaultGenericMobileDriver<T> implements ComparesImages, FindsByImage<T> {
extends DefaultGenericMobileDriver<T> implements ComparesImages, FindsByImage<T>, FindsByCustom<T> {

private static final ErrorHandler errorHandler = new ErrorHandler(new ErrorCodesMobile(), true);
// frequently used command parameters
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/io/appium/java_client/FindsByCustom.java
Original file line number Diff line number Diff line change
@@ -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<T extends WebElement> extends FindsByFluentSelector<T> {
/**
* 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 <a href="https://appium.io/docs/en/advanced-concepts/element-finding-plugins/">
* The documentation on custom element finding plugins and their use</a>
* @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 <a href="https://appium.io/docs/en/advanced-concepts/element-finding-plugins/">
* The documentation on custom element finding plugins and their use</a>
* @since Appium 1.9.2
*/
default List<T> findElementsByCustom(String selector) {
return findElements(MobileSelector.CUSTOM.toString(), selector);
}
}
68 changes: 68 additions & 0 deletions src/main/java/io/appium/java_client/MobileBy.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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<WebElement> 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) {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/io/appium/java_client/MobileSelector.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit f10393a

Please sign in to comment.