oldergod oldergod - 29 days ago 16
Android Question

How assert a BottomNavigationItemView is checked with Espresso?

BottomNavigationItemView
implements the
ItemView
interface which has the
setChecked()
method.

I tried to assert with Espresso that one itemView is checked but I got the same error, whatever my expected value is,
isChecked()
or
isNotChecked()
.

My test:

ViewInteraction buttonHome = onView(
allOf(withId(R.id.bottomHome),
childAtPosition(
childAtPosition(
withId(R.id.bottom_navigation),
0),
0),
isDisplayed()));
buttonHome.check(matches(isNotChecked()));


The error message

android.support.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'with checkbox state: is <true>' doesn't match the selected view.
Expected: with checkbox state: is <true>
Got: "BottomNavigationItemView{id=2131493015, res-name=bottomHome, visibility=VISIBLE, width=360, height=168, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}"


How could I assert a
BottomNavigationItemView
is the current selected item of the
BottomNavigationView
?

Answer

Both isChecked() andisNotChecked() expect Checkable interface to be implemented by the view.

Moreover, BottomNavigationItemView hides its checked status inside of the itemData field. This means that Espresso out of the box does not support this kind of a check. Luckily, Espresso is a very extensible framework and you can easily add functionality to it. In this case, we need to write a custom matcher to do the check.

Implementation of the said matcher might look like this:

public static Matcher<View> withBottomNavItemCheckedStatus(final boolean isChecked) {
    return new BoundedMatcher<View, BottomNavigationItemView>(BottomNavigationItemView.class) {
        boolean triedMatching;

        @Override
        public void describeTo(Description description) {
            if (triedMatching) {
                description.appendText("with BottomNavigationItem check status: " + String.valueOf(isChecked));
                description.appendText("But was: " + String.valueOf(!isChecked));
            }
        }

        @Override
        protected boolean matchesSafely(BottomNavigationItemView item) {
            triedMatching = true;
            return item.getItemData().isChecked() == isChecked;
        }
    };
}

And the usage is:

buttonHome.check(matches(withBottomNavItemCheckedStatus(false)));
Comments