2

There are posts on how to click on a certain item in a RecyclerView at whatever position you input, but is there a way to click on all the views, especially given the fact that I may not know how many views there will be in the Recycler View.

I thought of getting the number of items in the RecyclerView like in this link but it involves getting the actual RecyclerView from the activity which sometimes is not possible.

I've also seen a block of code like:

public static 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));
    }
}

But i'm unsure of how to manipulate to get the count

3 Answers3

1

So simply in your test:

final View viewById = activityTestRule.getActivity().findViewById(R.id.your_recycler_view_id);
final RecyclerView recyclerView = (RecyclerView) viewById;
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
final int itemsCount = adapter.getItemCount();

So you can iterate through from 0 to itemsCount-1

You can use this class to get recycler view element at position (in your case 0 to itemsCount-1)

public class RecyclerViewMatcher {
private final int recyclerViewId;

public RecyclerViewMatcher(int recyclerViewId) {
    this.recyclerViewId = 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) {
            String idDescription = Integer.toString(recyclerViewId);
            if (this.resources != null) {
                try {
                    idDescription = this.resources.getResourceName(recyclerViewId);
                } catch (Resources.NotFoundException var4) {
                    idDescription = String.format("%s (resource name not found)", recyclerViewId);
                }
            }

            description.appendText("with id: " + idDescription);
        }

        public boolean matchesSafely(View view) {

            this.resources = view.getResources();

            if (childView == null) {
                RecyclerView recyclerView =
                        (RecyclerView) view.getRootView().findViewById(recyclerViewId);
                if (recyclerView != null && recyclerView.getId() == recyclerViewId) {
                    childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
                } else {
                    return false;
                }
            }

            if (targetViewId == -1) {
                return view == childView;
            } else {
                View targetView = childView.findViewById(targetViewId);
                return view == targetView;
            }
        }
    };
}}

and use this class like this:

onView(new RecyclerViewMatcher(R.id.your_recycler_view_id)
            .atPositionOnView(0, R.id.your_item_body))
            .perform(click());

So finally you are able to click all items in your recyclerview. I hope it would help. Cheers.

Piotr Mądry
  • 221
  • 2
  • 7
0

I'm thinking out loud here, but a couple of things I would try are:
a- Check to see if there is any way to put this in the ViewHolder/RecyclerView Adapter. That really depends on when you want to trigger the click on all items so I'm guessing it won't work for you.
b- Try a while loop with a try/catch for getting the item. This doesn't sound like a good idea from a software engineering best practices perspective, but it should work if your goal is just to get something working.
c- If you can't get the recycler view itself, is there some way you can access the arraylist (or whatever) you used to populate the recyclerView itself?

Some questions:
1- In what cases is it not possible for you to get the actual recycler view? And if you can't get it, then how will you trigger its onclick anyway?
2- Could you maybe share your code and where you need to do this?

disclaimer: I'm a bit new to android development, but I hope this helps.

Dina
  • 23
  • 6
0

To be thread safe you should use custom view action something like

@RunWith(AndroidJUnit4.class)
public class XXXXActivityTest {

int count=0;

@Test
public void xxxxxxx() throws Exception {
    onView(allOf(withId(R.id.drawer_list))).perform(new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return null;
        }

        @Override
        public String getDescription() {
            return null;
        }

        @Override
        public void perform(UiController uiController, View view) {
            count=((ListView)view).getAdapter().getCount();
        }
    });

}
}

then you can iterate with

onView(new RecyclerViewMatcher(R.id.drawer_list)
        .atPositionOnView(0, R.id.your_item_body))
        .perform(click());
assertThat(.......) for all items
Amit Kaushik
  • 642
  • 7
  • 13