How to assert inside a RecyclerView in Espresso?

后端 未结 11 1793
故里飘歌
故里飘歌 2020-12-02 06:38

I am using espresso-contrib to perform actions on a RecyclerView, and it works as it should, ex:

onView(withId(R.id.recycler_view))
.perform(Rec         


        
相关标签:
11条回答
  • 2020-12-02 07:01

    Just to enhance riwnodennyk's answer, if your ViewHolder is a ViewGroup instead of a direct View object like TextView, then you can add hasDescendant matcher to match the TextView object in the ViewGroup. Example:

    onView(withId(R.id.recycler_view))
        .check(matches(atPosition(0, hasDescendant(withText("First Element")))));
    
    0 讨论(0)
  • 2020-12-02 07:01

    I combined a few answers above into a reusable method for testing other recycler views as the project grows. Leaving the code here in the event it helps anyone else out...

    Declare a function that may be called on a RecyclerView Resource ID:

    fun Int.shouldHaveTextAtPosition(text:String, position: Int) {
        onView(withId(this))
            .perform(scrollToPosition<RecyclerView.ViewHolder>(position))
            .check(matches(atPosition(position, hasDescendant(withText(text)))))
    }
    

    Then call it on your recycler view to check the text displayed of multiple adapter items in the list at a given position by doing:

    with(R.id.recycler_view_id) {
        shouldHaveTextAtPosition("Some Text at position 0", 0)
        shouldHaveTextAtPosition("Some Text at position 1", 1)
        shouldHaveTextAtPosition("Some Text at position 2", 2)
        shouldHaveTextAtPosition("Some Text at position 3", 3)
    }
    
    0 讨论(0)
  • 2020-12-02 07:02

    This thread is pretty old but I recently extended the RecyclerViewAction support to be usable for assertions as well. This allows you to test off-screen elements without specifying a position while still using view matchers.

    Check out this article > Better Android RecyclerView Testing!

    0 讨论(0)
  • 2020-12-02 07:05

    Danny Roa's solution is awesome, but it didn't work for the off-screen items I had just scrolled to. The fix is replacing this:

    View targetView = recyclerView.getChildAt(this.position)
                                  .findViewById(this.viewId);
    

    with this:

    View targetView = recyclerView.findViewHolderForAdapterPosition(this.position)
                                  .itemView.findViewById(this.viewId);
    

    ... in the TestUtils class.

    0 讨论(0)
  • 2020-12-02 07:07

    I have been struggling on the same issue where I have a recycler view with 6 items and then I have to choose the one at position 5 and the 5th one is not visible on the view.
    The above solution also works. Also, I know its a bit late but thought its worth sharing.

    I did this with a simple solution as below:

    onView(withId(R.id.recylcer_view))
        .perform(RecyclerViewActions.actionOnItem(
             hasDescendant(withText("Text of item you want to scroll to")), 
             click()));
    

    RecyclerViewActions.actionOnItem - Performs a ViewAction on a view matched by viewHolderMatcher.

    1. Scroll RecyclerView to the view matched by itemViewMatcher
    2. Perform an action on the matched view

    More details can be found at : RecyclerViewActions.actionOnItem

    0 讨论(0)
  • 2020-12-02 07:09

    Pretty easy. No extra library is needed. Do:

        onView(withId(R.id.recycler_view))
                .check(matches(atPosition(0, withText("Test Text"))));
    

    if your ViewHolder uses ViewGroup, wrap withText() with a hasDescendant() like:

    onView(withId(R.id.recycler_view))
                    .check(matches(atPosition(0, hasDescendant(withText("Test Text")))));
    

    with method you may put into your Utils class.

    public static Matcher<View> atPosition(final int position, @NonNull final Matcher<View> itemMatcher) {
        checkNotNull(itemMatcher);
        return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) {
            @Override
            public void describeTo(Description description) {
                description.appendText("has item at position " + position + ": ");
                itemMatcher.describeTo(description);
            }
    
            @Override
            protected boolean matchesSafely(final RecyclerView view) {
                RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position);
                if (viewHolder == null) {
                    // has no item on such position
                    return false;
                }
                return itemMatcher.matches(viewHolder.itemView);
            }
        };
    }
    

    If your item may be not visible on the screen at first, then scroll to it before:

        onView(withId(R.id.recycler_view))
                .perform(scrollToPosition(87))
                .check(matches(atPosition(87, withText("Test Text"))));
    
    0 讨论(0)
提交回复
热议问题