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