Comment cliquer sur un article à L'intérieur D'un RecyclerView dans Espresso
I have a RecyclerView (R. id.recyclerView) où chaque ligne a une image (R. id.row_image) et un TextView. Je veux cliquer sur l'image dans la première rangée.
J'ai essayé d'utiliser onData(..) mais il ne semble pas fonctionner.
8 réponses
onView(withId(R.id.recyclerView))
.perform(actionOnItemAtPosition(0, click()));
incluez ceci dans votre script gradle:
dependencies {
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0'
}
juste pour ajouter à la réponse de Gabor (qui est la réponse correcte et complète depuis Espresso 2.0).
vous pouvez rencontrer des problèmes au moment où vous utilisez espresso-contrib et RecyclerView s (Voir android-Test-Kit ticket ).
une solution consiste à ajouter cette exclusion dans la dépendance espresso-contrib Gabor mentionnée ci-dessus:
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'
}
(ceci est une réponse au lieu d'un commentaire à la réponse de Gabor parce que je n'ai pas encore le droit de poster des commentaires)
Edit:
Espresso 2.0 a été publié, le changelog comprend ce qui suit:
Nouvelles Caractéristiques
- espresso-contrib
- RecyclerViewActions: gère les interactions avec les RecyclerViews
Vieille Réponse
Je ne l'ai pas encore testé moi-même, mais Thomas Keller posté ce sur G+ avec une courte explication et un lien vers un Gist avec les matches de vue nécessaires.
depuis que le nouveau
RecyclerViewAPI hérite deViewGroupet non deAdapterView, vous ne pouvez pas utiliser leonData()D'Espresso pour tester les mises en page en utilisant ce composant.
je joindrai le code, juste pour être complet (note: pas le mien! tout le crédit va à Thomas Keller)
ViewMatcher:
public class ViewMatchers {
@SuppressWarnings("unchecked")
public static Matcher<View> withRecyclerView(@IdRes int viewId) {
return allOf(isAssignableFrom(RecyclerView.class), withId(viewId));
}
@SuppressWarnings("unchecked")
public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) {
Matcher<View> itemView = allOf(withParent(withRecyclerView(R.id.start_grid)),
withChild(allOf(withId(identifyingView), identifyingMatcher)));
return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher));
}
}
et échantillon d'utilisation:
onRecyclerItemView(R.id.item_title, withText("Test"), withId(R.id.item_content))
.matches(check(withText("Test Content")));
vous devez utiliser une ViewAction personnalisée:
public void clickOnImageViewAtRow(int position) {
onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView()));
}
public class ClickOnImageView implements ViewAction{
ViewAction click = click();
@Override
public Matcher<View> getConstraints() {
return click.getConstraints();
}
@Override
public String getDescription() {
return " click on custom image view";
}
@Override
public void perform(UiController uiController, View view) {
click.perform(uiController, view.findViewById(R.id.imageView));
}
}
j'ai trouvé deux façons:
- en supposant que vous avez un textview avec id " R. id.description" pour chaque article du RecyclerView. Vous pouvez faire cela pour correspondre à un enfant spécifique:
onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());
- un tutoriel D'Android Testing Codelab https://codelabs.developers.google.com/codelabs/android-testing/#0
`
public Matcher<View> withItemText(final String itemText) {
checkArgument(!TextUtils.isEmpty(itemText),"cannot be null");
return new TypeSafeMatcher<View>() {
@Override
protected boolean matchesSafely(View item) {
return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item);
}
@Override
public void describeTo(Description description) {
description.appendText("is descendant of a RecyclerView with text" + itemText);
}
};
}
"
et ensuite, faites ceci:
onView(withItemText("what")).perform(click());
il n'est pas nécessaire d'ajouter" testing-support-lib", ni"espresso:espresso-core". Ils sont transitifs lorsque "espresso: espresso-contrib" est ajouté.
"151950920 de construire".classe
dependencies {
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2'
}
Utilisation :
onView(withId(R.id.recyclerView)).perform(
RecyclerViewActions.actionOnItemAtPosition(0, click()));
j'ai suivi la réponse de @Gabor mais quand j'ai inclus les bibliothèques, j'ai atteint la limite dex!
donc, j'ai enlevé les bibliothèques, ajouté ce getInstrumentation().waitForIdleSync(); et puis juste appelé onView(withId...))...
fonctionne parfaitement.
dans votre cas, vous aurez plusieurs vues d'image avec le même ID de sorte que vous aurez à comprendre quelque chose sur la façon dont vous pouvez sélectionner l'élément de la liste particulière.
Comme je l'ai posté ici , vous pouvez mettre en œuvre votre custom RecyclerView matcher. Supposons que vous avez RecyclerView où chaque élément a sujet vous wonna match:
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);
}
};
}
et usage:
onView(withId(R.id.my_recycler_view_id)
.perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));
vous pouvez faire correspondre tout ce que vous voulez. Dans cet exemple, nous avons utilisé le sujet TextView , mais il peut s'agir de n'importe quel élément de l'élément RecyclerView .
une autre chose à clarifier est vérifier la visibilité (subjectTextView.getVisibility() == View.VISIBLE) . Nous devons l'avoir parce que parfois d'autres vues à l'intérieur de RecyclerView peuvent avoir le même sujet, mais ce serait avec View.GONE . De cette façon, nous évitons plusieurs correspondances de notre matcher personnalisé et la cible seulement l'article qui affiche réellement notre sujet.