How to let Espresso click a specific RecyclerView item?

五迷三道 提交于 2020-01-05 05:27:27

问题


I am trying to write an instrumentation test with Espresso for my Android app which uses a RecyclerView. Here is the main layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/grid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

</android.support.design.widget.CoordinatorLayout>

... and the item view layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/label"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</RelativeLayout>

This means there are a couple of TextViews on the screen which all have the label id. I am trying to click a specific label. I tried to let Espresso test recorder generate the code:

onView(allOf(withId(R.id.grid), isDisplayed()))
    .perform(actionOnItemAtPosition(5, click()));

I rather want to to something like:

// Not working
onView(allOf(withId(R.id.grid), isDisplayed()))
    .perform(actionOnItem(withText("Foobar"), click()));

Readings

I read quite a bit about the topic but still cannot figure out how to test a RecyclerView item based on its content not based on its position index.

  • Advanced Android Espresso - Slide on RecyclerViewActions (Chiu-Ki Chan)
  • RecyclerView and espresso, a complicated story (Patrick Bacon, Jul 18, 2015)
  • Espresso – Testing RecyclerViews at Specific Positions (Romain Piel, April 15, 2016)

回答1:


You can implement your custom RecyclerView matcher. Let's assume you have RecyclerView where each element has subject you want to match:

public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) {
    Checks.checkNotNull(subject);
    return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>(
            MyCustomViewHolder.class) {

        @Override
        protected boolean matchesSafely(MyCustomViewHolder viewHolder) {
            TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id);

            return ((subject.equals(subjectTextView.getText().toString())
                    && (subjectTextView.getVisibility() == View.VISIBLE)));
        }

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

And usage:

onView(withId(R.id.my_recycler_view_id)
    .perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));

Basically you can match anything you want. In this example we used subject TextView but it can be any element inside the RecyclerView item.

One more thing to clarify is check for visibility (subjectTextView.getVisibility() == View.VISIBLE). We need to have it because sometimes other views inside RecyclerView can have the same subject but it would be with View.GONE. This way we avoid multiple matches of our custom matcher and target only item that actually displays our subject.




回答2:


actionOnItem() matches against the itemView of the ViewHolder. In this case, the TextView is wrapped in the RelativeLayout, so you need to update the Matcher to account for it.

onView(allOf(withId(R.id.grid), isDisplayed()))
    .perform(actionOnItem(withChild(withText("Foobar")), click()));

You can also use hasDescendant() to wrap your matcher is the case of a more complex nesting.



来源:https://stackoverflow.com/questions/40366044/how-to-let-espresso-click-a-specific-recyclerview-item

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!