Android Espresso: нажмите на определенный вид внутри элемента RecyclerView - PullRequest
0 голосов
/ 20 июня 2019

У меня есть следующий список RecyclerView:

enter image description here

Я хочу, чтобы только в моем тесте был установлен флажок справа, а не весь элемент.Вот что я попробовал:

onView(withId(R.id.recycler_view))
    .perform(actionOnViewHolder<ViewHolder>(matcher = { vh ->
        if (vh == null) return@actionOnViewHolder false

        if (vh.position == no) {
            // v1
            (vh.itemView as ViewGroup).findViewById<View>(R.id.checkbox)?.performClick()
            // v2
            (vh.itemView as ViewGroup).getChildAt(2)?.performClick()
        }
        return@actionOnViewHolder false
    }))

И некоторые вспомогательные методы / классы:

inline fun <reified VH : RecyclerView.ViewHolder> actionOnViewHolder(
    noinline matcher: (VH?) -> Boolean): RecyclerViewActions.PositionableRecyclerViewAction {
    return RecyclerViewActions.actionOnHolderItem(
        RecyclerViewViewHolderMatcher(VH::class.java, matcher), ViewActions.click())
}

class RecyclerViewViewHolderMatcher<VH : RecyclerView.ViewHolder>(
    clazz: Class<VH>,
    private val matcher: (VH?) -> Boolean) : BoundedMatcher<RecyclerView.ViewHolder, VH>(clazz) {

    override fun describeTo(description: Description?) { }

    override fun matchesSafely(item: VH): Boolean = matcher(item)
}

V1: (vh.itemView as ViewGroup).findViewById<View>(R.id.checkbox) возвращает ноль, хотя в отладчике я вижу, что представление, которое3 ребенка, последний из которых имеет идентификатор: checkbox.

V2: (vh.itemView as ViewGroup).getChildAt(2) возвращает представление, но щелчок происходит намного позже.

Кроме того, я всегда возвращаю falseот actionOnViewHolder, потому что я не хочу click() или что-либо еще для всего ViewHolder.

Есть ли способ сделать это лучше?

1 Ответ

0 голосов
/ 25 июня 2019

Добавить новый класс с помощью вспомогательного метода:

object EspressoMatchers { 
    fun atPositionOnView(mRecyclerViewId: Int, position: Int, targetViewId: Int): Matcher<View> {

    return object : TypeSafeMatcher<View>() {
        var resources: Resources? = null
        var childView: View? = null

        override fun describeTo(description: Description) {
            val id = targetViewId
            var idDescription = Integer.toString(id)
            if (this.resources != null) {
                try {
                    idDescription = this.resources!!.getResourceName(id)
                } catch (var4: Resources.NotFoundException) {
                    idDescription = String.format("%s (resource name not found)", id)
                }
            }
            description.appendText("with id: $idDescription")
        }

        public override fun matchesSafely(view: View): Boolean {
            this.resources = view.resources
            if (childView == null) {
                val recyclerView: RecyclerView = if (view.rootView.findViewById<View>(mRecyclerViewId) is RecyclerView) {
                    view.rootView.findViewById<View>(mRecyclerViewId) as RecyclerView
                } else {
                    //todo need only if you want acces to recyclerView in custom views
                }
                childView = recyclerView.findViewHolderForAdapterPosition(position)!!.itemView
            }
            val targetView = childView!!.findViewById<View>(targetViewId)
            return view === targetView
        }
    }
}}

Создать упаковщик ячеек

open class BaseCell(val listId: Int, val position: Int) {

public fun tap(id: Int) {
    onView(atPositionOnView(listId, position, id)).perform(click())
}
}

И тогда мы сможем использовать его в тесте

val cell = BaseCell(R.id.recyclerViewId, 0)
cell.tap(R.id.checkBoxId)
...