Подтвердить что ты не робот

Как утверждать внутри 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.

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

4b9b3361

Ответ 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.

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

Более подробную информацию можно найти по адресу: 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!