5

I have an Android App with a login screen, which also contains a forgot password button that brings you to a website for further assistance. I'm testing it using Spoon and Espresso, with the following simple test function:

@Test
public void testForgotPassword()
{
    onView(withId(R.id.login_forgot_password)).perform(click());

    intended(allOf(
            hasAction(Intent.ACTION_VIEW),
            hasData(BuildConfig.FORGOT_PW_URL)));
}

This test passes fine, and shows the "Complete action using browser/chrome dialog" on the screen, which is the correct behaviour for this device. All good so far. However, as long as that dialog remains there, any subsequent test fails to open the app, returning an exception after a long pause and failing the test.

How can I update the test to actively get rid of the dialog, or otherwise make sure I can continue with the remainder of my unit tests?

The full exception for your reference:

2016-04-21 17:37:04 [STRL.testFailed] failed java.lang.RuntimeException: Could not launch intent Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=nl.test.example/.ui.activity.login.LoginActivity_ } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1461252979050 and now the last time the queue went idle was: 1461252979050. If these numbers are the same your activity might be hogging the event queue.
  at android.support.test.runner.MonitoringInstrumentation.startActivitySync(MonitoringInstrumentation.java:360)
  at android.support.test.rule.ActivityTestRule.launchActivity(ActivityTestRule.java:219)
  at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:268)
  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.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 android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1667)
Combuster
  • 583
  • 5
  • 19

1 Answers1

12

You have to stub all external intents to be able to proceed with your test cases. Put this peace of code in your test class:

@Before
public void stubAllExternalIntents() {
    // By default Espresso Intents does not stub any Intents. Stubbing needs to be setup before
    // every test run. In this case all external Intents will be blocked.
    intending(not(isInternal())).respondWith(new ActivityResult(Activity.RESULT_OK, null));
}

More here - IntentsBasicSample.

denys
  • 6,834
  • 3
  • 37
  • 36
  • That snippet also broke every other test case that involved navigation within the app. However, thanks to the pointer I ended up modifying it to use intending(hasAction(Intent.ACTION_VIEW)) instead, which works for me. – Combuster Apr 22 '16 at 08:10
  • You absolute life saver!, jeez that is deep in the examples haha – Joe Maher Mar 30 '17 at 06:23
  • This should be marked as the answer! Worked like a charm- thanks. – Axe Jul 27 '19 at 00:31
  • Thanks for this answer. It saved my life. However, putting this in `@Before` was causing my tests to crash. I just need to put the `intending` block in the particular test which was launching the Intent chooser. I have to put it just before the action which will launch the Intent Chooser. – Abhishek Aug 11 '20 at 15:42