currently to click on menu-item that is sometimes on some devices in the overflow-menu I am doing the following:
fun invokeMenu(@IdRes menuId: Int, @StringRes menuStringRes: Int) {
try {
onView(withId(menuId)).perform(click())
} catch (nmv: NoMatchingViewException) {
openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getInstrumentation().targetContext)
onView(withText(menuStringRes)).perform(click())
}
}
But I am searching for a better approach - ideally something where I just have to know the menu-id. How do you do this in your espresso tests?
Unfortunately, your ideal case cannot be acomplished. This is due to the construction of support libraries.
Let's start from PopupMenu
, which has a reference to MenuPopupHelper
, which has reference to MenuPopup
. This is an abstract class extended ie. by StandardMenuPopup
. It has reference to MenuAdapter
. If you look into the line 92 of MenuAdapter
you will see, the line:
itemView.initialize(getItem(position), 0);
This is the key method invocation. It can be invoked either in ActionMenuItemView
or ListMenuItemView
. Their implementations differ in the case, that id is attached to ActionMenuItemView, and is not attached to ListMenuItemView
Moreover, MenuAdapter.getItemId(int position)
returns just position
. The id of menu item is lost in overflow menu.
Hovewer, your code can be simplified to one liner. Define a function:
public static Matcher<View> withMenuIdOrText(@IdRes int id, @StringRes int menuText) {
Matcher<View> matcher = withId(id);
try {
onView(matcher).check(matches(isDisplayed()));
return matcher;
} catch (Exception NoMatchingViewException) {
openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getInstrumentation().getTargetContext());
return withText(menuText);
}
}
Usage:
onView(withMenuIdOrText(R.id.menu_id, R.string.menu_text)).perform(click());