8

How can I assert a dialog is not shown?

At the moment I have a test which checks if text does not exist in a dialog where a dialog doesn't show

onView(withText("Mobile connection")).inRoot(isDialog()).check(doesNotExist());

But I get a NoMatchingRootException

android.support.test.espresso.NoMatchingRootException: Matcher 'is dialog' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W@9acefba, window-token=android.view.ViewRootImpl$W@9acefba, has-window-focus=true, layout-params-type=1, layout-params-string=WM.LayoutParams{(0,0)(fillxfill) ty=1 fl=#81810100 wanim=0x1030465 needsMenuKey=2}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=768, height=1280, 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=5}}]
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:1566)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:92)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:56)
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
at android.support.test.espresso.ViewInteraction.check(ViewInteraction.java:158)
at uk.co.imagitech.learn2.hp.MainActivityConnectedTest.doesntShowMeteredDialogAtStart(MainActivityConnectedTest.java:43)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:270)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at uk.co.imagitech.learn2.hp.TestButlerAndroidRunner.onStart(TestButlerAndroidRunner.java:17)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1932)
Tim Kist
  • 1,164
  • 1
  • 14
  • 38

3 Answers3

1

What is suggested by piotrek did not work for me. The same NoMatchingRootException was always throwing from Espresso.

What worked was this:

onView(withText("DIALOG_MESSAGE")).check(doesNotExist())

A Roboelectric test code:

  @Test
  fun canShowBlockingDialog() {
    val scenario = launchActivity<FragmentScenario.EmptyFragmentActivity>()
    scenario.onActivity {
      //I need to set a support Theme otherwise we can't create MaterialAlertDialogs
      it.setTheme(R.style.AppTheme_NoActionBar)
      //this method is an extension function which shows a MaterialAlertDialog 
      //with an OK button
      it.showBlockingDialog("DIALOG_MESSAGE", "DIALOG_TITLE")
      onView(withText("DIALOG_MESSAGE")).inRoot(isDialog()).check(matches(isDisplayed()))
      onView(withText("DIALOG_TITLE")).inRoot(isDialog()).check(matches(isDisplayed()))
      onView(withText("OK")).inRoot(isDialog()).check(matches(isDisplayed()))
      //press the OK button to close the dialog     
    onView(withText("OK")).inRoot(isDialog()).perform(scrollTo()).perform(click())
      //check that DIALOG_MESSAGE is not on screen anymore
      onView(withText("DIALOG_MESSAGE")).check(doesNotExist())
    }
    scenario.close()
  }
MatPag
  • 41,742
  • 14
  • 105
  • 114
  • Can you have a look at my question. I have a very similar setup to your answer but I'm not sure what I'm doing wrong. https://stackoverflow.com/questions/67412611/how-to-run-a-unit-test-on-a-dialog-fragment – Shawn May 07 '21 at 03:54
  • I found that this line of code passes even if the root (in this case a dialog, but could be anything like an autocomplete dropdown etc) is displayed. It doesn't seem to match against the element if `inRoot` is not present. for me, in the end I ended up running the check in a try-catch and failing the test if the exception was not thrown. Horrible I know but I could not find anything else that worked. (Basically, `inRoot` is not compatible with `doesNotExist`, which is really annoying.) – Adam Burley Sep 29 '22 at 10:07
0

You cannot check if dialog's text is displayed until it is shown.

onView(withText("Mobile connection")).inRoot(isDialog()) .check(doesNotExist());

As you may know this code checks if Dialog has a view with text displayed on it, but as there's no dialog you cannot finish this part of test. It's saying: "There's no root, no Dialog, how I can achieve this?"

Don't check view's attributes until it would be loaded.

Tim Kist
  • 1,164
  • 1
  • 14
  • 38
piotrek1543
  • 19,130
  • 7
  • 81
  • 94
  • 1
    This does not answer the question, OP is expecting the dialog to NOT be shown, so there is no waiting until it's loaded. – Adam Burley Sep 29 '22 at 10:10
0

My eventual solution:

    // This is necessary because inRoot is not compatible with doesNotExist
    public static boolean doesRootExist(Matcher<Root> rootMatcher) {
        try {
            onView(any(View.class)).inRoot(rootMatcher).check(matches(anything()));
            return true;
        } catch (NoMatchingRootException ex) {
            return false;
        } catch (AmbiguousViewMatcherException ex) {
            return true;
        }
    }

And called like: assertFalse(doesRootExist(RootMatchers.isDialog)).

It's a really horrible solution as it causes the thread to block for about 60 seconds while waiting for the root to appear, but in the end it's the only thing which worked for me.

Adam Burley
  • 5,551
  • 4
  • 51
  • 72