Espresso - how to find a specific item in a recycler view (order is random)

11,452

Solution 1

I was able to get this to work doing the following:

Matcher<RecyclerView.ViewHolder> matcher = CustomMatcher.withTitle("A");
onView((withId(R.id.recycler_view))).perform(scrollToHolder(matcher), actionOnHolderItem(matcher, click()));

Where CustomMatcher.withTitle is:

    public static Matcher<RecyclerView.ViewHolder> withTitle(final String title)
{
    return new BoundedMatcher<RecyclerView.ViewHolder, CustomListAdapter.ItemViewHolder>(CustomListAdapter.ItemViewHolder.class)
    {
        @Override
        protected boolean matchesSafely(CustomListAdapter.ItemViewHolder item)
        {
            return item.mTitleView.getText().toString().equalsIgnoreCase(title);
        }

        @Override
        public void describeTo(Description description)
        {
            description.appendText("view holder with title: " + title);
        }
    };
}

Solution 2

You don't need a custom matcher for this, just use this

onView(withId(R.id.recycler_id)).perform(RecyclerViewActions.actionOnItem(hasDescendant(withText("A")), click()));

and add espresso-contrib dependency

    androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:<espressso-version>'

Or if you're using AndroidX

    androidTestImplementation 'androidx.test.espresso:espresso-contrib:<espressso-version>'

Solution 3

I know it's an old question, while @Zach's answer is a good start, and help me in my answer, we have a recycler view with loads of different types of ViewHolders with different Ids for the texts the answer did not fully suit our use case.

What I ended up doing was using a slightly different matcher, which does not reference any specific Ids or variables:

fun withText(title: String) = object : BoundedMatcher<View, View>(View::class.java) {
    override fun describeTo(description: Description?) {
        description?.appendText("Searching for title with: $title")
    }

    override fun matchesSafely(item: View?): Boolean {
        val views = ArrayList<View>()
        item?.findViewsWithText(views, title, View.FIND_VIEWS_WITH_TEXT)

        return when {
            views.size == 1 -> true
            else -> false
        }
    }
}

And usage:

RecyclerViewActions.scrollTo<ViewHolder>(withText("Some unique text I'm looking for")
Share:
11,452
Zach
Author by

Zach

Android developer.

Updated on June 15, 2022

Comments

  • Zach
    Zach almost 2 years

    I'm wondering how I would be able to find a specific item in a recycler view where the order of items is randomized each run.

    Let's assume I have 4 items in the recycler view, each represented by the same type of view holder with a text view in it. A unique title is applied to each view holder/item. For this example let's say the titles are, for simplicity's sake, "A", "B", "C", and "D".

    How would I find the position (and then click) item "A" if the order is randomized? I know if the order does not change I could the scrollToPosition RecyclerViewInteraction action, but in this case the order can and will change.

    Any thoughts?

  • Zach
    Zach almost 8 years
    Sounds like a good approach, but I'm getting an error trying to use this: android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: is assignable from class: class android.widget.AdapterView
  • Zach
    Zach almost 8 years
    Ah, I don't think onData can be used for recycler views, is that correct?
  • njzk2
    njzk2 almost 8 years
    right. I would have thought it could have worked. there this, though: stackoverflow.com/questions/27396583/…
  • Zach
    Zach almost 8 years
    Thanks, this led me to figuring out a way to handle it... will post in an answer now!
  • tir38
    tir38 over 5 years
    This only works because CustomListAdapter.ItemViewHolder exposes mTitleView as a public field. If you only do this for testing then you are leaking test code into the app.
  • Conner
    Conner almost 4 years
    Very helpful. I couldn't figure out how to find an item by text.
  • Abhinav Tyagi
    Abhinav Tyagi about 3 years
    this will not work when the item is not in view
  • Anass NAZIH
    Anass NAZIH about 3 years
    It will scroll to find the item first then click it
  • Slartibartfast
    Slartibartfast over 2 years
    Does not scroll for me.
  • Carson Holzheimer
    Carson Holzheimer over 2 years
    I honestly can't believe this was the only place I found this information. Why isn't this the default way to test lists :(