Espresso - How to check if one of the view is displayed

85,359

Solution 1

It's possible to catch the exceptions raised by Espresso like this:

If you want to test if a view is in hierarchy:

try {
    onView(withText("Button")).perform(click());
    // View is in hierarchy

} catch (NoMatchingViewException e) {
    // View is not in hierarchy
}

This exception will be thrown if the view is not in the hierarchy.

Sometimes the view can be in the hierarchy, but we need to test if it is displayed, so there is another exception for assertions, like this:

try {
    onView(withText("Button")).check(matches(isDisplayed()));
    // View is displayed
} catch (AssertionFailedError e) {
    // View not displayed
}

Solution 2

There are two cases here that you could be trying to cover. The first is if you are checking if the view "is displayed on the screen to the user" in which case you would use isDisplayed()

onView(matcher).check(matches(isDisplayed()));

or the negation

onView(matcher).check(matches(not(isDisplayed())));

The other case is if you are checking if the view is visible but not necessarily displayed on the screen (ie. an item in a scrollview). For this you can use withEffectiveVisibility(Visibility)

onView(matcher).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

Solution 3

You can use Matchers.anyOf to check if any of the two views are displayed:

onView(
   anyOf(withId(R.id.view_1), withId(R.id.view_2)) 
).check(matches(isDisplayed()));

Solution 4

For the ones looking to check the visibility status for a view; here are some utility functions I use.

fun ViewInteraction.isGone() = getViewAssertion(ViewMatchers.Visibility.GONE)

fun ViewInteraction.isVisible() = getViewAssertion(ViewMatchers.Visibility.VISIBLE)

fun ViewInteraction.isInvisible() = getViewAssertion(ViewMatchers.Visibility.INVISIBLE)

private fun getViewAssertion(visibility: ViewMatchers.Visibility): ViewAssertion? {
    return ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(visibility))
}

And can be used as follows

onView(withId(R.id.progressBar)).isVisible()
onView(withId(R.id.progressBar)).isGone()

Solution 5

I researched Espresso a bit, and I found this @ Espresso Samples.

  1. Search text "Asserting that a view is not displayed". It says "The above approach works if the view is still part of the hierarchy." So I think your code should work but you need to use ViewAssertions also. Using your code, perhaps do this:

    if (ViewAssertions.doesNotExist()) == null) {
       return;
    }
    onMyPageOne.check(matches(isDisplayed()));
    
  2. Another technique is check for UI existence. Search for text "Asserting that a view is not present". Using your code, my best suggestion is:

    onMyPageOne.check(doesNotExist());

Note: This calls doesNotExist method.

Their sample code is: onView(withId(R.id.bottom_left)).check(doesNotExist());

Share:
85,359
user846316
Author by

user846316

Android, iOS, Windows, Mac, Unix (Linux, Solaris, Suse, Sol86, HP-UX, IBM-UX...) Android phones, tablets, iPhone, iPad, Alexa, Kindle Fire, Kindle eReader, Fire TV, Chromecast, Raspberry Pi etc etc etc... you name it, I have it all... don't you think I'm a geek???

Updated on May 25, 2020

Comments

  • user846316
    user846316 about 4 years

    In my test, after one action, there are two possible views which can appear and both of them are correct. How can I check if one of the view is displayed. For a single view I can check with is Displayed(). But that would fail if other view is visible instead. I want to pass the test if any one of those two views are displayed.

    onMyButton.perform(click());
    
    onMyPageOne.check(matches(isDisplayed())); //view 1
    or
    onMyPageTwo.check(matches(isDisplayed())); //view 2
    

    After, perform click on MyButton, any one of the view (1 or 2) is expected to appear but not both. It is not fixed that which one would be displayed. How can I check if any one of them is displayed?