web-dev-qa-db-fra.com

Utilisation d'Espresso pour cliquer sur une vue à l'intérieur d'un élément RecyclerView

Comment utiliser Espresso pour cliquer sur une vue spécifique dans un élément RecyclerView? Je sais que je peux cliquer sur l'élément en position 0 en utilisant:

onView(withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

Mais je dois cliquer sur une vue spécifique à l'intérieur de cet élément et non sur l'élément lui-même.

Merci d'avance.

-- modifier --

Pour être plus précis: j'ai un RecyclerView (R.id.recycler_view) quels éléments sont CardView (R.id.card_view). Dans chaque CardView J'ai quatre boutons (entre autres) et je veux cliquer sur un bouton spécifique (R.id.bt_deliver).

J'aimerais utiliser les nouvelles fonctionnalités d'Espresso 2.0, mais je ne suis pas sûr que ce soit possible.

Si ce n’est pas possible, je voudrais utiliser quelque chose comme ceci (en utilisant le code Thomas Keller):

onRecyclerItemView(R.id.card_view, ???, withId(R.id.bt_deliver)).perform(click());

mais je ne sais pas quoi mettre sur les points d'interrogation.

86
Filipe Ramos

Vous pouvez le faire avec une action d'affichage personnalisée.

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();
            }
        };
    }

}

Ensuite, vous pouvez cliquer dessus avec

onView(withId(R.id.rv_conference_list)).perform(
            RecyclerViewActions.actionOnItemAtPosition(0, MyViewAction.clickChildViewWithId(R.id. bt_deliver)));
119
blade

Maintenant, avec Android.support.test.espresso.contrib, c'est devenu plus simple:

1) Ajouter une dépendance de test

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'
}

* exclure 3 modules, car très probablement vous l'avez déjà

2) Ensuite, fais quelque chose comme

onView(withId(R.id.recycler_grid))
            .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

Ou

onView(withId(R.id.recyclerView))
  .perform(RecyclerViewActions.actionOnItem(
            hasDescendant(withText("whatever")), click()));

Ou

onView(withId(R.id.recycler_linear))
            .check(matches(hasDescendant(withText("whatever"))));
58
Andrey

Essayez l'approche suivante:

    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;
                }

            }
        };
    }
}
6
Sergey

Voici comment j'ai résolu le problème dans 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))
}

et alors

onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(position, clickOnViewChild(R.id.viewToClickInTheRow)))
4
user2768856

Vous pouvez cliquer sur ème élément de recyclerView comme ceci:

onView(withId(R.id.recyclerView)).perform(
                RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(2,click()))

Faites n'oubliez pas pour fournir le type ViewHolder afin que l'inférence n'échoue pas.

2
erluxman