Как разрешить Espresso щелкнуть конкретный элемент RecyclerView?
Я пытаюсь написать инструментарий с помощью Espresso для моего приложения для Android, которое использует RecyclerView
, Вот основной макет:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
... и макет представления элемента:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
Это означает, что есть пара TextViews
на экране которого все имеют label
Я бы. Я пытаюсь нажать на определенный ярлык. Я попытался позволить тест-рекордеру Espresso сгенерировать код:
onView(allOf(withId(R.id.grid), isDisplayed()))
.perform(actionOnItemAtPosition(5, click()));
Я скорее хочу что-то вроде:
// Not working
onView(allOf(withId(R.id.grid), isDisplayed()))
.perform(actionOnItem(withText("Foobar"), click()));
Показания
Я прочитал немного о теме, но все еще не могу понять, как проверить RecyclerView
элемент на основе его содержимого, а не на основе его индекса позиции.
- Расширенный Android Espresso - Слайд о RecyclerViewActions (Чиу-Ки Чан)
- RecyclerView и эспрессо, сложная история (Патрик Бэкон, 18 июля 2015 г.)
- Эспрессо - тестирование RecyclerViews на определенных позициях (Romain Piel, 15 апреля 2016 г.)
2 ответа
Вы можете реализовать свой заказ RecyclerView
согласовани. Давайте предположим, что у вас есть RecyclerView
где каждый элемент имеет предмет, который вы не хотите совпадать:
public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) {
Checks.checkNotNull(subject);
return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>(
MyCustomViewHolder.class) {
@Override
protected boolean matchesSafely(MyCustomViewHolder viewHolder) {
TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id);
return ((subject.equals(subjectTextView.getText().toString())
&& (subjectTextView.getVisibility() == View.VISIBLE)));
}
@Override
public void describeTo(Description description) {
description.appendText("item with subject: " + subject);
}
};
}
И использование:
onView(withId(R.id.my_recycler_view_id)
.perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));
В основном вы можете сопоставить все, что вы хотите. В этом примере мы использовали тему TextView
но это может быть любой элемент внутри RecyclerView
вещь.
Еще одна вещь, чтобы уточнить, это проверка на видимость (subjectTextView.getVisibility() == View.VISIBLE)
, Нам нужно иметь это, потому что иногда другие взгляды внутри RecyclerView
может иметь ту же тему, но это было бы с View.GONE
, Таким образом, мы избегаем многократного совпадения нашего пользовательского сопоставления и целевого элемента, который фактически отображает нашу тему.
actionOnItem()
совпадает с itemView ViewHolder. В этом случае TextView оборачивается в RelativeLayout, поэтому вам необходимо обновить Matcher для его учета.
onView(allOf(withId(R.id.grid), isDisplayed()))
.perform(actionOnItem(withChild(withText("Foobar")), click()));
Вы также можете использовать hasDescendant(), чтобы обернуть ваш matcher в случае более сложной вложенности.