android - studio - Usando Espresso para hacer clic en ver dentro del elemento RecyclerView
recyclerview in activity (6)
Ahora con android.support.test.espresso.contrib se ha vuelto más fácil:
1) Agregar dependencia de prueba
androidTestCompile(''com.android.support.test.espresso:espresso-contrib:2.0'') {
exclude group: ''com.android.support'', module: ''appcompat''
exclude group: ''com.android.support'', module: ''support-v4''
exclude module: ''recyclerview-v7''
}
* excluye 3 módulos, porque muy probablemente ya lo tengas
2) Luego haz algo como
onView(withId(R.id.recycler_grid))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
O
onView(withId(R.id.recyclerView))
.perform(RecyclerViewActions.actionOnItem(
hasDescendant(withText("whatever")), click()));
O
onView(withId(R.id.recycler_linear))
.check(matches(hasDescendant(withText("whatever"))));
¿Cómo puedo usar Espresso para hacer clic en una vista específica dentro de un elemento RecyclerView ? Sé que puedo hacer clic en el elemento en la posición 0 usando:
onView(withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
Pero necesito hacer clic en una vista específica dentro de ese elemento y no en el elemento en sí.
Gracias por adelantado.
- editar -
Para ser más precisos: tengo un
RecyclerView
(
R.id.recycler_view
) cuyos elementos son
CardView
(
R.id.card_view
).
Dentro de cada
CardView
tengo cuatro botones (entre otras cosas) y quiero hacer clic en un botón específico (
R.id.bt_deliver
).
Me gustaría usar las nuevas funciones de Espresso 2.0, pero no estoy seguro de que sea posible.
Si no es posible, quiero usar algo como esto (usando el código de Thomas Keller):
onRecyclerItemView(R.id.card_view, ???, withId(R.id.bt_deliver)).perform(click());
pero no sé qué poner en los signos de interrogación.
Aquí está, cómo resolví el problema en kotlin:
fun clickOnViewChild(viewId: Int) = object : ViewAction {
override fun getConstraints() = null
override fun getDescription() = "Click on a child view with specified id."
override fun perform(uiController: UiController, view: View) = click().perform(uiController, view.findViewById<View>(viewId))
}
y entonces
onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(position, clickOnViewChild(R.id.viewToClickInTheRow)))
Primero dé a sus botones un contenido único Descripciones, es decir, "fila de botones de entrega 5".
<button android:contentDescription=".." />
Luego desplácese a la fila:
onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.scrollToPosition(5));
Luego, seleccione la vista según el contenido Descripción.
onView(withContentDescription("delivery button row 5")).perform(click());
La Descripción del contenido es una excelente manera de usar onView de Espresso y hacer que su aplicación sea más accesible.
Prueba el siguiente enfoque:
onView(withRecyclerView(R.id.recyclerView)
.atPositionOnView(position, R.id.bt_deliver))
.perform(click());
public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
return new RecyclerViewMatcher(recyclerViewId);
}
public class RecyclerViewMatcher {
final int mRecyclerViewId;
public RecyclerViewMatcher(int recyclerViewId) {
this.mRecyclerViewId = recyclerViewId;
}
public Matcher<View> atPosition(final int position) {
return atPositionOnView(position, -1);
}
public Matcher<View> atPositionOnView(final int position, final int targetViewId) {
return new TypeSafeMatcher<View>() {
Resources resources = null;
View childView;
public void describeTo(Description description) {
int id = targetViewId == -1 ? mRecyclerViewId : targetViewId;
String idDescription = Integer.toString(id);
if (this.resources != null) {
try {
idDescription = this.resources.getResourceName(id);
} catch (Resources.NotFoundException var4) {
idDescription = String.format("%s (resource name not found)", id);
}
}
description.appendText("with id: " + idDescription);
}
public boolean matchesSafely(View view) {
this.resources = view.getResources();
if (childView == null) {
RecyclerView recyclerView =
(RecyclerView) view.getRootView().findViewById(mRecyclerViewId);
if (recyclerView != null) {
childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
}
else {
return false;
}
}
if (targetViewId == -1) {
return view == childView;
} else {
View targetView = childView.findViewById(targetViewId);
return view == targetView;
}
}
};
}
}
Puede hacer
clic
en el
tercer elemento
de
recyclerView
como este:
onView(withId(R.id.recyclerView)).perform(
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(2,click()))
No
olvide
proporcionar el tipo
ViewHolder
para que la inferencia no falle.
Puede hacerlo con la acción de vista personalizada.
public class MyViewAction {
public static ViewAction clickChildViewWithId(final int id) {
return new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return null;
}
@Override
public String getDescription() {
return "Click on a child view with specified id.";
}
@Override
public void perform(UiController uiController, View view) {
View v = view.findViewById(id);
v.performClick();
}
};
}
}
Luego puedes hacer clic con
onView(withId(R.id.rv_conference_list)).perform(
RecyclerViewActions.actionOnItemAtPosition(0, MyViewAction.clickChildViewWithId(R.id. bt_deliver)));