Search code examples
androidandroid-espresso

Android Espresso onData with doesNotExist


I am trying to verify that a ListView does not contain a particular item. Here's the code I'm using:

onData(allOf(is(instanceOf(Contact.class)), is(withContactItemName(is("TestName")))))
      .check(doesNotExist());

When the name exists, I correctly get an error because of check(doesNotExist()). When the name does not exist, I get the following error, because allOf(...) doesn't match anything:

Caused by: java.lang.RuntimeException: No data found matching: 
(is an instance of layer.sdk.contacts.Contact and is with contact item name:
is "TestName")

How can I get functionality like onData(...).check(doesNotExist())?

EDIT:

I have a terrible hack to get the functionality I'd like by using try/catch and inspecting the event's getCause(). I would love to replace this with a good technique.


Solution

  • According to Espresso samples you must not use onData(...) to check if view doesn't exists in adapter. Check this out - link. Read "Asserting that a data item is not in an adapter" part. You have to use a matcher together with onView() that finds the AdapterView.

    Based on Espresso samples from link above:

    1. matcher:

       private static Matcher<View> withAdaptedData(final Matcher<Object> dataMatcher) {
           return new TypeSafeMatcher<View>() {
      
               @Override
               public void describeTo(Description description) {
                   description.appendText("with class name: ");
                   dataMatcher.describeTo(description);
               }
      
               @Override
               public boolean matchesSafely(View view) {
                   if (!(view instanceof AdapterView)) {
                       return false;
                   }
      
                   @SuppressWarnings("rawtypes")
                   Adapter adapter = ((AdapterView) view).getAdapter();
                   for (int i = 0; i < adapter.getCount(); i++) {
                       if (dataMatcher.matches(adapter.getItem(i))) {
                           return true;
                       }
                   }
                   return false;
               }
           };
       }
      
    2. then onView(...), where R.id.list is the id of your adapter ListView:

       @SuppressWarnings("unchecked")
       public void testDataItemNotInAdapter(){
           onView(withId(R.id.list))
               .check(matches(not(withAdaptedData(is(withContactItemName("TestName"))))));
       }
      

    And one more suggestion - to avoid writing is(withContactItemName(is("TestName")) add below code to your matcher:

        public static Matcher<Object> withContactItemName(String itemText) {
            checkArgument( itemText != null );
            return withContactItemName(equalTo(itemText));
        }
    

    then you'll have more readable and clear code is(withContactItemName("TestName")