Espresso openActionBarOverflowOrOptionsMenu causes NoMatchingViewException

Issue

I have just started experimenting with the Espresso testing framework for Android and the first thing I wanted to do was click the “Settings” button in an activity’s options menu. However, when I try to call openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext()) the test crashes with this exception

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: ((is displayed on the screen to the user and with content description: is "More options") or (is displayed on the screen to the user and with class name: a string ending with "OverflowMenuButton"))

View Hierarchy:
+>DecorView{id-1, visibilityVISIBLE, width800, height1232, has-focustrue, has-focusabletrue, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0, child-count1}
|
+->LinearLayout{id-1, visibilityVISIBLE, width800, height1232, has-focustrue, has-focusabletrue, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0, child-count2}
|
+-->ViewStub{id16909074, visibilityGONE, width0, height0, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedtrue, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0}
|
+-->FrameLayout{id16908290, res-namecontent, visibilityVISIBLE, width800, height1207, has-focustrue, has-focusabletrue, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y25.0, child-count1}
|
+--->RelativeLayout{id-1, visibilityVISIBLE, width800, height1207, has-focustrue, has-focusabletrue, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0, child-count9}
|
+---->ImageView{id2131361813, res-namemain_logo, desclogo, visibilityVISIBLE, width768, height158, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x16.0, y36.0}
|
+---->Button{id2131361814, res-namemain_new_button, visibilityINVISIBLE, width210, height48, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickabletrue, is-enabledtrue, is-focusedfalse, is-focusabletrue, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x295.0, y232.0, textNew forest, input-type0, ime-targetfalse, has-linksfalse}
|
+---->Button{id2131361815, res-namemain_load_button, visibilityVISIBLE, width210, height48, has-focustrue, has-focusabletrue, has-window-focustrue, is-clickabletrue, is-enabledtrue, is-focusedtrue, is-focusabletrue, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x295.0, y310.0, textLoad forest, input-type0, ime-targettrue, has-linksfalse}
|
+---->Button{id2131361816, res-namesatform_download_button, visibilityVISIBLE, width210, height48, has-focusfalse, has-focusabletrue, has-window-focustrue, is-clickabletrue, is-enabledtrue, is-focusedfalse, is-focusabletrue, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x295.0, y388.0, textDownload, input-type0, ime-targetfalse, has-linksfalse}
|
+---->Button{id2131361817, res-namemain_resume_button, visibilityGONE, width0, height0, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickabletrue, is-enabledtrue, is-focusedfalse, is-focusabletrue, is-layout-requestedtrue, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0, textContinue, input-type0, ime-targetfalse, has-linksfalse}
|
+---->ToggleButton{id2131361818, res-namemarking_mode_toggle, visibilityVISIBLE, width223, height48, has-focusfalse, has-focusabletrue, has-window-focustrue, is-clickabletrue, is-enabledtrue, is-focusedfalse, is-focusabletrue, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x288.0, y466.0, textAuto Marking RFID mode, input-type0, ime-targetfalse, has-linksfalse, is-checkedfalse}
|
+---->ProgressBar{id2131361819, res-nameprogress_bar, visibilityGONE, width0, height0, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedtrue, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0}
|
+---->TextView{id2131361820, res-nameprogress_text, visibilityGONE, width0, height0, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickablefalse, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedtrue, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x0.0, y0.0, textPlease wait…, input-type0, ime-targetfalse, has-linksfalse}
|
+---->TextView{id2131361821, res-nameversion_text, visibilityVISIBLE, width210, height25, has-focusfalse, has-focusablefalse, has-window-focustrue, is-clickabletrue, is-enabledtrue, is-focusedfalse, is-focusablefalse, is-layout-requestedfalse, is-selectedfalse, root-is-layout-requestedfalse, has-input-connectionfalse, x295.0, y1128.0, textversion:0.7.0, input-type0, ime-targetfalse, has-linksfalse}
|
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:579)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:82)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:53)
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115)
at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87)
at android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu(Espresso.java:214)
at com.treemetrics.treedegrees.TestBluetoothPeripheralDialog.openOverflowMenu(TestBluetoothPeripheralDialog.java:28)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
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:257)
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:54)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1710)

The options menu is initialised in the activity like this

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.menu_comp_activity, menu);
    this.menu  menu;
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // handle item selection
    switch (item.getItemId()) {
    case R.id.action_rfid:
        toggleRfid(item);
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    MainApplication.debugOut(true, 2, TAG, getString(R.string.called_on_prepare_options_menu));
    if (RfidBtService.isRunning){
        menu.findItem(R.id.action_rfid).setTitle(R.string.action_rfid_off);
        menu.findItem(R.id.action_rfid).setIcon(R.drawable.bt_rfid);
    }else{
        menu.findItem(R.id.action_rfid).setTitle(R.string.action_rfid_on);
        menu.findItem(R.id.action_rfid).setIcon(R.drawable.bt_rfid_on);
    }
    return true;
}

and here is the XML for the menu

<menu xmlns:android"http://schemas.android.com/apk/res/android" >

<item
    android:id"@+id/menuitem_saveforest"
    android:onClick"saveForest"
    android:orderInCategory"100"
    android:showAsAction"never"
    android:title"@string/action_save_forest"/>
<item
    android:id"@+id/action_sendforest"
    android:onClick"sendForest"
    android:orderInCategory"100"
    android:showAsAction"never"
    android:title"@string/action_send_forest"/>
<item
    android:id"@+id/action_settings"
    android:onClick"launchSettings"
    android:orderInCategory"100"
    android:showAsAction"never"
    android:title"@string/action_settings"/>
<item
    android:id"@+id/action_saveforest"
    android:icon"@drawable/ic_menu_save"
    android:onClick"saveForest"
    android:showAsAction"always"
    android:title"@string/action_save_forest"/>
<item
    android:id"@+id/action_rfid"
    android:icon"@drawable/bt_rfid_on"
    android:onClick"toggleRfid"
    android:showAsAction"ifRoom"
    android:title"@string/action_rfid_on"/>

</menu>

Here is my test class

@RunWith(AndroidJUnit4.class)
@SmallTest
public class TestBluetoothPeripheralDialog {

  @Rule
  public ActivityTestRule<ForestActivity> mActivityRule
       new ActivityTestRule<>(ForestActivity.class);

  @Test
  public void openOverflowMenu() {
    // Open the overflow menu OR open the options menu,
    // depending on if the device has a hardware or software overflow menu button.
    openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());

    // Click the item.
    onView(withText("Settings"))
        .perform(click());
  }

}

Solution

I realised my problem. I thought ForestActivity was being launched because it was declared as the generic type in the ActivityTestRule (I still don’t know what ActivityTestRule’s function is, I’ve only just started with Espresso and testing on Android in general). So my problem was I was trying to open the overflow menu in the splash screen at the start of the app, as opposed to the ForestActivity.

Answered By – Moses

Leave a Comment