How to click on an item inside a RecyclerView in Espresso

前端 未结 10 2266
逝去的感伤
逝去的感伤 2020-12-01 05:33

I have a RecyclerView (R.id.recyclerView) where each row has an image (R.id.row_image) and a TextView. I want to click on the image in the first row.
I\'ve tried to use

相关标签:
10条回答
  • 2020-12-01 05:41

    Use RecyclerViewActions

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

    Include this in your gradle script:

    dependencies {
        androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
        androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0'
    }
    
    0 讨论(0)
  • 2020-12-01 05:41

    Edit:

    Espresso 2.0 has been released, the changelog includes the following:

    New Features

    • espresso-contrib
      • RecyclerViewActions: handles interactions with RecyclerViews

    Old Answer

    I haven't yet tested this myself, but Thomas Keller posted this on G+ with a short explanation and a link to a Gist with the necessary view matchers.

    Since the new RecyclerView API inherits from ViewGroup and not from AdapterView, you cannot use Espresso's onData() to test layouts using this component.

    Link to Gist.

    I'll attach the code, just for completeness sake (note: not mine! All credit goes to 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));
        }
    }
    

    And sample usage:

    onRecyclerItemView(R.id.item_title, withText("Test"),  withId(R.id.item_content))
        .matches(check(withText("Test Content")));
    
    0 讨论(0)
  • 2020-12-01 05:50

    Just to add to Gabor's answer (which is the correct and complete answer since Espresso 2.0).

    You may encounter problems at the moment when using espresso-contrib and RecyclerViews (see android-test-kit ticket).

    A workaround is to add this exclusion in the espresso-contrib dependency Gabor mentioned above:

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

    (This is an answer instead of a comment to Gabor's answer because I don't have the right to post comments yet)

    0 讨论(0)
  • 2020-12-01 05:52

    You needn't to add "testing-support-lib", neither "espresso:espresso-core". They are transitive added when "espresso:espresso-contrib" is added.

    build.grade

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

    Usage:

    onView(withId(R.id.recyclerView)).perform(
                RecyclerViewActions.actionOnItemAtPosition(0, click()));
    
    0 讨论(0)
  • 2020-12-01 05:53

    I have found two ways:

    1. Assuming you have a textview with id "R.id.description" for each item in the RecyclerView. You can do this to match a specific child:

    onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());

    1. A tutorial from 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);
                }
            };
        }
    

    `

    And then, do this:

    onView(withItemText("what")).perform(click());
    
    0 讨论(0)
  • 2020-12-01 05:53

    Same answer like above but when some small modification since you have to provide the Viewholder type

    With using RecyclerViewActions

    fun tapOnRecyclerView(@IdRes resId: Int , position: Int) = onView(withId(resId))
            .perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(position, click()));
    

    and to include this libraries in your project , use this

    androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
    androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
    

    Prefer to use the latest espresso version from this link

    0 讨论(0)
提交回复
热议问题