Espresso: return boolean if view exists

Viewed 41964

I am trying to check to see if a view is displayed with Espresso. Here is some pseudo code to show what I am trying:

if (!Espresso.onView(withId(R.id.someID)).check(doesNotExist()){
   // then do something
 } else {
   // do nothing, or what have you
 }

But my problem is .check(doesNotExist()) does not return boolean. It is just an assertion. With UiAutomator I was able to just do something like so:

 if (UiAutomator.getbyId(SomeId).exists()){
      .....
   }
8 Answers

Why no one mentioned:

onView(withId(R.id.some_view_id)).check(matches(not(doesNotExist())))

just add not before doesNotExist. But if you use this logic a lot it's better to use a custom matcher.

It's been some time since this issue was stated, but as it is one of the top hit on Google when searching for ways to make sure a view is present, before doing any actions on it in Espresso, I would like to share my very basic way of handling this.

1: Start out by writing an extension to ViewInteraction:

fun ViewInteraction.exists(): Boolean {
val viewExists = AtomicReference<Boolean>()

this.perform(object : ViewAction {
    override fun perform(uiController: UiController?, view: View?) {
        viewExists.set(view != null)
    }

    override fun getConstraints(): Matcher<View>? {
        return Matchers.allOf(ViewMatchers.withEffectiveVisibility(
                ViewMatchers.Visibility.VISIBLE),
                ViewMatchers.isAssignableFrom(View::class.java))
    }

    override fun getDescription(): String {
        return "check if view exists"
    }
})
return viewExists.get()
}

2: Create a simple help method in your base class (to be used in all test classes):

fun viewExists(id: Int): Boolean {
    return try {
        onView(withId(id)).exists()
    } catch (e: RuntimeException) {
        false
    }
}

With this you either get true or false from onView(withId(id)).exists(), or safely catch the RuntimeException and return false.

Normally a simple check to .exists() would be sufficient, but in some cases, like when you are deleting ListView items until non is left -> when the last item is deleted, the ListView might no longer be present, then an Exception is thrown when trying to check if it exists.

3: With the above implementation, it is safe to check if any view exists, since the RuntimeException is handled nicely behind the scene:

if(viewExists(R.id.something)) {
    //do something
}
//do something else

I think that what Espresso wants you to do is to change your logic to use doesNotExist()

I have for example

        onView(snackBarMatcher).check(doesNotExist())

        onView(withId(R.id.button)).perform(click())
        onView(snackBarMatcher).check(matches(isDisplayed()))


Related