Android Expresso проверяет контекстное меню и элементы actionBar
У меня есть список, где каждая строка содержит имя и кнопку, которая вызывает контекстное меню параметров. Я хотел бы написать тест, который проверяет следующие вещи
- контекстное меню содержит правильное количество пунктов
- контекстное меню содержит правильные значения
- контекстное меню не содержит никаких необоснованных опций (проверки 1 и 2 выше проверят этот случай)
Я также хотел бы проверить содержимое меню переполнения actionBar и actionBar, когда элемент долго выбран.
Для обоих тестов я могу написать проверку, которая гарантирует, что есть элемент представления с отображенной правильной "меткой" (то есть, находим представление, используя onView(withText(this.elementText)). Однако у меня есть 2 действия, которые имеют одинаковую метку разные идентификаторы, и я должен убедиться, что правильное действие находится в контекстном меню / меню длинного щелчка.
Я не могу использовать идентификатор, указанный в XML, для меню моего контекстного меню, поскольку представления контекстного меню Android не имеют этих идентификаторов, вместо этого они содержат внутренний идентификатор Android (см. Скриншот ниже).
Когда я писал тесты с использованием Robotium, мне нужно было получить все текущие представления определенного типа и проанализировать их, проверяя, являются ли они элементами actionBar, см. Пример кода ниже.
public static List<MenuItemImpl> getLongClickMenuItems(String itemName) {
List<MenuItemImpl> menuItems = new ArrayList<>();
// long select the item
solo.clickLongOnText(itemName);
// get the children of the of the long click action bar
ArrayList<ActionMenuView> outViews = solo.getCurrentViews(ActionMenuView.class, solo.getView(R.id.action_mode_bar));
if (!outViews.isEmpty()) {
// get the first child which contains the action bar actions
ActionMenuView actionMenuView = outViews.get(0);
// loop over the children of the ActionMenuView which is the individual ActionMenuItemViews
// only a few fit will fit on the actionBar, others will be in the overflow menu
int count = actionMenuView.getChildCount();
for (int i = 0; i < count; i++) {
View child = actionMenuView.getChildAt(i);
if (child instanceof ActionMenuItemView) {
menuItems.add(((ActionMenuItemView) child).getItemData());
} else {
// this is the more button, click on it and wait for the popup window
// which will contain a list of ListMenuItemView
// As we are using the AppCompat the actionBar's menu items are the
// the AppCompat's ListMenuItemView (android.support.v7.view.menu.ListMenuItemView)
// In the context menu, the menu items are Android's native ListMenuItemView
// (com.android.internal.view.menu.ListMenuItemView)
solo.clickOnView(child);
solo.waitForView(ListMenuItemView.class);
ArrayList<ListMenuItemView> popupItems = solo.getCurrentViews(ListMenuItemView.class);
for (ListMenuItemView lvItem : popupItems) {
menuItems.add(lvItem.getItemData());
}
// close the more button actions menu
solo.goBack();
}
}
}
// get out of long click mode
solo.goBack();
return menuItems;
}
Кто-нибудь знает, как я могу получить список пунктов меню Context Row с помощью Expresso.
Кто-нибудь знает, как я могу получить элементы actionBar (включая все элементы в меню переполнения) с помощью Expresso?
2 ответа
Большое спасибо dominicoder за то, что он дал мне ответ на этот вопрос. работая над их ответом, мне удалось заставить его работать.
Вместо использования "isAssignableFrom(AdapterView.class)" я использую "isAssignableFrom(ListView.class)".
Затем я использую то же самое соответствие "dominicoder", чтобы проверить количество пунктов контекстного меню.
Используя примеры соответствия "dominicoder", я смог сам написать код, который проверяет MenuItem в определенной позиции в ListView, и я могу сравнить идентификаторы, чтобы убедиться, что это ожидаемый идентификатор.
public boolean verifyRowContextMenuContents(String name, MyActionObject[] actions){
// invoke the row context menu
clickRowActionButton(name);
// The Context Menu Popup contains a ListView
int expectedItemCount = actions.length;
// first check the Popup's listView contains the correct number of items
onView(isAssignableFrom(ListView.class))
.check(matches(correctNumberOfItems(expectedItemCount)));
// now check the order and the IDs of each action in the menu is the expected action
for (int i = 0; i < expectedItemCount; i++) {
onView(isAssignableFrom(ListView.class))
.check(matches(correctMenuId(i, actions[i].getId())));
}
// close the context menu
pressBack();
return true;
}
private static Matcher<View> correctNumberOfItems(final int itemsCount) {
return new BoundedMatcher<View, ListView>(ListView.class) {
@Override
public void describeTo(Description description) {
description.appendText("with number of items: " + itemsCount);
}
@Override
protected boolean matchesSafely(ListView listView) {
ListAdapter adapter = listView.getAdapter();
return adapter.getCount() == itemsCount;
}
};
}
private static Matcher<View> correctMenuId(final int position, final int expectedId) {
return new BoundedMatcher<View, ListView>(ListView.class) {
@Override
public void describeTo(Description description) {
description.appendText("with position : " + position + " expecting id: " + expectedId);
}
@Override
protected boolean matchesSafely(ListView listView) {
ListAdapter adapter = listView.getAdapter();
Object obj = adapter.getItem(position);
if (obj instanceof MenuItem){
MenuItem menuItem = (MenuItem)obj;
return menuItem.getItemId() == expectedId;
}
return false;
}
};
}
С помощью этого кода я могу проверить, что Контекстное меню содержит правильное количество пунктов меню, и что пункты в меню - это те, которые я ожидаю (с помощью проверки идентификатора), и порядок, который я ожидаю.
Огромное спасибо "Доминикодеру". Жаль, что вы не можете пометить оба ответа как правильные, поскольку вы фактически дали мне практически правильный ответ.
Если я правильно понимаю ваш вопрос, вы сможете использовать метод onData() для взаимодействия с контекстными меню, поскольку они просто AdapterViews
(обратите внимание на скриншот, всплывающее окно ListPopupWindow$DropDownListView
).
Таким образом, вы должны быть в состоянии сделать что-то вроде этого:
onView(withText("Item Label")).perform(longClick());
final int expectedItemCount = 10;
// Now the floating popup should be showing,
// first assert it has the expected item count
onView(isAssignableFrom(AdapterView.class))
.check(matches(withItemCount(expectedItemCount)));
// Now assert each entry (which should just be a string) is shown correctly
for (int i = 0; i < expectedItemCount; i++) {
String expectedItemText = getExpectedItemTextForIndex(i);
onData(instanceOf(String.class)).atPosition(i)
.check(matches(withText(expectedItemText)));
}
Где withItemCount
Приведенное выше совпадение - это простое сопоставление, которое утверждается в зависимости от количества адаптеров данного представления адаптера:
public static Matcher<View> withNumberOfItems(final int itemsCount) {
return new BoundedMatcher<View, AdapterView>(AdapterView.class) {
@Override
public void describeTo(Description description) {
description.appendText("with number of items: " + itemsCount);
}
@Override
protected boolean matchesSafely(AdapterView item) {
return item.getAdapter().getCount() == itemsCount;
}
};
}
Я думаю, что та же самая концепция должна работать для меню переполнения панели действий.
Мне не понятно, что вы имеете в виду под:
Для обоих тестов я могу написать проверку, которая гарантирует, что есть элемент представления с отображенной правильной "меткой" (то есть, находим представление, используя onView(withText(this.elementText)). Однако у меня есть 2 действия, которые имеют одинаковую метку, но разные идентификаторы, и я должен убедиться, что правильное действие находится в контекстном меню / меню длинного щелчка.
Но atPosition
должен получить именно тот вид, который вас интересует в списке, и вы можете добавить onChildView
если вам нужно настроить таргетинг как на подэлемент внутри данного элемента в списке.
Надеюсь, это поможет!