Espresso - Click by text in List view

30,659

Solution 1

The problem is, that you try to match the list view itself with the instanceOf(ListView.class) as argument for onData(). onData() requires a data matcher that matches the adapted data of the ListView, not the ListView itself, and also not the View that Adapter.getView() returns, but the actual data.

If you have something like this in your production code:

ListView listView = (ListView)findViewById(R.id.myListView);
ArrayAdapter<MyDataClass> adapter = getAdapterFromSomewhere();
listView.setAdapter(adapter);

Then the Matcher argument of Espresso.onData() should match the desired instance of MyDataClass. So, something like this should work:

onData(hasToString(startsWith("ASDF"))).perform(click());

(You can use another Matcher using a method of org.hamcrest.Matchers)

In case you have multiple adapter views in your activity, you can call ViewMatchers.inAdapterView() with a view matcher that specifies the AdapterView like this:

onData(hasToString(startsWith("ASDF")))
    .inAdapterView(withId(R.id.myListView))
    .perform(click());

Solution 2

If adapter have custom model class for example Item:

public static Matcher<Object> withItemValue(final String value) {
        return new BoundedMatcher<Object, Item>(Item.class) {
            @Override
            public void describeTo(Description description) {
                description.appendText("has value " + value);
            }

            @Override
            public boolean matchesSafely(Item item) {
                return item.getName().toUpperCase().equals(String.valueOf(value));
            }
        };
    }

Then call following:

onData(withItemValue("DRINK1")).inAdapterView(withId(R.id.menu_item_grid)).perform(click());
Share:
30,659
Chad Bingham
Author by

Chad Bingham

Arguing with a software engineer is like wrestling with a pig in the mud; after a while you realize the pig likes it. -Unknown

Updated on June 17, 2020

Comments

  • Chad Bingham
    Chad Bingham almost 4 years

    I am trying to click on a text in a list view using Espresso. I know they have this guide, but I can't see how to make this work by looking for text. This is what I have tried

    Espresso.onData(Matchers.allOf(Matchers.is(Matchers.instanceOf(ListView.class)), Matchers.hasToString(Matchers.startsWith("ASDF")))).perform(ViewActions.click());
    

    As expected, this didn't work. The error said no view in hierarchy. Does anyone know how to select a String? ("ASDF" in this case) Thanks in advance.

    Update due to @haffax

    I received error:

    com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException: 'is assignable from class: class android.widget.AdapterView' matches multiple views in the hierarchy.

    Second error

    With this code

    onData(hasToString(startsWith("ASDF"))).inAdapterView(withContentDescription("MapList")).perform(click());
    

    I get this error

    com.google.android.apps.common.testing.ui.espresso.PerformException: Error performing 'load adapter data' on view 'with content description: is "MapList"'.

    Caused by: java.lang.RuntimeException: No data found matching: asString(a string starting with "ASDF")


    Solution

    onData(anything()).inAdapterView(withContentDescription("desc")).atPosition(x).perform(click())

  • haffax
    haffax about 10 years
    Answer extended to include solution for multiple AdapterViews in hierarchy.
  • Chad Bingham
    Chad Bingham about 10 years
    I am getting the same error, but with less **MATCHES**
  • Chad Bingham
    Chad Bingham about 10 years
    The two that match, seem to be the same though. The only difference I can see is one is=focused=false
  • haffax
    haffax about 10 years
    Well, you'll have to sort the matching out yourself. Seems weird to have so many different list views with the same id. Can't you give your list views different IDs? Or is this because the are used in ListFragments? Other ways to further distinguish: Assign a tag to the view and use the hasTag() matcher or use isDescendantOfA() to distinguish via hierarchy.
  • Chad Bingham
    Chad Bingham about 10 years
    Yeah I think it is odd too. i didn't write the app, I just test it. But yes, you're right, I can't give them different id's cause they are in ListFragments. I will look in to adding a tag.
  • Chad Bingham
    Chad Bingham about 10 years
    If I look in the uiautomatorviewer, I only see one ListView. I don't get how its finding two??
  • Chad Bingham
    Chad Bingham about 10 years
    Alright, so I have given one list a content description. How could i click by text within content description?
  • Tomask
    Tomask about 8 years
    Be aware that if you have e.g. nav drawer with list view, it can be a second adapter view! so as it was already said, inAdapterView() must be used in that case to differentiate between them
  • mbob
    mbob almost 6 years
    this works for me on one screen, but on another screen, Espresso seems to scroll to that item, but the item is not clicked even if perform(click()) is called (tested this with breakpoints)....this is very weird