Skip to content


[Android] Enable matching on custom class names #294

bootstraponline opened this Issue · 8 comments

2 participants

Appium member

I'm trying to click a Sign Out button and Appium doesn't appear to be able to find it. The button is implemented using actionbarsherlock and is hidden until the pop up is triggered. I think if I attach a content description then it'll be possible. Are there any ways to find it without modifying the xml to set content-desc?

After calling a few methods I usually get this error:

info: [ADB STDOUT] Error in testRunServer:
info: [ADB STDOUT] java.lang.IllegalStateException: UiAutomationService not connected. Did you call #register()?
info: [ADB STDOUT] at android.accessibilityservice.UiTestAutomationBridge.ensureValidConnection(
info: [ADB STDOUT] at android.accessibilityservice.UiTestAutomationBridge.getRootAccessibilityNodeInfoInActiveWindow(
info: [ADB STDOUT] at
Appium member$OverflowMenuButton has a contentDescription and that seems to be the only way to find and click this button. I think OverflowMenuButton should be included when searching for tag name button because it's a common aspect of actionbarsherlock.

Appium member

Searching by class name fails.

> $driver.find_element :tag_name, '$OverflowMenuButton'
{"using":"tag name","value":"$OverflowMenuButton"}
Selenium::WebDriver::Error::NoSuchElementError: An element could not be located on the page using the given search parameters.
info: [ANDROID] [info] Using class selector$OverflowMenuButton for find
info: [ANDROID] [info] Returning result: {"value":"An element could not be located on the page using the given search parameters.","status":7}
info: [ADB] Received command result from bootstrap
Appium member
diff --git a/uiautomator/bootstrap/src/io/appium/android/bootstrap/ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/
index 0027561..72062ca 100644
--- a/uiautomator/bootstrap/src/io/appium/android/bootstrap/
+++ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/
@@ -220,14 +220,9 @@ class AndroidCommandHolder {
     private static UiSelector selectorForFind(String strategy, String selector, Boolean many) throws InvalidStrategyException, AndroidCommandExcepti
         UiSelector s = new UiSelector();
         if (strategy.equals("tag name")) {
-            String androidClass = "";
-            try {
-                androidClass = AndroidElementClassMap.match(selector);
-            } catch (UnallowedTagNameException e) {
-                throw new AndroidCommandException(e.getMessage());
-            }
-  "Using class selector " + androidClass + " for find");
-            s = s.className(androidClass);
+            String androidClass = selector;
+  "Using class selector classNameMatches " + androidClass + " for find");
+            s = s.classNameMatches(androidClass);
         } else if (strategy.equals("name")) {
             s = s.description(s
[37] pry(main)> a =  $driver.find_element :tag_name, '(?i).*button.*'
{"using":"tag name","value":"(?i).*button.*"}
=> #<Selenium::WebDriver::Element:0x5d98619cb7e94a00 id="6">
[38] pry(main)>
=> "More options"

It works on custom class names now. classNameMatches is a lot more useful than className.

com\\.android\\.internal\\.view\\.menu\\.ActionMenuPresenter\\$OverflowMenuButton will match and all button classes will be included in the results for tag_name button.

Appium member
  • Should tag_name include all classes that include the name of the tag?
    • If not, tag_name button should return regular buttons plus actionbar buttons.
  • How should classNameMatches be invoked from the client side? The above patch redefines tag_name to take a regex.
Appium member

awesome research, thanks. your 2 questions are good.

How should classNameMatches be invoked from the client side? The above patch redefines tag_name to take a regex.

My first instinct is to say this should be part of xpath's contains(). So something like:

//*[contains(@tag, "button")]

(and it's a case-insensitive search). I'm also provisionally open to enabling some kind of regex matcher in tag name selectors, as long as they start with a character that's not in any actual tag names (like your example above with the parenthesis).

If not, tag_name button should return regular buttons plus actionbar buttons.

I think that's right. Ideally we'd return all elements of that android class and all elements that subclass from that android class, but we have no idea about that in the bootstrap jar (or do we?). So I think the best we can do here is make sure to return all appropriate default UI elements that make sense (so in this case, regular + actionbar buttons), and allow for another type of search, like a regex search, as above.

Appium member

you completed the second task with #308 correct?

Appium member

This ticket is about matching class names. s.classNameMatches. #308 only dealt with finding text s.textContains. The //* support will be helpful for implementing custom class matching.

Appium member

Fixed in #321.

@sebv sebv pushed a commit to sebv/appium that referenced this issue
appium-ci ci android branch for build #294.3 a7b22ff
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.