How to count RecyclerView items with Espresso
Asked Answered
R

8

71

Using Espresso and Hamcrest,

How can I count items number available in a recyclerView?

Exemple: I would like check if 5 items are displaying in a specific RecyclerView (scrolling if necessary).

Rescue answered 4/4, 2016 at 10:7 Comment(1)
An answer Related to this AnswerAnson
F
115

Here an example ViewAssertion to check RecyclerView item count

public class RecyclerViewItemCountAssertion implements ViewAssertion {
  private final int expectedCount;

  public RecyclerViewItemCountAssertion(int expectedCount) {
    this.expectedCount = expectedCount;
  }

  @Override
  public void check(View view, NoMatchingViewException noViewFoundException) {
    if (noViewFoundException != null) {
        throw noViewFoundException;
    }

    RecyclerView recyclerView = (RecyclerView) view;
    RecyclerView.Adapter adapter = recyclerView.getAdapter();
    assertThat(adapter.getItemCount(), is(expectedCount));
  }
}

and then use this assertion

onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(5));

I have started to write an library which should make testing more simple with espresso and uiautomator. This includes tooling for RecyclerView action and assertions. https://github.com/nenick/espresso-macchiato See for example EspRecyclerView with the method assertItemCountIs(int)

Farhi answered 20/5, 2016 at 6:43 Comment(8)
This test always passes. I don't think it is working properly.Frizette
adapter.getItemCount() is coming null..Can u pls let me know the reason for that.Gunnery
@Frizette many has confirmed that this work, but please explain your situation where it always pass.Farhi
@VikashKumar does it return null or zero? Null should not be possible. But maybe its timing issue and your adapter has zero items at check time? Often occurs when using background tasks.Farhi
What about how to count the items, not how to check there are X items?Stability
tested this and it work with failure and success. thanksBedrail
Working as expected Tested with a positive and negative expectation. Logs Expected: is <2> Got: <3>Spermatophyte
Does not work no more. A white screen is shown and no response more is collected, eventually failing the test.Standush
K
35

Adding a bit of syntax sugar to the @Stephane's answer.

public class RecyclerViewItemCountAssertion implements ViewAssertion {
    private final Matcher<Integer> matcher;

    public static RecyclerViewItemCountAssertion withItemCount(int expectedCount) {
        return withItemCount(is(expectedCount));
    }

    public static RecyclerViewItemCountAssertion withItemCount(Matcher<Integer> matcher) {
        return new RecyclerViewItemCountAssertion(matcher);
    }

    private RecyclerViewItemCountAssertion(Matcher<Integer> matcher) {
        this.matcher = matcher;
    }

    @Override
    public void check(View view, NoMatchingViewException noViewFoundException) {
        if (noViewFoundException != null) {
            throw noViewFoundException;
        }

        RecyclerView recyclerView = (RecyclerView) view;
        RecyclerView.Adapter adapter = recyclerView.getAdapter();
        assertThat(adapter.getItemCount(), matcher);
    }
}

Usage:

    import static your.package.RecyclerViewItemCountAssertion.withItemCount;

    onView(withId(R.id.recyclerView)).check(withItemCount(5));
    onView(withId(R.id.recyclerView)).check(withItemCount(greaterThan(5)));
    onView(withId(R.id.recyclerView)).check(withItemCount(lessThan(5)));
    // ...
Kickstand answered 4/4, 2017 at 12:16 Comment(2)
Wonderful. I would suggest getting this into espresso because it is really strange that such a core feature is not available.Uvarovite
Does not work no more. A white screen is shown and no response more is collected, eventually failing the test.Standush
P
21

To complete nenick answer and provide and little bit more flexible solution to also test if item cout is greaterThan, lessThan ...

public class RecyclerViewItemCountAssertion implements ViewAssertion {

    private final Matcher<Integer> matcher;

    public RecyclerViewItemCountAssertion(int expectedCount) {
        this.matcher = is(expectedCount);
    }

    public RecyclerViewItemCountAssertion(Matcher<Integer> matcher) {
        this.matcher = matcher;
    }

    @Override
    public void check(View view, NoMatchingViewException noViewFoundException) {
        if (noViewFoundException != null) {
            throw noViewFoundException;
        }

        RecyclerView recyclerView = (RecyclerView) view;
        RecyclerView.Adapter adapter = recyclerView.getAdapter();
        assertThat(adapter.getItemCount(), matcher);
    }

}

Usage:

onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(5));
onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(greaterThan(5));
onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(lessThan(5));
// ...
Pellegrino answered 12/9, 2016 at 9:12 Comment(0)
L
20

Validated answer works but we can solve this problem with one line and without adapter awareness :

onView(withId(R.id.your_recycler_view_id)).check(matches(hasChildCount(2)))

Replace your_recycler_view_id with your id and 2 with the number to assert.

Lathrope answered 27/3, 2019 at 16:10 Comment(4)
IDE says: Cannot resolve method hasChildCount(int)Sewn
Don't forget to import androidx.test.espresso.matcher.ViewMatchers.hasChildCountLathrope
Does this count the total number of items that can be displayed (i.e. the adapter's getItemCount()) or does it count the number of recycled views currently in the RecyclerView?Ami
Good question. Probably not the adapter's getItemCount(). So this solution is only feasible when you can have limited number of items and not on all devices.Lathrope
O
12

Based on @Sivakumar Kamichetty answer:

  1. Variable 'COUNT' is accessed from within inner class, needs to be declared final.
  2. Unnecessarily line: COUNT = 0;
  3. Transfer COUNT variable to one element array.
  4. Variable result is unnecessary.

Not nice, but works:

public static int getCountFromRecyclerView(@IdRes int RecyclerViewId) {
    final int[] COUNT = {0};
    Matcher matcher = new TypeSafeMatcher<View>() {
        @Override
        protected boolean matchesSafely(View item) {
            COUNT[0] = ((RecyclerView) item).getAdapter().getItemCount();
            return true;
        }
        @Override
        public void describeTo(Description description) {}
    };
    onView(allOf(withId(RecyclerViewId),isDisplayed())).check(matches(matcher));
    return COUNT[0];
}
Oneidaoneil answered 22/12, 2017 at 14:24 Comment(0)
E
10

You can create a custom BoundedMatcher:

object RecyclerViewMatchers {
    @JvmStatic
    fun hasItemCount(itemCount: Int): Matcher<View> {
        return object : BoundedMatcher<View, RecyclerView>(
            RecyclerView::class.java) {

            override fun describeTo(description: Description) {
                description.appendText("has $itemCount items")
            }

            override fun matchesSafely(view: RecyclerView): Boolean {
                return view.adapter.itemCount == itemCount
            }
        }
    }
}

And then use it like this:

onView(withId(R.id.recycler_view)).check(matches((hasItemCount(5))))
Ectoderm answered 2/5, 2018 at 9:3 Comment(0)
V
9

I used the below method to get the count of RecyclerView

public static int getCountFromRecyclerView(@IdRes int RecyclerViewId) {
int COUNT = 0;
        Matcher matcher = new TypeSafeMatcher<View>() {
            @Override
            protected boolean matchesSafely(View item) {
                COUNT = ((RecyclerView) item).getAdapter().getItemCount();
                return true;
            }
            @Override
            public void describeTo(Description description) {
            }
        };
        onView(allOf(withId(RecyclerViewId),isDisplayed())).check(matches(matcher));
        int result = COUNT;
            COUNT = 0;
        return result;
    }

Usage -

int itemsCount = getCountFromRecyclerView(R.id.RecyclerViewId);

Then perform assertions to check if the itemsCount is as expected

Vierno answered 2/8, 2017 at 8:50 Comment(0)
B
-2

count with ActivityScenarioRule

@get: Rule
val activityScenarioRule = ActivityScenarioRule(ShowListActivity::class.java)
@Test
fun testItemCount(){
activityScenarioRule.scenario.onActivity { activityScenarioRule ->
    val recyclerView = activityScenarioRule.findViewById<RecyclerView(R.id.movieListRecyclerView)
    val itemCount = recyclerView.adapter?.itemCount?:0
    ....
    }
}
Bandsman answered 7/9, 2021 at 9:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.