I have the following RecyclerView list:
I only want my test to click on the checkbox on the right, not the whole item. Here is what I tried:
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
}))
And some helper methods/classes:
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)
returns null, even though in debugger I can see that the view that 3 childs, the last one having the id: checkbox
.
V2: (vh.itemView as ViewGroup).getChildAt(2)
returns the view, but a click happens way later.
Also, I always return false
from the actionOnViewHolder
because I don't want to click()
or anything else on the whole ViewHolder.
Is there any way to do this better?
Add new class with helper method:
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
}
}
}}
Create cell wrapper
open class BaseCell(val listId: Int, val position: Int) {
public fun tap(id: Int) {
onView(atPositionOnView(listId, position, id)).perform(click())
}
}
And then we can use it in test
val cell = BaseCell(R.id.recyclerViewId, 0)
cell.tap(R.id.checkBoxId)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.