Issue
I'm having a hard time figuring out how to test whether or not a certain image is being show on a position in a recyclerview using espresso. I have a list of people, and when one of them is selected, I'm showing a selected indicator around his image in the recyclerview. So I want to check that, for instance, position 0 has this indicator showing. What I'm trying is this:
fun test(position: Int, @DrawableRes res: Int): ViewInteraction {
return onView(withId(recyclerViewId)).check(matches(hasItemAtPosition(position, hasBackground(res))))
}
private fun hasItemAtPosition(position: Int, matcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has item at position $position : ")
matcher.describeTo(description)
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
?: return false
return matcher.matches(viewHolder.itemView)
}
}
}
This code works fine if I do it with withText rather than withBackground and match the text of the item.
The error I get looks like this:
androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'has item at position 0 : has background with drawable ID: 2131231310' doesn't match the selected view.
Expected: has item at position 0 : has background with drawable ID: 2131231310
I'm kind of new to espresso and testing in general, so hoping someone has any suggestions.
UPDATE:
The test method is inside a custom class I have looking like this:
class RecyclerViewWait(@IdRes val recyclerViewId: Int) {
test()
hasItemAtPosition()
}
So those two methods are in there as well (the ones above)
I am calling them from another class, like this:
override fun doesPositionContainImageInList(position: Int, imageRes: Int): ViewInteraction {
return RecyclerViewWait(R.id.recyclerViewTest).checkBackground(position, imageRes)
Which in return is called from my Robot class like this:
fun isImageShown(): Boolean {
return viewFinder.doesPositionContainImageInList(
0,
R.drawable.ic_selected_avatar
).isDisplayed()
}
I hope this makes sense.
Solution
My solution that worked, ended up being this:
fun checkBackground(position: Int, @DrawableRes imageRes: Int): ViewInteraction {
return onView(withId(recyclerViewId))
.check(matches(hasItemAtPosition(position, hasDescendant(withDrawable(imageRes)))))
}
private fun hasItemAtPosition(position: Int, matcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has item at position $position : ")
matcher.describeTo(description)
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
?: return false
return matcher.matches(viewHolder.itemView)
}
}
}
private fun withDrawable(@DrawableRes resourceId: Int): Matcher<View> {
return DrawableMatcher(resourceId)
}
private class DrawableMatcher(private val expectedId: Int) : TypeSafeMatcher<View>() {
@Suppress("ReturnCount")
override fun matchesSafely(target: View): Boolean {
if (target !is ImageView || target.visibility == View.GONE) {
return false
}
if (expectedId < 0) {
return target.drawable == null
}
val resources = target.context.resources
val expectedDrawable: Drawable =
ResourcesCompat.getDrawable(resources, expectedId, target.context.theme)
?: return false
val bitmap = getBitmap(target.drawable)
val otherBitmap = getBitmap(expectedDrawable)
return bitmap.sameAs(otherBitmap)
}
private fun getBitmap(drawable: Drawable): Bitmap {
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
override fun describeTo(description: Description?) {
description?.appendText("isMatchingDrawableResource")
}
}
With this I just ask checkBackground with the position and the imageRes that I want to check if is there. And I'm also checking that it is visible further down. I tried with isDisplayed from Espresso further up in the code, but that didn't work somehow.
Answered By - Mikkel Larsen
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.