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.view.View; 35 36 import androidx.test.uiautomator.UiDevice; 37 import androidx.test.uiautomator.UiObject; 38 import androidx.test.uiautomator.UiObjectNotFoundException; 39 import androidx.test.uiautomator.UiSelector; 40 41 import com.android.documentsui.R; 42 43 import org.hamcrest.Matcher; 44 45 /** 46 * A test helper class that provides support for controlling the search UI 47 * programmatically, and making assertions against the state of the UI. 48 * <p> 49 * Support for working directly with Roots and Directory view can be found in the respective bots. 50 */ 51 public class SearchBot extends Bots.BaseBot { 52 53 // Base search layout changes substantially between Ryu and Angler. 54 @SuppressWarnings("unchecked") 55 private static final Matcher<View> SEARCH_WIDGET = allOf( 56 withId(R.id.option_menu_search), 57 anyOf(isClickable(), hasDescendant(isClickable()))); 58 59 // Note that input is visible when the clicky button is not 60 // present. So to clearly qualify the two...we explicitly 61 // require this input be not clickable. 62 @SuppressWarnings("unchecked") 63 private static final Matcher<View> SEARCH_INPUT = allOf( 64 withId(androidx.appcompat.R.id.search_src_text), 65 isDisplayed()); 66 SearchBot(UiDevice device, Context context, int timeout)67 public SearchBot(UiDevice device, Context context, int timeout) { 68 super(device, context, timeout); 69 } 70 clickIcon()71 public void clickIcon() throws UiObjectNotFoundException { 72 UiObject searchView = findSearchView(); 73 searchView.click(); 74 } 75 clickSearchViewClearButton()76 public void clickSearchViewClearButton() throws UiObjectNotFoundException { 77 UiObject clear = findSearchViewClearButton(); 78 clear.click(); 79 } 80 81 // Click on the search history item with specified queryText, if exists. clickSearchHistory(String queryText)82 public void clickSearchHistory(String queryText) throws UiObjectNotFoundException { 83 UiObject history = findSearchHistoryView(); 84 UiSelector historyItemSelector = new UiSelector().text(queryText); 85 mDevice.findObject(history.getSelector().childSelector(historyItemSelector)).click(); 86 } 87 setInputText(String query)88 public void setInputText(String query) throws UiObjectNotFoundException { 89 onView(SEARCH_INPUT).perform(typeText(query)); 90 } 91 assertIconVisible(boolean visible)92 public void assertIconVisible(boolean visible) { 93 if (visible) { 94 assertTrue( 95 "Search icon should be visible.", 96 Matchers.present(SEARCH_WIDGET)); 97 } else { 98 assertFalse( 99 "Search icon should not be visible.", 100 Matchers.present(SEARCH_WIDGET)); 101 } 102 } 103 assertSearchHistoryVisible(boolean visible)104 public void assertSearchHistoryVisible(boolean visible) { 105 if (visible) { 106 assertTrue( 107 "Search fragment should be shown.", 108 findSearchHistoryView().exists()); 109 } else { 110 assertFalse( 111 "Search fragment should be dismissed.", 112 findSearchHistoryView().exists()); 113 } 114 } 115 assertInputEquals(String query)116 public void assertInputEquals(String query) 117 throws UiObjectNotFoundException { 118 UiObject textField = findSearchViewTextField(); 119 120 assertTrue(textField.exists()); 121 assertEquals(query, textField.getText()); 122 } 123 assertInputFocused(boolean focused)124 public void assertInputFocused(boolean focused) 125 throws UiObjectNotFoundException { 126 UiObject textField = findSearchViewTextField(); 127 128 assertTrue(textField.exists()); 129 assertEquals(focused, textField.isFocused()); 130 } 131 assertInputExists(boolean exists)132 public void assertInputExists(boolean exists) 133 throws UiObjectNotFoundException { 134 assertEquals(exists, findSearchViewTextField().exists()); 135 } 136 findSearchView()137 private UiObject findSearchView() { 138 return findObject(mTargetPackage + ":id/option_menu_search"); 139 } 140 findSearchHistoryView()141 private UiObject findSearchHistoryView() { 142 return findObject(mTargetPackage + ":id/history_list"); 143 } 144 findSearchViewTextField()145 private UiObject findSearchViewTextField() { 146 return findObject(mTargetPackage + ":id/option_menu_search", 147 mTargetPackage + ":id/search_src_text"); 148 } 149 findSearchViewClearButton()150 private UiObject findSearchViewClearButton() { 151 return findObject(mTargetPackage + ":id/option_menu_search", 152 mTargetPackage + ":id/search_close_btn"); 153 } 154 findSearchViewIcon()155 private UiObject findSearchViewIcon() { 156 return mContext.getResources().getBoolean(R.bool.full_bar_search_view) 157 ? findObject(mTargetPackage + ":id/option_menu_search") 158 : findObject(mTargetPackage + ":id/option_menu_search", 159 "android:id/search_button"); 160 } 161 } 162