androidkotlinandroid-espresso

Espresso not finding text inside of Custom View


Say I have a Custom View built from scratch that looks like this:

class CustomTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0
) : View(context, attrs, defStyleAttr, defStyleRes) {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL_AND_STROKE
        textSize = 48f
        color = Color.BLUE
        strokeWidth = 3f
    }

    override fun onDraw(canvas: Canvas?) {
        canvas?.drawText("Text from Custom view", width / 2f, height / 2f, paint)
    }
}

This is very simple drawing Text on Canvas. And in a fragment layout, I add a TextView and my CustomText view like the following:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="32dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text from Text View" />

    <com.example.testing.views.CustomTextView 
        android:layout_width="250dp"
        android:layout_height="32dp"
        android:layout_marginTop="10dp" />

</LinearLayout

My espresso test file looks like:

@RunWith(AndroidJUnit4::class)
class MyFragmentTest {
    private lateinit var scenario: FragmentScenario<MyFragment>

    @Before
    fun setup() {
        scenario = launchFragmentInContainer(themeResId = R.style.Theme_Testing)
        scenario.moveToState(Lifecycle.State.STARTED)
    }

    @Test
    fun testNormalTextView() { // -> PASSED
        onView(withText("Text from Text View")).check(matches(isDisplayed()))
    }

    @Test
    fun testCustomTextView() { // -> FAILED NoMatchingView Exception
        onView(withText("Text from Custom View")).check(matches(isDisplayed()))
    }
}

When I run the tests on my physical device, it passes only testNormalTextView but it fails on testCustomTextView. How do I make these Espresso test pass with Custom Views?


Solution

  • From the official docs, withText() viewMatcher works with Textviews.

    Returns a matcher that matches TextView based on its text property value.

    In your case your custom view is extending View class.

    Following are two ways which i will suggest.

    1. Make your custom view extend TextView. [If your requirement is to access only the view with the specific text regardless of it's id]
    2. Use withId() viewMatcher instead of withText(), passing id of your customview given in xml layout. You need to give id to your custom view in xml. [If you want to check view with specific id, not with the text it holds]

    In your xml

       <com.example.testing.views.CustomTextView 
            android:id="@+id/my_custom_view"
            android:layout_width="250dp"
            android:layout_height="32dp"
            android:layout_marginTop="10dp" />
    

    In your testFunction

        @Test
        fun testCustomTextView() {
            onView(withId(R.id.my_custom_view)).check(matches(isDisplayed()))
        }
    

    Update:

    For recyclerview, you can use onData() instead of onView() passing matcher in argument. You can find further info about testing adapterViews here