2

I am writing espresso tests for my application. For one test I have to click a button on a RecyclerView-Item. Said item is bigger than the screen, so when I scroll to the item the required button is still not displayed (which is required so I can click it).

I tried to scroll to the view with

onView(withId(R.id.recycler_view)).perform(scrollTo<MyViewHolder>(hasDescendant(withId(R.id.target_button))))

but this just scrolled to the top of the item that contains the button. Since the button is at the very bottom of that item and the item is larger than the screen, when I try to click the button I get

Action will not be performed because the target view does not match one or more of the following constraints:
at least 90 percent of the view's area is displayed to the user.

I also tried

onView(withId(R.id.recycler_view)).perform(actionOnItemAtPosition<MyViewHolder>(0, EspressoUtils.clickChildViewWithId(R.id.target_button)))

where EspressoUtils.clickChildViewWithId(id: Int) is what is described in the accepted answer of this question. This also yielded the same error. How can I scroll to the specific child within the RecyclerView-Item?

Emil S.
  • 412
  • 4
  • 20
  • do you know the text of the item inside the recycler view to which you want to scroll to? – Alok Gupta Feb 15 '19 at 09:32
  • The Item inside the RecyclerView contains multiple views, including the one I want to click. I only know the text of the view I want to click in this scenario. – Emil S. Feb 15 '19 at 09:38
  • Can you check this link https://stackoverflow.com/questions/42915073/espresso-recyclerview-scroll-to-end it tells how to scroll to a position and then you can see this link https://stackoverflow.com/questions/31394569/how-to-assert-inside-a-recyclerview-in-espresso – Alok Gupta Feb 15 '19 at 09:42
  • Both questions deal with items, that fit the screen if they are scrolled to. If I scroll to my item, the lower part of it is still not displayed as the item is bigger than the screen. My question here is how I can get the lower part of the item displayed. – Emil S. Feb 15 '19 at 10:55
  • In your question, you said, "...when I try to click the button I get" but you didn't provide the code for how you tried. Btw, it's better to add the code for `EspressoUtils.clickChildViewWithId` to your question even if you provide a link. – Just The Highlights Feb 17 '19 at 02:03

1 Answers1

2

The following solution works for me when clicking a view inside a RecyclerView item that is twice as big as my screen. Note: the view I'm clicking is actually off the screen but since it's in the view hierarchy, it can be clicked.

Create a custom ViewAction:

private fun clickChildViewWithId(id: Int) = object : ViewAction {

    override fun getConstraints() = null

    override fun getDescription() = "click child view with id $id"

    override fun perform(uiController: UiController, view: View) {
        val v = view.findViewById<View>(id)
        v.performClick()
    }
}

Usage:

onView(withId(R.id.recycler_view))
            .perform(actionOnItemAtPosition<MyViewHolder>(0, clickChildViewWithId(R.id.target_button)))
Just The Highlights
  • 1,555
  • 19
  • 31
  • This didn't work for me initially. The click wouldn't fail with an error but the action of the click was not performed as an expected activity is not opened. But I found out I had to click the parent of that view as the view itself wasn't clickable, just it's parent is. Espresso should report to you if you ask it to click an unclickable item and not just do nothing. Anyways, thanks for the help. – Emil S. Feb 21 '19 at 12:49
  • 1
    Glad I could help. As for Espresso, I'm not sure whether it should tell you that a view is not clickable since that could be exactly what you're testing. But I see what you mean. – Just The Highlights Feb 21 '19 at 13:56