blob: 02ee9be825be85033f14bc1426bd5f53c8291b57 [file] [log] [blame]
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package android.widget.espresso;
18
19import static android.support.test.espresso.Espresso.onView;
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -080020import static android.support.test.espresso.action.ViewActions.click;
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -080021import static android.support.test.espresso.assertion.ViewAssertions.matches;
22import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
23import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
24import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
25import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
26import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -080027import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -080028import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
29import static android.support.test.espresso.matcher.ViewMatchers.withText;
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -080030
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -080031import static org.hamcrest.Matchers.allOf;
32import static org.hamcrest.Matchers.not;
33
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -080034import android.support.test.espresso.NoMatchingRootException;
35import android.support.test.espresso.NoMatchingViewException;
36import android.support.test.espresso.ViewInteraction;
37import android.support.test.espresso.matcher.ViewMatchers;
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -080038import android.view.View;
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -080039import android.widget.MenuPopupWindow.MenuDropDownListView;
40
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -080041import com.android.internal.view.menu.ListMenuItemView;
42
43import org.hamcrest.Description;
44import org.hamcrest.Matcher;
45import org.hamcrest.TypeSafeMatcher;
46
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -080047/**
48 * Espresso utility methods for the context menu.
49 */
50public final class ContextMenuUtils {
51 private ContextMenuUtils() {}
52
53 private static ViewInteraction onContextMenu() {
54 // TODO: Have more reliable way to get context menu.
55 return onView(ViewMatchers.isAssignableFrom(MenuDropDownListView.class))
56 .inRoot(withDecorView(hasFocus()));
57 }
58
59 /**
60 * Asserts that the context menu is displayed
61 *
62 * @throws AssertionError if the assertion fails
63 */
64 private static void assertContextMenuIsDisplayed() {
65 onContextMenu().check(matches(isDisplayed()));
66 }
67
68 /**
69 * Asserts that the context menu is not displayed
70 *
71 * @throws AssertionError if the assertion fails
72 */
73 public static void assertContextMenuIsNotDisplayed() {
74 try {
75 assertContextMenuIsDisplayed();
76 } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
77 return;
78 }
79 throw new AssertionError("Context menu is displayed");
80 }
81
82 /**
83 * Asserts that the context menu contains the specified item and the item has specified enabled
84 * state.
85 *
86 * @param itemLabel label of the item.
87 * @param enabled enabled state of the item.
88 * @throws AssertionError if the assertion fails
89 */
90 private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
91 boolean enabled) {
92 onContextMenu().check(matches(
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -080093 hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled))));
94 }
95
96 private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) {
97 return allOf(
98 isAssignableFrom(ListMenuItemView.class),
99 hasDescendant(withText(itemLabel)),
100 enabled ? isEnabled() : not(isEnabled()),
101 isDisplayingAtLeast(90));
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -0800102 }
103
104 /**
105 * Asserts that the context menu contains the specified item and the item is enabled.
106 *
107 * @param itemLabel label of the item.
108 * @throws AssertionError if the assertion fails
109 */
110 public static void assertContextMenuContainsItemEnabled(String itemLabel) {
111 asssertContextMenuContainsItemWithEnabledState(itemLabel, true);
112 }
113
114 /**
115 * Asserts that the context menu contains the specified item and the item is disabled.
116 *
117 * @param itemLabel label of the item.
118 * @throws AssertionError if the assertion fails
119 */
120 public static void assertContextMenuContainsItemDisabled(String itemLabel) {
121 asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
122 }
Vladislav Kaznacheevd959c9d2018-01-23 14:03:36 -0800123
124 /**
125 * Asserts that the context menu window is aligned to a given view with a given offset.
126 *
127 * @param anchor Anchor view.
128 * @param offsetX x offset
129 * @param offsetY y offset.
130 * @throws AssertionError if the assertion fails
131 */
132 public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) {
133 int [] expectedLocation = new int[2];
134 anchor.getLocationOnScreen(expectedLocation);
135 expectedLocation[0] += offsetX;
136 expectedLocation[1] += offsetY;
137
138 final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
139
140 onContextMenu().check(matches(new TypeSafeMatcher<View>() {
141 @Override
142 public void describeTo(Description description) {
143 description.appendText("root view ");
144 description.appendText(rtl ? "right" : "left");
145 description.appendText("=");
146 description.appendText(Integer.toString(offsetX));
147 description.appendText(", top=");
148 description.appendText(Integer.toString(offsetY));
149 }
150
151 @Override
152 public boolean matchesSafely(View view) {
153 View rootView = view.getRootView();
154 int [] actualLocation = new int[2];
155 rootView.getLocationOnScreen(actualLocation);
156 if (rtl) {
157 actualLocation[0] += rootView.getWidth();
158 }
159 return expectedLocation[0] == actualLocation[0]
160 && expectedLocation[1] == actualLocation[1];
161 }
162 }));
163 }
164
165 /**
166 * Check is the menu item is clickable (i.e. visible and enabled).
167 *
168 * @param itemLabel Label of the item.
169 * @return True if the menu item is clickable.
170 */
171 public static boolean isMenuItemClickable(String itemLabel) {
172 try {
173 onContextMenu().check(matches(
174 hasDescendant(getVisibleMenuItemMatcher(itemLabel, true))));
175 return true;
176 } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
177 return false;
178 }
179 }
180
181 /**
182 * Click on a menu item with the specified label
183 * @param itemLabel Label of the item.
184 */
185 public static void clickMenuItem(String itemLabel) {
186 onView(getVisibleMenuItemMatcher(itemLabel, true))
187 .inRoot(withDecorView(hasFocus())).perform(click());
188 }
Keisuke Kuroyanagia0b3c062015-12-07 11:09:40 -0800189}