Testing visibility of Views with Espresso

donderdag 17 oktober 2019

Sometimes you’ll want to check whether a view is displayed or not during a test. Espresso supplies a few matchers that might be useful:

(this last one is actually a view assertion, not a matcher). These matchers are related, but check different aspects that play a role in the visibility of a view. That’s why it’s important to pick the right one that works for your scenario under all circumstances and on all types of devices.

Choosing the right matcher to check your view

I will discusses all three options and how they relate to each other, starting off with doesNotExist().

doesNotExist()

Chances are that the UI of the app that you’re checking contains multiple views. Take for example this language translation app:

Image 1. App hierarchy and view visibility

On the left side you can see a hierarchy of the views that are used in the UI. The one that’s selected is an ImageView, below that there’s a TextView and another TextView and so on. The doesNotExist() view assertion checks if a view exists in the current view hierarchy. For instance the following example will pass, because the view with id “made_up_view_id” does not exist in the hierarchy: onView(withId(R.id.<em>made_up_view_id</em>)).check(doesNotExist()) and onView(withId(R.id.<em>list_item_icon</em>)).check(doesNotExist()) would fail, because that id exists in the current hierarchy.

withEffectiveVisibility()

If a view exists in the hierarchy that’s no guarantee that it’s also visible. That’s where visibility comes in. The withEffectiveVisibility() matcher checks how the visibility of a view is set in the code.
If you look at the list on the right side in image one, you’ll see getVisibility() listed with value VISIBLE. There are two other possible values: INVISIBLEand GONE.

VISIBLE: The view is rendered as something that should be visible;
INVISIBLE: The view is invisible, but it still takes up space for layout purposes;
GONE: The view is invisible and doesn’t take any space.

Image 2. View with visibility set to INVISIBLE
Image 3. View with visibility set to GONE

You can check for effective visibility like this:
onView(withId(R.id.<em>miwok_text</em>)).check(matches(withEffectiveVisibility(Visibility.<strong>VISIBLE</strong>)))

isDisplayed()

This method checks if a view is displayed on screen (in other words, if it is visible from a user’s perspective). For example in the language app example that I’ve used above, there’s an item that contains the words “lutti” and “one”. If you scroll down in the app until that specific item in the list is not visible on screen anymore, the isDisplayed() check would fail.

usage:
onView(withId(R.id.<em>miwok_text</em>)).check(matches(isDisplayed())) or onView(withId(R.id.<em>miwok_text</em>)).check(matches(not(isDisplayed())))

Summary

doesNotExist() checks whether a view exists at all;
withEffectiveVisibility() assumes a view exists and checks the visibility state for the view in the code;
isDisplayed() assumes that a view exists and has effective visibility set to visible, and it checks if the view is currently displayed (to the user) on the screen.