Espresso : Recyclerview scroll to end

RecyclerViewActions.scrollTo() matches against the ItemView of the ViewHolder, which is inflated in onCreateViewHolder() of the adapter. And in order for the scrollTo() to work, you need to provide a matcher that uniquely identifies that ItemView.

Your current matcher tells espresso to scroll to a ViewHolder that was inflated with a TextView as an itemView. Which can happen, but usually you have some ViewGroup action going on there to style the view holders in the way you want them to look.

If you change your scrollTo() Matcher, to hasDescendant(withText("Text XYZ")) to account for all nested layouts (if there more than one).

Also keep in mind since you are also trying to click the item - you can't do it in the same perform() because it will send the click to the current ViewInteraction, which is in this case a RecyclerView with id R.id.recycler_view. Doing so in the same perform just clicks the middle on the RecyclerView, not the item that you scrolled to.

To solve this you need either need another onView() with the matcher that you used to scroll to an item or use RecyclerView.actionOnItem().

In case of another onView() statement, the hasDescendant(withText("Text XYZ")) will fail you, because it will find all parents of that TextView (viewholder, recyclerview, the viewgroup that holds the recyclerview and so on) as they all have this particular descendant. This will force you to make the ItemView matcher to be more precise and account for all nested layouts. My usual go to matcher is withChild() in these situations, but it might be different for you.


If you know the last position of the RecyclerView, then you can scroll to it

static final int LAST_POSITION = 100;

// First method
onView(withId(R.id.recyclerview))
    .perform(RecyclerViewActions.scrollToPosition((LAST_POSITION)));

// Second method
onView(withId(R.id.recyclerview))
        .perform(actionOnItemAtPosition(LAST_POSITION, scrollTo()));