1 /*
2  * Copyright (C) 2016 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 
17 package com.android.documentsui.bots;
18 
19 import static androidx.test.espresso.Espresso.onView;
20 import static androidx.test.espresso.action.ViewActions.typeText;
21 import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
22 import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
23 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
24 import static androidx.test.espresso.matcher.ViewMatchers.withId;
25 
26 import static junit.framework.Assert.assertEquals;
27 import static junit.framework.Assert.assertFalse;
28 import static junit.framework.Assert.assertTrue;
29 
30 import static org.hamcrest.CoreMatchers.allOf;
31 import static org.hamcrest.CoreMatchers.anyOf;
32 
33 import android.content.Context;
34 import android.support.test.uiautomator.UiDevice;
35 import android.support.test.uiautomator.UiObject;
36 import android.support.test.uiautomator.UiObjectNotFoundException;
37 import android.view.View;
38 
39 import androidx.recyclerview.R;
40 
41 import org.hamcrest.Matcher;
42 
43 /**
44  * A test helper class that provides support for controlling the search UI
45  * programmatically, and making assertions against the state of the UI.
46  * <p>
47  * Support for working directly with Roots and Directory view can be found in the respective bots.
48  */
49 public class SearchBot extends Bots.BaseBot {
50 
51     // Dumb search layout changes substantially between Ryu and Angler.
52     @SuppressWarnings("unchecked")
53     private static final Matcher<View> SEARCH_WIDGET = allOf(
54             withId(R.id.option_menu_search),
55             anyOf(isClickable(), hasDescendant(isClickable())));
56 
57     // Note that input is visible when the clicky button is not
58     // present. So to clearly qualify the two...we explicitly
59     // require this input be not clickable.
60     @SuppressWarnings("unchecked")
61     private static final Matcher<View> SEARCH_INPUT = allOf(
62             withId(R.id.search_src_text),
63             isDisplayed());
64 
SearchBot(UiDevice device, Context context, int timeout)65     public SearchBot(UiDevice device, Context context, int timeout) {
66         super(device, context, timeout);
67     }
68 
clickIcon()69     public void clickIcon() throws UiObjectNotFoundException {
70         UiObject searchView = findSearchView();
71         searchView.click();
72 
73         UiObject fragmentSearchView = findFragmentSearchView();
74         assertTrue(fragmentSearchView.exists());
75     }
76 
clickSearchViewClearButton()77     public void clickSearchViewClearButton() throws UiObjectNotFoundException {
78         UiObject clear = findSearchViewClearButton();
79         clear.click();
80     }
81 
clickFragmentSearchViewClearButton()82     public void clickFragmentSearchViewClearButton() throws UiObjectNotFoundException {
83         UiObject clear = findFragmentSearchClearButton();
84         clear.click();
85     }
86 
setInputText(String query)87     public void setInputText(String query) throws UiObjectNotFoundException {
88         onView(SEARCH_INPUT).perform(typeText(query));
89     }
90 
assertIconVisible(boolean visible)91     public void assertIconVisible(boolean visible) {
92         if (visible) {
93             assertTrue(
94                     "Search icon should be visible.",
95                     Matchers.present(SEARCH_WIDGET));
96         } else {
97             assertFalse(
98                     "Search icon should not be visible.",
99                     Matchers.present(SEARCH_WIDGET));
100         }
101     }
102 
assertInputEquals(String query)103     public void assertInputEquals(String query)
104             throws UiObjectNotFoundException {
105         UiObject textField = findSearchViewTextField();
106 
107         assertTrue(textField.exists());
108         assertEquals(query, textField.getText());
109     }
110 
assertInputFocused(boolean focused)111     public void assertInputFocused(boolean focused)
112             throws UiObjectNotFoundException {
113         UiObject textField = findSearchViewTextField();
114 
115         assertTrue(textField.exists());
116         assertEquals(focused, textField.isFocused());
117     }
118 
assertInputExists(boolean exists)119     public void assertInputExists(boolean exists)
120             throws UiObjectNotFoundException {
121         assertEquals(exists, findSearchViewTextField().exists());
122     }
123 
assertFragmentInputFocused(boolean focused)124     public void assertFragmentInputFocused(boolean focused)
125             throws UiObjectNotFoundException {
126         UiObject textField = findFragmentSearchViewTextField();
127 
128         assertTrue(textField.exists());
129         assertEquals(focused, textField.isFocused());
130     }
131 
assertFragmentInputExists(boolean exists)132     public void assertFragmentInputExists(boolean exists)
133             throws UiObjectNotFoundException {
134         assertEquals(exists, findFragmentSearchViewTextField().exists());
135     }
136 
findSearchView()137     private UiObject findSearchView() {
138         return findObject(mTargetPackage + ":id/option_menu_search");
139     }
140 
findSearchViewTextField()141     private UiObject findSearchViewTextField() {
142         return findObject(mTargetPackage + ":id/option_menu_search",
143                 mTargetPackage + ":id/search_src_text");
144     }
145 
findSearchViewClearButton()146     private UiObject findSearchViewClearButton() {
147         return findObject(mTargetPackage + ":id/option_menu_search",
148                 mTargetPackage + ":id/search_close_btn");
149     }
150 
findFragmentSearchView()151     private UiObject findFragmentSearchView() {
152         return findObject(mTargetPackage + ":id/search_view");
153     }
154 
findFragmentSearchViewTextField()155     private UiObject findFragmentSearchViewTextField() {
156         return findObject(mTargetPackage + ":id/search_view",
157                 mTargetPackage + ":id/search_src_text");
158     }
159 
findFragmentSearchClearButton()160     private UiObject findFragmentSearchClearButton() {
161         return findObject(mTargetPackage + ":id/search_view",
162                 mTargetPackage + ":id/search_close_btn");
163     }
164 
findSearchViewIcon()165     private UiObject findSearchViewIcon() {
166         return mContext.getResources().getBoolean(R.bool.full_bar_search_view)
167                 ? findObject(mTargetPackage + ":id/option_menu_search")
168                 : findObject(mTargetPackage + ":id/option_menu_search",
169                         "android:id/search_button");
170     }
171 }
172