Как утверждать внутри 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, конечно, ожидает действия, он говорит о неправильном типе второго аргумента. Там нет RecyclerViewAssertions
на espresso-contrib.
Есть ли способ выполнить утверждения на просмотре ресайлера?
Ответы
Ответ 1
Вы должны проверить решение Danny Roa Пользовательские действия RecyclerView
И используйте его вот так:
onView(withRecyclerView(R.id.recycler_view)
.atPositionOnView(1, R.id.ofElementYouWantToCheck))
.check(matches(withText("Test text")));
Ответ 2
Довольно легко. Никакой дополнительной библиотеки не требуется. У:
onView(withId(R.id.recycler_view))
.check(matches(atPosition(0, withText("Test Text"))));
если ваш ViewHolder использует ViewGroup, оберните withText()
с помощью hasDescendant()
как:
onView(withId(R.id.recycler_view))
.check(matches(atPosition(0, hasDescendant(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"))));
Ответ 3
Просто чтобы увеличить riwnodennyk ответ, если ваш ViewHolder
является ViewGroup
вместо прямого объекта View
, такого как TextView
, тогда вы можете добавить hasDescendant
matcher, чтобы он соответствовал объекту TextView
в ViewGroup
. Пример:
onView(withId(R.id.recycler_view))
.check(matches(atPosition(0, hasDescendant(withText("First Element")))));
Ответ 4
В моем случае необходимо было объединить Дэнни Роа и рионоденный раствор:
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);
}
};
}
Ответ 5
Я боролся с той же проблемой, где у меня есть вид переработчика с 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
.
- Прокрутите
RecyclerView
до вида, соответствующего itemViewMatcher
- Выполнить действие в согласованном представлении
Более подробную информацию можно найти по адресу: RecyclerViewActions.actionOnItem
Ответ 6
Этот поток довольно старый, но я недавно расширил поддержку RecyclerViewAction, чтобы его можно было использовать и для утверждений. Это позволяет вам тестировать внеэкранные элементы без указания позиции, в то же время используя сопоставления видов.
Ознакомьтесь с этой статьей> Лучшее тестирование Android RecyclerView!
Ответ 7
Решение Danny Roa является удивительным, но оно не работает для элементов вне экрана, которые я только что прокрутил. Исправление заменяет это:
View targetView = recyclerView.getChildAt(this.position)
.findViewById(this.viewId);
с этим:
View targetView = recyclerView.findViewHolderForAdapterPosition(this.position)
.itemView.findViewById(this.viewId);
... в TestUtils
class.
Ответ 8
Для тестирования всех предметов (включая закадровый) используйте код ниже
Пример:
fun checkThatRedDotIsGone(itemPosition: Int) {
onView(
withId(R.id.recycler_view)).
check(itemViewMatches(itemPosition, R.id.inside_item_view,
withEffectiveVisibility(Visibility.GONE)))
}
Класс:
object RecyclerViewAssertions {
fun itemViewMatches(position: Int, viewMatcher: Matcher<View>): ViewAssertion {
return itemViewMatches(position, -1, viewMatcher)
}
/**
* Provides a RecyclerView assertion based on a view matcher. This allows you to
* validate whether a RecyclerView contains a row in memory without scrolling the list.
*
* @param viewMatcher - an Espresso ViewMatcher for a descendant of any row in the recycler.
* @return an Espresso ViewAssertion to check against a RecyclerView.
*/
fun itemViewMatches(position: Int, @IdRes resId: Int, viewMatcher: Matcher<View>): ViewAssertion {
assertNotNull(viewMatcher)
return ViewAssertion { view, noViewException ->
if (noViewException != null) {
throw noViewException
}
assertTrue("View is RecyclerView", view is RecyclerView)
val recyclerView = view as RecyclerView
val adapter = recyclerView.adapter
val itemType = adapter!!.getItemViewType(position)
val viewHolder = adapter.createViewHolder(recyclerView, itemType)
adapter.bindViewHolder(viewHolder, position)
val targetView = if (resId == -1) {
viewHolder.itemView
} else {
viewHolder.itemView.findViewById(resId)
}
if (viewMatcher.matches(targetView)) {
[email protected] // Found a matching view
}
fail("No match found")
}
}
}
Решение на основе этой статьи> Лучшее тестирование Android RecyclerView!