15

I am trying to test the text of an ActionPage using Espresso. However, when I run the Ui Automation Viewer I can see that the ActionPage is being shown as a View instead of an ActionView and it does not have a TextView.

I have tried checking for the ActionLabel text like this but that does not work:

onView(withClassName(equalToIgnoringCase("android.support.wearable.view.ActionLabel"))).check(matches(withText("MyText")));

I have an id for my ActionPage so I can find it with onView(withId(R.id.actionPage)) but I dont know how to access its children to get at ActionLabel text. I tried writing a custom matcher but this also does not work:

onView(withId(R.id.actionPage)).check(matches(withChildText("MyText")));

static Matcher<View> withChildText(final String string) {
        return new BoundedMatcher<View, View>(View.class) {
            @Override
            public boolean matchesSafely(View view) {
                ViewGroup viewGroup = ((ViewGroup) view);
                //return (((TextView) actionLabel).getText()).equals(string);
                for(int i = 0; i < view.getChildCount(); i++){
                    View child = view.getChildAt(i);
                    if (child instanceof TextView) {
                        return ((TextView) child).getText().toString().equals(string);
                    }
                }
                return false;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("with child text: " + string);
            }
        };
    }

Could someone please help me out, the ActionLabel does not seem to have an id by itself and its not a TextView...how can I check the text inside of it?

+------>FrameLayout{id=-1, visibility=VISIBLE, width=320, height=320, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+------->ActionPage{id=2131689620, res-name=actionPage, visibility=VISIBLE, width=320, height=320, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-------->ActionLabel{id=-1, visibility=VISIBLE, width=285, height=111, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=17.0, y=209.0}
|
+-------->CircularButton{id=-1, visibility=VISIBLE, width=144, height=144, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=88.0, y=65.0}

enter image description here

Allen Hair
  • 1,021
  • 2
  • 10
  • 21
AlexIIP
  • 2,461
  • 5
  • 29
  • 44
  • Is it possible to add programmatically content description or id to at least one of this layouts? It would be much easier to catch – piotrek1543 Dec 19 '15 at 20:56

1 Answers1

6

You can use withParent with allOf:

onView(
    allOf(
      withParent(withId(R.id.actionPage)),
      isAssignableFrom(ActionLabel.class)))
  .check(matches(withActionLabel(is("MyText"))));

Unfortunately ActionLabel does not expose its text via getText(), so instead of the standard withText() matcher, you have to write a custom one using reflection:

private static Matcher<Object> withActionLabel(
    final Matcher<CharSequence> textMatcher) {
  return new BoundedMatcher<Object, ActionLabel>(ActionLabel.class) {
    @Override public boolean matchesSafely(ActionLabel label) {
      try {
        java.lang.reflect.Field f = label.getClass().getDeclaredField("mText");
        f.setAccessible(true);
        CharSequence text = (CharSequence) f.get(label);
        return textMatcher.matches(text);
      } catch (NoSuchFieldException e) {
        return false;
      } catch (IllegalAccessException e) {
        return false;
      }
    }
    @Override public void describeTo(Description description) {
      description.appendText("with action label: ");
      textMatcher.describeTo(description);
    }
  };
}

More info: http://blog.sqisland.com/2015/05/espresso-match-toolbar-title.html

Please file a bug to request Google to add a public method ActionLabel.getText() so you can test it without reflection.

chiuki
  • 14,580
  • 4
  • 40
  • 38
  • Thanks! The problem is `ActionLabel` is not assignable to `TextView` and `ActionLabel` does not have a public `getText()` method. – AlexIIP Dec 03 '15 at 22:24
  • Is `ActionLabel` your custom view? If so, you can add a `getText()` method and write a custom matcher using that. See the blog link for a sample custom matcher. – chiuki Dec 03 '15 at 22:34
  • Its not, its an android class. http://developer.android.com/reference/android/support/wearable/view/ActionPage.html – AlexIIP Dec 03 '15 at 23:00
  • Try simply `onView( withParent(withId(R.id.actionPage))) .check(matches(withText("MyText")));` – piotrek1543 Dec 22 '15 at 09:43
  • I have edited the answer to include a custom matcher to verify the `ActionLabel` using reflection. – chiuki Dec 22 '15 at 13:38