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.

32
demandé sur Mr-IDE 2014-12-10 11:45:05

8 réponses

Use RecyclerViewActions

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'
}
63
répondu Gabor 2016-11-15 09:44:21

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)

21
répondu Sir4ur0n 2015-06-19 06:59:14

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 de ViewGroup et non de AdapterView , vous ne pouvez pas utiliser le onData() D'Espresso pour tester les mises en page en utilisant ce composant.

lien vers Gist .

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")));
14
répondu aried3r 2016-11-15 09:45:56

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));
    }
}
4
répondu fede1608 2016-01-27 12:53:36

j'ai trouvé deux façons:

  1. 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());

  1. 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());
2
répondu Luo Lei 2017-01-28 01:27:27

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()));
1
répondu Víctor Albertos 2015-09-03 09:11:45

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.

1
répondu vedant 2016-03-25 15:21:55

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.

0
répondu denys 2017-05-23 12:10:36