Check TextView in each item of RecyclerView with Espresso

Issue

There is a RecyclerView (R.id.recycler_view). Each item (R.id.movie_card) contains two views: ImageView and TextView (R.id.movie_title_text_view). The goal is to check with the Espresso that all of recyclerview’s items contain not empty text view. Please help to write code correctly.

There is using also Idle. So, the moment of start testing RecyclerView is correct (after all data is loaded).

There is not clear how to make assertion that all of the R.id.movie_title_text_view are not empty. Full test method is following:

@Rule
public ActivityTestRule activityTestRule  new ActivityTestRule(MainActivity.class);

@Test
public void GridFragmentRecycleViewTest(){
    final int TESTED_VIEWHOLDERS_QUANTITY  10;

    IdlingResource componentIdlingResource  getIdlingResource();
    Espresso.registerIdlingResources(componentIdlingResource);
    Log.d(TAG, "GridFragmentRecycleViewTest()");
    onView(withId(R.id.action_search)).perform(click());
    onView(isAssignableFrom(SearchView.class)).perform(typeSearchViewText("lord")).perform(pressKey(KeyEvent.KEYCODE_ENTER));
    EspressoIdlingResource.increment();
    onView(withId(R.id.recycler_view)).check(new RecyclerViewItemCountAssertion(TESTED_VIEWHOLDERS_QUANTITY));

    //up to here all works good
    onView(allOf(withId(R.id.movie_title_text_view))).check(matches(withText(not(isEmptyString()))));
}

public static ViewAction typeSearchViewText(final String text){
    return new ViewAction(){
        @Override
        public Matcher<View> getConstraints() {
            //Ensure that only apply if it is a SearchView and if it is visible.
            return allOf(isDisplayed(), isAssignableFrom(SearchView.class));
        }

        @Override
        public String getDescription() {
            return "Change view text";
        }

        @Override
        public void perform(UiController uiController, View view) {
            ((SearchView) view).setQuery(text,false);
        }


    };
}

The line:

onView(allOf(withId(R.id.movie_title_text_view))).check(matches(withText(not(isEmptyString()))));

makes the following exception: androidx.test.espresso.AmbiguousViewMatcherException: ‘(with id: com.example.myapplication3:id/movie_title_text_view)’ matches multiple views in the hierarchy. Problem views are marked with ‘****MATCHES****’ below.

View Hierarchy: +>DecorView{id-1, visibilityVISIBLE, width1440, height2560, has-focustrue, has-focusabletrue, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, layout-params{(0,0)(fillxfill) tyBASE_APPLICATION wanim0x10302f8 flLAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS pflFORCE_DRAW_STATUS_BAR_BACKGROUND}, tagnull, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0, child-count3} …

Solution

This is not ready to use answer, but if you get no other answers it will hopefully help drive you into right direction.

  1. You need to rely on RecyclerView finding view holder capabilities, and build assertion around it (RecyclerView.ViewHolder holder recyclerViewInstance.findViewHolderForAdapterPosition(index);)
  2. Find relevant view holder view using holder.itemView.findViewsWithText(listOfViews, text, FIND_VIEWS_WITH_TEXT); or for example holder.itemView.findViewById(yourViewId);
  3. Iterate through the items you have and execute the above for each item

You may want to build some view assertion for the purpose:

    public static ViewAssertion hasViewWithXyzAtPosition(final int index, final CharSequence text) {
        return new ViewAssertion() {
            @Override
            public void check(View view, NoMatchingViewException e) {
                if (!(view instanceof RecyclerView)) {
                    throw e;
                }
                RecyclerView rv  (RecyclerView) view;
                RecyclerView.ViewHolder holder  rv.findViewHolderForAdapterPosition(index);

                //...

                Assert.assertTrue(
                        "There's no view at index " + index + ",
                        ...
                );
            }
        };
    }

Answered By – ror

Leave a Comment