1

I'm starting out with Espresso and I've got a custom Toast that I show when the user puts in something wrong (I know I can use EditText.setError(), but that's just how it is).

Here's the code for the Toast

private static void showToast(Context context, String message, boolean isError) {
    if (context != null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        TextView toastView = (TextView) inflater.inflate(R.layout.error_toast_layout, null);
        if (!isError) {
            toastView.setBackgroundColor(context.getResources().getColor(R.color.alert_positive));
        }
        toastView.setText(message);
        Toast errorToast = new Toast(context);
        errorToast.setGravity(Gravity.TOP, 0, 0);
        errorToast.setDuration(Toast.LENGTH_SHORT);
        errorToast.setView(toastView);
        errorToast.show();
    }
}

and I am writing up a little UI test that will assert that correct Toasts are being shown when the user puts in wrong input

Here's the test

@RunWith(AndroidJUnit4.class)
@LargeTest
public class ForgotPasswordTest extends BaseEspressoTest<ForgotPasswordActivity> {

    @Test
    public void testEmailNotEntered() {
        onView(withId(R.id.email_et)).perform(typeText("w"), closeSoftKeyboard());
        onView(withId(R.id.btn_submit)).perform(click());
        onView(withText(R.string.incorrect_email_dialog)).inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView()))).check(matches(isDisplayed()));     
    }
}

this works fine if I substitute my custom Toast for a regular Toast, but fails when I try it with mine. I can see that the Toast is being shown during the test.

Here's the error:

android.support.test.espresso.NoMatchingRootException: Matcher 'with decor view not <com.android.internal.policy.impl.PhoneWindow$DecorView{3852d97 V.ED.... R....... 0,0-1080,1920}>' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W@2d629b84, window-token=android.view.ViewRootImpl$W@2d629b84, has-window-focus=true, layout-params-type=1, layout-params-string=WM.LayoutParams{(0,0)(fillxfill) sim=#22 ty=1 fl=#8d810100 pfl=0x8 wanim=0x1030461 surfaceInsets=Rect(0, 0 - 0, 0)}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}]

I've also tried to match the the Toast based on the fact that it's supposed to focus:

onView(withText(R.string.incorrect_email_dialog))
    .inRoot(isFocusable()).check(matches(isDisplayed()));

but that just says that it can't find it within the view hierarchy:

No views in hierarchy found matching: with string from resource id: <2131165635>[incorrect_email_dialog] value: Please enter a valid email

nsmirosh
  • 45
  • 2
  • 8

1 Answers1

3

You can try with CustomToastMatcher given below:

import android.os.IBinder;
import android.support.test.espresso.Root;
import android.view.WindowManager;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

    public class ToastMatcher extends TypeSafeMatcher<Root> {

        @Override    public void describeTo(Description description) {
            description.appendText("is toast");
        }

        @Override    public boolean matchesSafely(Root root) {
            int type = root.getWindowLayoutParams().get().type;
            if ((type == WindowManager.LayoutParams.TYPE_TOAST)) {
                IBinder windowToken = root.getDecorView().getWindowToken();
                IBinder appToken = root.getDecorView().getApplicationWindowToken();
                if (windowToken == appToken) {
                  //means this window isn't contained by any other windows. 
                }
            }
            return false;
        }
    }

Use it in test case like this:

onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
    .check(matches(isDisplayed()));

Other References: https://stackoverflow.com/a/33387980/2069407 http://baroqueworksdev.blogspot.de/2015/03/how-to-check-toast-window-on-android.html

s-hunter
  • 24,172
  • 16
  • 88
  • 130
anuja jain
  • 1,367
  • 13
  • 19