Как утверждать внутри RecyclerView в Espresso?

Я использую espresso-contrib для выполнения действий в RecyclerView , и он работает так, как должен, например:

 onView(withId(R.id.recycler_view)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); //click on first item 

И мне нужно выполнить на нем утверждения. Что-то вроде этого:

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

Но, поскольку RecyclerViewActions , конечно, ожидает действия, он говорит о неправильном типе второго аргумента. На espresso-contrib нет RecyclerViewAssertions .

Есть ли способ выполнить утверждения на ресайклере?

Solutions Collecting From Web of "Как утверждать внутри RecyclerView в Espresso?"

Вы должны проверить решение Danny Roa Custom RecyclerView Actions и использовать его следующим образом:

 onView(withRecyclerView(R.id.recycler_view) .atPositionOnView(1, R.id.ofElementYouWantToCheck)) .check(matches(withText("Test text"))); 

Довольно легко. Никакой дополнительной библиотеки не требуется. Делать:

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

С помощью метода, который вы можете поместить в свой класс Utils .

 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); } }; } 

Если ваш элемент сначала не отображается на экране, затем прокрутите его до:

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

Чтобы усилить ответ riwnodennyk, если ваш ViewHolder представляет собой ViewGroup вместо прямого объекта View такого как TextView , тогда вы можете добавить hasDescendant для соответствия объекту TextView в ViewGroup . Пример:

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

Я боролся с той же проблемой, когда у меня есть просмотр ресайклера с 6 элементами, а затем я должен выбрать тот, который находится в позиции 5, а пятый не отображается в представлении.
Вышеупомянутое решение также работает. Кроме того, я знаю, что он немного опоздал, но подумал, что это стоит того.

Я сделал это с простым решением, как показано ниже:

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

RecyclerViewActions.actionOnItem – выполняет ViewAction в представлении, совпадающем с viewHolderMatcher .

  1. Прокрутите RecyclerView до представления, совпадающего с itemViewMatcher
  2. Выполните действие в соответствующем представлении

Более подробную информацию можно найти по адресу: RecyclerViewActions.actionOnItem

В моем случае необходимо было объединить решение Дэнни Роа и рионоденки:

 onView(withId(R.id.recyclerview)) .perform(RecyclerViewActions.scrollToPosition(80)) .check(matches(atPositionOnView(80, withText("Test Test"), R.id.targetview))); 

И метод:

 public static Matcher<View> atPositionOnView(final int position, final Matcher<View> itemMatcher, @NonNull final int targetViewId) { return new BoundedMatcher<View, RecyclerView>(RecyclerView.class) { @Override public void describeTo(Description description) { description.appendText("has view id " + itemMatcher + " at position " + position); } @Override public boolean matchesSafely(final RecyclerView recyclerView) { RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position); View targetView = viewHolder.itemView.findViewById(targetViewId); return itemMatcher.matches(targetView); } }; } 

Решение Danny Roa является удивительным, но оно не работает для элементов вне экрана, которые я только что прокрутил. Исправление заменяет это:

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

с этим:

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

… в классе TestUtils .