The answer by @Barry Irvine is really helpful. Just wanted to clarify if anyone wonders how to use the given Matcher method in an Espresso test. (Kotlin)
Step 1: Create a new file CustomMatchers from this link mentioned in the question.
(include the sameBitmap
method, however, looking at the comments, modified the sameBitmap
method)
You could directly add the method within your test file, but adding it in a different file would help in re-using it whenever you need to test menu item icons.
For reference, this is how my CustomMatchers
file looks like
object CustomMatchers {
fun withActionIconDrawable(@DrawableRes resourceId: Int): Matcher<View?> {
return object : BoundedMatcher<View?, ActionMenuItemView>(ActionMenuItemView::class.java) {
override fun describeTo(description: Description) {
description.appendText("has image drawable resource $resourceId")
}
override fun matchesSafely(actionMenuItemView: ActionMenuItemView): Boolean {
return sameBitmap(
actionMenuItemView.context,
actionMenuItemView.itemData.icon,
resourceId,
actionMenuItemView
)
}
}
}
private fun sameBitmap(
context: Context,
drawable: Drawable?,
resourceId: Int,
view: View
): Boolean {
var drawable = drawable
val otherDrawable: Drawable? = context.resources.getDrawable(resourceId)
if (drawable == null || otherDrawable == null) {
return false
}
if (drawable is StateListDrawable) {
val getStateDrawableIndex =
StateListDrawable::class.java.getMethod(
"getStateDrawableIndex",
IntArray::class.java
)
val getStateDrawable =
StateListDrawable::class.java.getMethod(
"getStateDrawable",
Int::class.javaPrimitiveType
)
val index = getStateDrawableIndex.invoke(drawable, view.drawableState)
drawable = getStateDrawable.invoke(drawable, index) as Drawable
}
val bitmap = getBitmapFromDrawable(context, drawable)
val otherBitmap = getBitmapFromDrawable(context, otherDrawable)
return bitmap.sameAs(otherBitmap)
}
private fun getBitmapFromDrawable(context: Context?, drawable: Drawable): Bitmap {
val bitmap: 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
} }
Step 2: Using the matcher in a test
onView(withId(R.id.menu_item_id))
.check(matches(CustomMatchers.withActionIconDrawable(R.drawable.ic_favorite_border)))
BottomNavigationItemView
instead ofActionMenuItemView
– Antislavery