How can I check the state of a menu item in Espresso? I am testing a Kotlin android application

20 Views Asked by At

I am testing whether the right message is displayed after unfavoriting a recipe. To prepare for the test, I am conditionally checking whether it is already favorited. If it isn't, I favorite it in the setup so that it can be unfavorited in the test.

This is the menu item:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/save_to_favorites_menu"
        android:icon="@drawable/ic_star"
        android:title="@string/save_to_favorites"
        app:showAsAction="ifRoom"
        android:iconTint="@color/white"
        tools:targetApi="o" />
</menu>

These are my tests:

    @Before
    fun setUp(){
        // Click on the first recipe
        Espresso.onView(ViewMatchers.withId(R.id.recyclerview))
            .perform(
                RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0,
                    ViewActions.click()
                ))
        // Add to favorites if it the favorite button is not checked
        if (!isChecked(R.id.save_to_favorites_menu)){
            // click on the favorites button
            Espresso.onView(ViewMatchers.withId(R.id.save_to_favorites_menu))
                .perform(ViewActions.click())
            Thread.sleep(5000)
        }
    }

    @Test
    fun testRemoveFromFavorites(){
        // click on the favorite button
        Espresso.onView(ViewMatchers.withId(R.id.save_to_favorites_menu))
            .perform(ViewActions.click())

        // check whether the right text is displayed
        Espresso.onView(ViewMatchers.withText("Removed from Favorites."))
            .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
    }

And this is my isChecked function:

    // check button state by action view
    fun isChecked(menuItemId: Int): Boolean {
        var isChecked = false

        // Use Espresso to check the menu item
        Espresso.onView(ViewMatchers.withId(menuItemId))
            .check { view, _ ->
                if (view is MenuItem) {
                    isChecked = view.isActionViewExpanded
                }
            }

        return isChecked
    }

I even tried checking the state if the button by checking its color like this:

Explanation: the star is sometimes white, sometimes black when it is not checked. It is yellow when it is checked, but I don't know what I should type after "R.color" for yellow color, which is why I am testing the opposite scenario - "button not checked".

    fun isNotCheckedByColor(buttonId: Int): Boolean {
        var isChecked = true

        val viewInteraction = Espresso.onView(ViewMatchers.withId(buttonId))
        viewInteraction.check { view, _ ->
            if (view is Button) {
                val buttonBackground: Drawable = view.background

                // Get the color resource for white
                val whiteColorResource = R.color.white
                val whiteColor = ContextCompat.getColor(view.context, whiteColorResource)

                // Get the color resource for black
                val blackColorResource = R.color.black
                val blackColor = ContextCompat.getColor(view.context, blackColorResource)


                val colorDrawable = buttonBackground as? ColorDrawable


                if (colorDrawable != null && (colorDrawable.color == whiteColor || colorDrawable.color == blackColor)) {
                    isChecked = false
                }
            }
        }

        return isChecked
    }

Nothing seems to work. isChecked always returns false and isNotCheckedByColor always returns true. Any idea why and how to fix it? Thank you in advance.

0

There are 0 best solutions below