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
RecyclerView
API hérite deViewGroup
et 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.