Writing ViewHolder Matcher with Espresso for Android

Recently we had a need to adapt Espresso tests to operate on RecyclerView after application migration from ListView component. The current Espresso view actions that are available for RecyclerView component based on item position work fine but we don't like to depend on position since our test data is dynamic.

After googling the ViewHolder matchers you can find only the following documentation without any practical example - RecyclerViewActions.

Then based on already created Matcher<Object> used in onData(...) it was possible to create Matcher<VH> which was not so difficult.

Let's assume each item in RecyclerView adapter has subject, represented by TextView. The below matcher will search for the item inside RecylerView with unique subject provided into matcher. Feel free to use it:

public static Matcher<RecyclerView.ViewHolder> withItemSubjectInViewHolder(final String itemSubject) {
    Checks.checkNotNull(itemSubject);
    return new BoundedMatcher(
            RecyclerView.ViewHolder, 
            MyListRecyclerViewItemAdapter.MyViewHolder.class) {
        @Override
        public boolean matchesSafely(MyListRecyclerViewItemAdapter.MyViewHolder holder) {
            boolean isMatches = false;

            if (!(holder.subject == null)) {
                isMatches = ((itemSubject.equals(holder.subject.getText().toString()))
                        && (holder.subject.getVisibility() == View.VISIBLE));
            }
            return isMatches;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("with item subject: " + itemSubject.toString());
        }
    };
}

And the possible usage is:

onView(withId(R.id.adapter_list))
    .perform(scrollToHolder(withItemSubjectInViewHolder(itemSubject)));
onView(withId(R.id.adapter_list))
    .perform(actionOnHolderItem(withItemSubjectInViewHolder(itemSubject), click()));