J'utilise espresso-contrib pour effectuer des actions sur un RecyclerView
, et cela fonctionne comme il se doit, ex:
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); //click on first item
et j'ai besoin de faire des affirmations dessus. Quelque chose comme ça:
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, check(matches(withText("Test Text"))));
mais, parce que RecyclerViewActions est, bien sûr, en attente d'une action, il indique un deuxième type d'argument incorrect. Il n'y a pas de RecyclerViewAssertions
sur espresso-contrib.
Existe-t-il un moyen d'effectuer des assertions sur une vue de recycleur?
Vous devriez vérifier la solution de Danny Roa Actions RecyclerView personnalisées Et l'utiliser comme ceci:
onView(withRecyclerView(R.id.recycler_view)
.atPositionOnView(1, R.id.ofElementYouWantToCheck))
.check(matches(withText("Test text")));
Plutôt facile. Aucune bibliothèque supplémentaire n'est nécessaire. Faire:
onView(withId(R.id.recycler_view))
.check(matches(atPosition(0, withText("Test Text"))));
si votre ViewHolder utilise ViewGroup, enveloppez withText()
avec un hasDescendant()
comme:
onView(withId(R.id.recycler_view))
.check(matches(atPosition(0, hasDescendant(withText("Test Text")))));
avec la méthode que vous pouvez mettre dans votre classe 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);
}
};
}
Si votre article peut ne pas être visible à l'écran au début, faites-le défiler avant:
onView(withId(R.id.recycler_view))
.perform(scrollToPosition(87))
.check(matches(atPosition(87, withText("Test Text"))));
Juste pour améliorer la réponse de riwnodennyk, si votre ViewHolder
est un ViewGroup
au lieu d'un objet direct View
comme TextView
, alors vous pouvez ajouter hasDescendant
matcher pour faire correspondre l'objet TextView
dans le ViewGroup
. Exemple:
onView(withId(R.id.recycler_view))
.check(matches(atPosition(0, hasDescendant(withText("First Element")))));
Dans mon cas, il a fallu fusionner la solution de Danny Roa et de riwnodennyk:
onView(withId(R.id.recyclerview))
.perform(RecyclerViewActions.scrollToPosition(80))
.check(matches(atPositionOnView(80, withText("Test Test"), R.id.targetview)));
et la méthode:
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);
}
};
}
J'ai eu du mal sur le même problème où j'ai une vue de recycleur avec 6 articles et ensuite je dois choisir celui en position 5 et le 5ème n'est pas visible sur la vue.
La solution ci-dessus fonctionne également. De plus, je sais que c'est un peu tard mais j'ai pensé que ça valait le coup d'être partagé.
Je l'ai fait avec une solution simple comme ci-dessous:
onView(withId(R.id.recylcer_view))
.perform(RecyclerViewActions.actionOnItem(
hasDescendant(withText("Text of item you want to scroll to")),
click()));
RecyclerViewActions.actionOnItem
- Effectue un ViewAction
sur une vue correspondant à viewHolderMatcher
.
RecyclerView
jusqu'à la vue correspondant à itemViewMatcher
Plus de détails peuvent être trouvés à: RecyclerViewActions.actionOnItem
La solution de Danny Roa est géniale, mais elle n'a pas fonctionné pour les éléments hors écran que je venais de parcourir. Le correctif remplace ceci:
View targetView = recyclerView.getChildAt(this.position)
.findViewById(this.viewId);
avec ça:
View targetView = recyclerView.findViewHolderForAdapterPosition(this.position)
.itemView.findViewById(this.viewId);
... dans la classe TestUtils
.
Ce fil est assez ancien mais j'ai récemment étendu la prise en charge de RecyclerViewAction pour qu'elle soit également utilisable pour les assertions. Cela vous permet de tester des éléments hors écran sans spécifier de position tout en utilisant des égaliseurs de vue.
Consultez cet article> Mieux Android Test RecyclerView !