agoda-com/Kakao

Unable to click on a view inside a recyclerview viewholder

lewiemortier opened this issue · 8 comments

Steps to reproduce:

  1. Add a screen with a recyclerview
  2. Add a viewholder with a button to the recyclerview
  3. In the tests, go to the screen
  4. Get the first item inside the recyclerview
  5. Click on the button of the first item inside the recyclerview

Observed Results:

  • Instead of clicking on the button, the test runner clicks on the viewholder itself

Expected Results:

  • The test runner should click on the button inside the view holder

Relevant Code:

class ScreenA : Screen<ScreenA>() {

    val recycler by lazy {
        KRecyclerView({
            this.withId(R.id.recyclerview)
        }, {
            itemType(::ViewHolder)
        })
    }

    class ViewHolder(parent: Matcher<View>) : KRecyclerItem<ViewHolder>(parent) {
        val title = KView(parent) { withId(R.id.title) }
        val moreOptions = KView { withId(R.id.more)  }
    }
}
Screen.onScreen<ScreenA> {
    recycler.firstChild<ScreenA.ViewHolder> { 
        moreOptions.click()
    }
}

Hi!
You forgot to pass parent to your moreOptions view. Here's how it should be declared:

val moreOptions = KView(parent) { withId(R.id.more) }
Vacxe commented

@lewiemortier let us know please does it solve the issue?

Adding the parent to the view inside the recyclerview item did not work for me. The click is still happening on the middle of the viewholder instead of on the button which is displayed on the bottom right of the viewholder.

Obviously we don't want to pass any coordinates to the click method as those coordinates will differ depending on the device this test is running on

We're using version 2.1.0 of the library

Can you provide your layout then, please?
If espresso clicks at the center of the holder, it believes that the center of the button is at that point as well.

The provided layout looks like this

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
        android:contentDescription="@string/search_result_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/spListSelectorActivated"
        android:minHeight="@dimen/row_height_72"
        android:paddingBottom="@dimen/padding_medium"
        android:paddingTop="@dimen/padding_medium"
        android:paddingStart="@dimen/padding_medium"
        android:paddingEnd="@dimen/padding_medium"
        tools:background="@android:color/darker_gray">

    <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/icon"
            android:layout_width="@dimen/content_picker_search_preview"
            android:layout_height="@dimen/content_picker_search_preview"
            android:layout_marginEnd="@dimen/padding_medium"
            android:layout_centerVertical="true"/>

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_toEndOf="@id/icon"
            android:layout_toStartOf="@id/ib_more">

        <TextView
                android:id="@+id/title"
                style="@style/SP.Text.Primary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:maxLines="2"
                android:textSize="16sp"
                android:layout_marginBottom="8dp" />

        <FrameLayout
                android:id="@+id/layout_tags"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:minHeight="20dp"
                android:layout_marginBottom="8dp"/>

        <TextView
                android:id="@+id/id_snippet"
                style="@style/SP.Text.Primary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLines="2"
                android:ellipsize="end"/>

    </LinearLayout>

    <ImageView
            android:id="@+id/more"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_marginStart="@dimen/padding_medium"
            android:rotation="90"
            app:srcCompat="@drawable/ic_more_vert_white_24dp"/>

</RelativeLayout>

In the UI test we're trying to click on the mroe button.
We've temporarily worked around the issue by using the following code snippet:

fun clickChildViewWithId(id: Int): ViewAction {
        return object : ViewAction {
            override fun getConstraints(): Matcher<View>? {
                return null
            }

            override fun getDescription(): String {
                return "Click on a child view with specified id."
            }

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

Hello again!
I don't see any obvious issue with your layout, but I suggest you to debug it with LayoutInspector and check the boundaries of your ImageView.
Your workaround just triggers the click callback and do not simulate the real click from user.

@lewiemortier seems like the middle layout blocking the click event

 <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_toEndOf="@id/icon"
            android:layout_toStartOf="@id/ib_more">
...

If you see the id of android:layout_toStartOf="@id/ib_more" different to the more button id which should be android:id="@+id/more". I dont know if this would work but I think worth to try.

Closing this issue due to no activity