6

The following statement does not work because doesNotExist() returns a ViewAssertion instead of a matcher. Any way to make it work without a try-catch?

.check(either(matches(doesNotExist())).or(matches(not(isDisplayed()))));
ferbeb
  • 163
  • 1
  • 2
  • 11
  • what you dont like at a `try-catch`? – Simon Schnell Dec 23 '16 at 08:38
  • 1
    @SimonSchnell it does not fit well into the grammar of the hamcrest matchers. I thought there might be a more beautiful solution. – ferbeb Dec 23 '16 at 09:59
  • 1
    From my point of view this statement is incorrect. `(not(isDisplayed()))` is used to check that view which is present in hierarchy is not displayed, but `doesNotExist()` verifies that view is not present in the hierarchy at all. They are contradicting each other. – denys Dec 23 '16 at 12:16
  • what about `.check(either(matches(is(doesNotExist()))).or(matches(not(isDisplayed()))));` ` – piotrek1543 Dec 24 '16 at 19:07
  • @piotrek1543 either cannot be applied to ViewAssertion, needs hamcrest matcher. – ferbeb Jan 02 '17 at 15:53
  • Correct answer https://stackoverflow.com/a/50263055/2212847 – jimmy0251 May 09 '18 at 22:46

4 Answers4

11

If you want to check if a view doesn't not exist in the hierarchy, please use below assertion.

ViewInteraction.check(doesNotExist());

If you want to check if a view exist in the hierarchy but not displayed to the user, please use below assertion.

ViewInteraction.check(matches(not(isDisplayed())));

Hope this helps.

  • While this is correct, I don't believe this is what he's asking. He wants to validate that it doesn't exist, but if it _does_, check to make sure it's at least not displayed. – Scott Merritt Apr 07 '23 at 20:46
5

I had the same issue, one of my views will not have a certain view initially but could add it and hide it later. Which state the UI was in depended on wether background activities were destroyed.

I ended up just writing a variation on the implementation of doesNotExist:

public class ViewAssertions {
    public static ViewAssertion doesNotExistOrGone() {
        return new ViewAssertion() {
            @Override
            public void check(View view, NoMatchingViewException noView) {
                if (view != null && view.getVisibility() != View.GONE) {
                    assertThat("View is present in the hierarchy and not GONE: "
                               + HumanReadables.describe(view), true, is(false));
                }
            }
        };
    }
}
user2143491
  • 341
  • 3
  • 8
1

I encountered a similar situation. I believe this works and will check to ensure that a displayed view does not exist. It needs to either be not displayed or not in the view hierarchy:

onView(allOf(withId(R.id.viewId), isDisplayed())).check(doesNotExist())
Scott Merritt
  • 1,284
  • 2
  • 13
  • 24
0

not(isDisplayed) is not perfect because i.e. the view might be displayed but below the screen in a ScrollView.

Simple checking view.getVisibility() != View.GONE also is not a 100% solution. If view parent is hidden, the view is effectively hidden so the test should pass the scenario.

I suggest checking if view and its parents are visible:

fun isNotPresented(): ViewAssertion = object : ViewAssertion {
    override fun check(view: View?, noViewFoundException: NoMatchingViewException?) {
        if (view != null) {
            if (view.visibility != View.VISIBLE) {
                return
            }
            var searchView: View = view
            while (searchView.parent != null && searchView.parent is View) {
                searchView = searchView.parent as View
                if (searchView.visibility != View.VISIBLE) {
                    return
                }
            }
            assertThat<Boolean>(
                "View is present in the hierarchy and it is visible" + HumanReadables.describe(view),
                true,
                `is`(false)
            )
        }
    }
}
Jacek Marchwicki
  • 1,565
  • 15
  • 17
  • I think a better way to deal with your particular example is to actually make the test scroll the view. `not(isDisplayed())` fails like that because espresso tests are built from the prespective of a user, if a view is outside the screen, then it is not displayed. If even after you scroll, the view is still not visible, then you have a problem. If you want to make sure the user sees what you want him to see, checking the visibility of the parent views is not a good way to do it. – Orgmir Jul 05 '19 at 00:32