productivity_launcher_search_view_unittest.cc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/app_list/views/productivity_launcher_search_view.h"
  5. #include <tuple>
  6. #include <utility>
  7. #include "ash/app_list/app_list_controller_impl.h"
  8. #include "ash/app_list/app_list_model_provider.h"
  9. #include "ash/app_list/model/app_list_test_model.h"
  10. #include "ash/app_list/model/search/test_search_result.h"
  11. #include "ash/app_list/test/app_list_test_helper.h"
  12. #include "ash/app_list/views/app_list_bubble_search_page.h"
  13. #include "ash/app_list/views/result_selection_controller.h"
  14. #include "ash/app_list/views/search_box_view.h"
  15. #include "ash/app_list/views/search_result_list_view.h"
  16. #include "ash/app_list/views/search_result_page_view.h"
  17. #include "ash/constants/ash_features.h"
  18. #include "ash/shell.h"
  19. #include "ash/test/ash_test_base.h"
  20. #include "ash/test/layer_animation_stopped_waiter.h"
  21. #include "base/test/scoped_feature_list.h"
  22. #include "testing/gtest/include/gtest/gtest.h"
  23. #include "ui/accessibility/ax_node_data.h"
  24. #include "ui/compositor/layer.h"
  25. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  26. #include "ui/compositor/test/test_utils.h"
  27. #include "ui/events/keycodes/keyboard_codes_posix.h"
  28. #include "ui/views/controls/button/label_button.h"
  29. #include "ui/views/controls/textfield/textfield.h"
  30. #include "ui/views/test/ax_event_counter.h"
  31. namespace {
  32. int kDefaultSearchItems = 3;
  33. const int kResultContainersCount = static_cast<int>(
  34. ash::SearchResultListView::SearchResultListType::kMaxValue);
  35. } // namespace
  36. namespace ash {
  37. // Parameterized based on whether the search view is shown within the clamshell
  38. // or tablet mode launcher UI.
  39. class ProductivityLauncherSearchViewTest
  40. : public AshTestBase,
  41. public testing::WithParamInterface<bool> {
  42. public:
  43. ProductivityLauncherSearchViewTest()
  44. : AshTestBase((base::test::TaskEnvironment::TimeSource::MOCK_TIME)),
  45. tablet_mode_(GetParam()) {
  46. scoped_feature_list_.InitAndEnableFeature(features::kProductivityLauncher);
  47. }
  48. ProductivityLauncherSearchViewTest(
  49. const ProductivityLauncherSearchViewTest&) = delete;
  50. ProductivityLauncherSearchViewTest& operator=(
  51. const ProductivityLauncherSearchViewTest&) = delete;
  52. ~ProductivityLauncherSearchViewTest() override = default;
  53. void SetUp() override {
  54. AshTestBase::SetUp();
  55. if (tablet_mode_)
  56. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  57. }
  58. void SetUpSearchResults(SearchModel::SearchResults* results,
  59. int init_id,
  60. int new_result_count,
  61. int display_score,
  62. bool best_match,
  63. SearchResult::Category category) {
  64. for (int i = 0; i < new_result_count; ++i) {
  65. std::unique_ptr<TestSearchResult> result =
  66. std::make_unique<TestSearchResult>();
  67. result->set_result_id(base::NumberToString(init_id + i));
  68. result->set_display_type(ash::SearchResultDisplayType::kList);
  69. result->SetTitle(
  70. base::UTF8ToUTF16(base::StringPrintf("Result %d", init_id + i)));
  71. result->set_display_score(display_score);
  72. result->SetDetails(u"Detail");
  73. result->set_best_match(best_match);
  74. result->set_category(category);
  75. results->Add(std::move(result));
  76. }
  77. // Adding results will schedule Update().
  78. base::RunLoop().RunUntilIdle();
  79. }
  80. void SetUpAnswerCardResult(SearchModel::SearchResults* results,
  81. int init_id,
  82. int new_result_count) {
  83. std::unique_ptr<TestSearchResult> result =
  84. std::make_unique<TestSearchResult>();
  85. result->set_result_id(base::NumberToString(init_id));
  86. result->set_display_type(ash::SearchResultDisplayType::kAnswerCard);
  87. result->SetTitle(base::UTF8ToUTF16(base::StringPrintf("Answer Card")));
  88. result->set_display_score(1000);
  89. result->SetDetails(u"Answer Card Details");
  90. result->set_best_match(false);
  91. results->Add(std::move(result));
  92. // Adding results will schedule Update().
  93. base::RunLoop().RunUntilIdle();
  94. }
  95. SearchResultListView::SearchResultListType GetListType(
  96. SearchResultContainerView* result_container_view) {
  97. return static_cast<SearchResultListView*>(result_container_view)
  98. ->list_type_for_test();
  99. }
  100. std::u16string GetListLabel(
  101. SearchResultContainerView* result_container_view) {
  102. return static_cast<SearchResultListView*>(result_container_view)
  103. ->title_label_for_test()
  104. ->GetText();
  105. }
  106. ProductivityLauncherSearchView* GetProductivityLauncherSearchView() {
  107. if (tablet_mode_) {
  108. return GetAppListTestHelper()
  109. ->GetFullscreenSearchResultPageView()
  110. ->productivity_launcher_search_view_for_test();
  111. }
  112. return GetAppListTestHelper()->GetProductivityLauncherSearchView();
  113. }
  114. bool IsSearchResultPageVisible() {
  115. if (tablet_mode_) {
  116. return GetAppListTestHelper()
  117. ->GetFullscreenSearchResultPageView()
  118. ->GetVisible();
  119. }
  120. return GetAppListTestHelper()->GetBubbleSearchPage()->GetVisible();
  121. }
  122. std::vector<size_t> GetVisibleResultContainers() {
  123. std::vector<SearchResultContainerView*> result_containers =
  124. GetProductivityLauncherSearchView()->result_container_views_for_test();
  125. std::vector<size_t> visible_result_containers = {};
  126. for (size_t i = 0; i < result_containers.size(); i++) {
  127. if (result_containers[i]->GetVisible())
  128. visible_result_containers.push_back(i);
  129. }
  130. return visible_result_containers;
  131. }
  132. SearchBoxView* GetSearchBoxView() {
  133. if (tablet_mode_)
  134. return GetAppListTestHelper()->GetSearchBoxView();
  135. return GetAppListTestHelper()->GetBubbleSearchBoxView();
  136. }
  137. private:
  138. const bool tablet_mode_;
  139. base::test::ScopedFeatureList scoped_feature_list_;
  140. };
  141. INSTANTIATE_TEST_SUITE_P(Tablet,
  142. ProductivityLauncherSearchViewTest,
  143. testing::Bool());
  144. TEST_P(ProductivityLauncherSearchViewTest, AnimateSearchResultView) {
  145. // Enable animations.
  146. ui::ScopedAnimationDurationScaleMode duration(
  147. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  148. GetAppListTestHelper()->ShowAppList();
  149. // Press a key to start a search.
  150. PressAndReleaseKey(ui::VKEY_A);
  151. // Populate answer card result.
  152. auto* test_helper = GetAppListTestHelper();
  153. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  154. // Create categorized results and order categories as {kApps, kWeb}.
  155. std::vector<AppListSearchResultCategory>* ordered_categories =
  156. test_helper->GetOrderedResultCategories();
  157. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  158. ordered_categories->push_back(AppListSearchResultCategory::kApps);
  159. ordered_categories->push_back(AppListSearchResultCategory::kWeb);
  160. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, false,
  161. SearchResult::Category::kApps);
  162. SetUpSearchResults(results, 1 + kDefaultSearchItems, kDefaultSearchItems, 1,
  163. false, SearchResult::Category::kWeb);
  164. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  165. // Check result container visibility.
  166. std::vector<SearchResultContainerView*> result_containers =
  167. GetProductivityLauncherSearchView()->result_container_views_for_test();
  168. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  169. EXPECT_TRUE(result_containers[2]->GetVisible());
  170. EXPECT_LT(result_containers[2]->GetResultViewAt(0)->layer()->opacity(), 1.0f);
  171. EXPECT_TRUE(result_containers[3]->GetVisible());
  172. EXPECT_LT(result_containers[3]->GetResultViewAt(0)->layer()->opacity(), 1.0f);
  173. LayerAnimationStoppedWaiter().Wait(
  174. result_containers[2]->GetResultViewAt(0)->layer());
  175. LayerAnimationStoppedWaiter().Wait(
  176. result_containers[3]->GetResultViewAt(0)->layer());
  177. EXPECT_EQ(result_containers[3]->GetResultViewAt(0)->layer()->opacity(), 1.0f);
  178. EXPECT_EQ(result_containers[3]->GetResultViewAt(0)->layer()->opacity(), 1.0f);
  179. }
  180. TEST_P(ProductivityLauncherSearchViewTest, ResultContainerIsVisible) {
  181. GetAppListTestHelper()->ShowAppList();
  182. // Press a key to start a search.
  183. PressAndReleaseKey(ui::VKEY_A);
  184. // Populate answer card result.
  185. auto* test_helper = GetAppListTestHelper();
  186. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  187. SetUpAnswerCardResult(results, 1, 1);
  188. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  189. // Check result container visibility.
  190. std::vector<SearchResultContainerView*> result_containers =
  191. GetProductivityLauncherSearchView()->result_container_views_for_test();
  192. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  193. EXPECT_TRUE(result_containers[0]->GetVisible());
  194. }
  195. TEST_P(ProductivityLauncherSearchViewTest,
  196. SearchResultsAreVisibleDuringHidePageAnimation) {
  197. auto* helper = GetAppListTestHelper();
  198. helper->ShowAppList();
  199. // Press a key to start a search.
  200. PressAndReleaseKey(ui::VKEY_A);
  201. // Populate answer card result.
  202. auto* results = helper->GetSearchResults();
  203. SetUpAnswerCardResult(results, 1, 1);
  204. auto* search_view = GetProductivityLauncherSearchView();
  205. search_view->OnSearchResultContainerResultsChanged();
  206. // Enable animations.
  207. ui::ScopedAnimationDurationScaleMode duration(
  208. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  209. // Press backspace to delete the query and switch back to the apps page.
  210. PressAndReleaseKey(ui::VKEY_BACK);
  211. search_view->OnSearchResultContainerResultsChanged();
  212. // Result is visible during hide animation.
  213. std::vector<SearchResultContainerView*> result_containers =
  214. search_view->result_container_views_for_test();
  215. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  216. EXPECT_TRUE(result_containers[0]->GetVisible());
  217. EXPECT_TRUE(result_containers[0]->GetResultViewAt(0)->GetVisible());
  218. }
  219. // Tests that key traversal correctly cycles between the list of results and
  220. // search box close button.
  221. TEST_P(ProductivityLauncherSearchViewTest, ResultSelectionCycle) {
  222. auto* test_helper = GetAppListTestHelper();
  223. test_helper->ShowAppList();
  224. EXPECT_FALSE(GetProductivityLauncherSearchView()->CanSelectSearchResults());
  225. // Press a key to start a search.
  226. PressAndReleaseKey(ui::VKEY_A);
  227. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  228. // Create categorized results and order categories as {kApps, kWeb}.
  229. std::vector<AppListSearchResultCategory>* ordered_categories =
  230. test_helper->GetOrderedResultCategories();
  231. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  232. ordered_categories->push_back(AppListSearchResultCategory::kApps);
  233. ordered_categories->push_back(AppListSearchResultCategory::kWeb);
  234. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, false,
  235. SearchResult::Category::kApps);
  236. SetUpSearchResults(results, 1 + kDefaultSearchItems, kDefaultSearchItems, 1,
  237. false, SearchResult::Category::kWeb);
  238. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  239. // Press VKEY_DOWN and check if the first result view is selected.
  240. EXPECT_TRUE(GetProductivityLauncherSearchView()->CanSelectSearchResults());
  241. ResultSelectionController* controller =
  242. GetProductivityLauncherSearchView()
  243. ->result_selection_controller_for_test();
  244. // Traverse the first results container.
  245. for (int i = 0; i < kDefaultSearchItems - 1; ++i) {
  246. PressAndReleaseKey(ui::VKEY_DOWN);
  247. ASSERT_TRUE(controller->selected_result()) << i;
  248. EXPECT_EQ(controller->selected_location_details()->container_index, 2) << i;
  249. EXPECT_EQ(controller->selected_location_details()->result_index, i + 1);
  250. }
  251. // Traverse the second container.
  252. for (int i = 0; i < kDefaultSearchItems; ++i) {
  253. PressAndReleaseKey(ui::VKEY_DOWN);
  254. ASSERT_TRUE(controller->selected_result()) << i;
  255. EXPECT_EQ(controller->selected_location_details()->container_index, 3) << i;
  256. EXPECT_EQ(controller->selected_location_details()->result_index, i);
  257. }
  258. // Pressing down while the last result is selected moves focus to the close
  259. // button.
  260. PressAndReleaseKey(ui::VKEY_DOWN);
  261. EXPECT_FALSE(controller->selected_result());
  262. EXPECT_TRUE(GetSearchBoxView()->close_button()->HasFocus());
  263. // Move focus the the search box, and verify result selection is properly set.
  264. PressAndReleaseKey(ui::VKEY_DOWN);
  265. EXPECT_TRUE(GetSearchBoxView()->search_box()->HasFocus());
  266. ASSERT_TRUE(controller->selected_result());
  267. EXPECT_EQ(controller->selected_location_details()->container_index, 2);
  268. EXPECT_EQ(controller->selected_location_details()->result_index, 0);
  269. // Up key should cycle focus to the close button, and then the last search
  270. // result.
  271. PressAndReleaseKey(ui::VKEY_UP);
  272. EXPECT_FALSE(controller->selected_result());
  273. EXPECT_TRUE(GetSearchBoxView()->close_button()->HasFocus());
  274. PressAndReleaseKey(ui::VKEY_UP);
  275. EXPECT_TRUE(GetSearchBoxView()->search_box()->HasFocus());
  276. ASSERT_TRUE(controller->selected_result());
  277. EXPECT_EQ(controller->selected_location_details()->container_index, 3);
  278. EXPECT_EQ(controller->selected_location_details()->result_index,
  279. kDefaultSearchItems - 1);
  280. }
  281. TEST_P(ProductivityLauncherSearchViewTest, AnswerCardSelection) {
  282. auto* test_helper = GetAppListTestHelper();
  283. test_helper->ShowAppList();
  284. EXPECT_FALSE(GetProductivityLauncherSearchView()->CanSelectSearchResults());
  285. // Press a key to start a search.
  286. PressAndReleaseKey(ui::VKEY_A);
  287. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  288. // Create categorized results and order categories as {kApps}.
  289. std::vector<ash::AppListSearchResultCategory>* ordered_categories =
  290. test_helper->GetOrderedResultCategories();
  291. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  292. ordered_categories->push_back(ash::AppListSearchResultCategory::kApps);
  293. SetUpSearchResults(results, 1, kDefaultSearchItems, 1, false,
  294. SearchResult::Category::kApps);
  295. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  296. // Verify result container ordering.
  297. std::vector<SearchResultContainerView*> result_containers =
  298. GetProductivityLauncherSearchView()->result_container_views_for_test();
  299. SetUpAnswerCardResult(results, 1, 1);
  300. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  301. EXPECT_EQ(GetVisibleResultContainers(), (std::vector<size_t>{0, 2}));
  302. EXPECT_TRUE(GetProductivityLauncherSearchView()->CanSelectSearchResults());
  303. ResultSelectionController* controller =
  304. GetProductivityLauncherSearchView()
  305. ->result_selection_controller_for_test();
  306. // Press VKEY_DOWN and check if the next is selected.
  307. EXPECT_EQ(controller->selected_location_details()->container_index, 0);
  308. EXPECT_EQ(controller->selected_location_details()->result_index, 0);
  309. PressAndReleaseKey(ui::VKEY_DOWN);
  310. EXPECT_EQ(controller->selected_location_details()->container_index, 2);
  311. EXPECT_EQ(controller->selected_location_details()->result_index, 0);
  312. PressAndReleaseKey(ui::VKEY_UP);
  313. EXPECT_EQ(controller->selected_location_details()->container_index, 0);
  314. EXPECT_EQ(controller->selected_location_details()->result_index, 0);
  315. }
  316. // Tests that result selection controller can change between within and between
  317. // result containers.
  318. TEST_P(ProductivityLauncherSearchViewTest, ResultSelection) {
  319. auto* test_helper = GetAppListTestHelper();
  320. test_helper->ShowAppList();
  321. EXPECT_FALSE(GetProductivityLauncherSearchView()->CanSelectSearchResults());
  322. // Press a key to start a search.
  323. PressAndReleaseKey(ui::VKEY_A);
  324. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  325. // Create categorized results and order categories as {kApps, kWeb}.
  326. std::vector<AppListSearchResultCategory>* ordered_categories =
  327. test_helper->GetOrderedResultCategories();
  328. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  329. ordered_categories->push_back(AppListSearchResultCategory::kApps);
  330. ordered_categories->push_back(AppListSearchResultCategory::kWeb);
  331. SetUpSearchResults(results, 2, kDefaultSearchItems, 100, false,
  332. SearchResult::Category::kApps);
  333. SetUpSearchResults(results, 2 + kDefaultSearchItems, kDefaultSearchItems, 1,
  334. false, SearchResult::Category::kWeb);
  335. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  336. std::vector<SearchResultContainerView*> result_containers =
  337. GetProductivityLauncherSearchView()->result_container_views_for_test();
  338. EXPECT_EQ(GetVisibleResultContainers(), (std::vector<size_t>{2, 3}));
  339. // Press VKEY_DOWN and check if the first result view is selected.
  340. EXPECT_TRUE(GetProductivityLauncherSearchView()->CanSelectSearchResults());
  341. ResultSelectionController* controller =
  342. GetProductivityLauncherSearchView()
  343. ->result_selection_controller_for_test();
  344. // Tests that VKEY_DOWN selects the next result.
  345. EXPECT_EQ(controller->selected_location_details()->container_index, 2);
  346. EXPECT_EQ(controller->selected_location_details()->result_index, 0);
  347. PressAndReleaseKey(ui::VKEY_DOWN);
  348. EXPECT_EQ(controller->selected_location_details()->container_index, 2);
  349. EXPECT_EQ(controller->selected_location_details()->result_index, 1);
  350. PressAndReleaseKey(ui::VKEY_DOWN);
  351. EXPECT_EQ(controller->selected_location_details()->container_index, 2);
  352. EXPECT_EQ(controller->selected_location_details()->result_index, 2);
  353. // Tests that VKEY_DOWN while selecting the last result of the current
  354. // container causes the selection controller to select the next container.
  355. PressAndReleaseKey(ui::VKEY_DOWN);
  356. EXPECT_EQ(controller->selected_location_details()->container_index, 3);
  357. EXPECT_EQ(controller->selected_location_details()->result_index, 0);
  358. PressAndReleaseKey(ui::VKEY_DOWN);
  359. EXPECT_EQ(controller->selected_location_details()->container_index, 3);
  360. EXPECT_EQ(controller->selected_location_details()->result_index, 1);
  361. PressAndReleaseKey(ui::VKEY_DOWN);
  362. EXPECT_EQ(controller->selected_location_details()->container_index, 3);
  363. EXPECT_EQ(controller->selected_location_details()->result_index, 2);
  364. // Tests that VKEY_UP while selecting the first result of the current
  365. // container causes the selection controller to select the previous container.
  366. PressAndReleaseKey(ui::VKEY_UP);
  367. PressAndReleaseKey(ui::VKEY_UP);
  368. PressAndReleaseKey(ui::VKEY_UP);
  369. EXPECT_EQ(controller->selected_location_details()->container_index, 2);
  370. EXPECT_EQ(controller->selected_location_details()->result_index, 2);
  371. }
  372. TEST_P(ProductivityLauncherSearchViewTest, ResultPageHiddenInZeroSearchState) {
  373. auto* test_helper = GetAppListTestHelper();
  374. test_helper->ShowAppList();
  375. // Tap on the search box to activate it.
  376. GetEventGenerator()->GestureTapAt(
  377. GetSearchBoxView()->GetBoundsInScreen().CenterPoint());
  378. EXPECT_TRUE(GetSearchBoxView()->is_search_box_active());
  379. EXPECT_FALSE(IsSearchResultPageVisible());
  380. // Set some zero-state results.
  381. std::vector<AppListSearchResultCategory>* ordered_categories =
  382. GetAppListTestHelper()->GetOrderedResultCategories();
  383. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  384. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  385. ordered_categories->push_back(AppListSearchResultCategory::kApps);
  386. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, false,
  387. SearchResult::Category::kApps);
  388. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  389. // Verify that keyboard traversal does not change the result selection.
  390. PressAndReleaseKey(ui::VKEY_DOWN);
  391. EXPECT_EQ(u"", GetSearchBoxView()->search_box()->GetText());
  392. EXPECT_FALSE(IsSearchResultPageVisible());
  393. // Selection should be set if user enters a query.
  394. PressAndReleaseKey(ui::VKEY_A);
  395. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  396. ordered_categories->push_back(AppListSearchResultCategory::kWeb);
  397. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, false,
  398. SearchResult::Category::kWeb);
  399. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  400. EXPECT_TRUE(GetSearchBoxView()->is_search_box_active());
  401. EXPECT_EQ(u"a", GetSearchBoxView()->search_box()->GetText());
  402. EXPECT_TRUE(IsSearchResultPageVisible());
  403. ResultSelectionController* controller =
  404. GetProductivityLauncherSearchView()
  405. ->result_selection_controller_for_test();
  406. EXPECT_TRUE(controller->selected_result());
  407. // Backspace should clear selection, and search box content.
  408. PressAndReleaseKey(ui::VKEY_BACK);
  409. EXPECT_TRUE(GetSearchBoxView()->is_search_box_active());
  410. EXPECT_EQ(u"", GetSearchBoxView()->search_box()->GetText());
  411. EXPECT_FALSE(IsSearchResultPageVisible());
  412. }
  413. // Verifies that search result categories are sorted properly.
  414. TEST_P(ProductivityLauncherSearchViewTest, SearchResultCategoricalSort) {
  415. auto* test_helper = GetAppListTestHelper();
  416. test_helper->ShowAppList();
  417. // Press a key to start a search.
  418. PressAndReleaseKey(ui::VKEY_A);
  419. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  420. std::vector<SearchResultContainerView*> result_containers =
  421. GetProductivityLauncherSearchView()->result_container_views_for_test();
  422. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  423. // Create categorized results and order categories as {kApps, kWeb}.
  424. std::vector<ash::AppListSearchResultCategory>* ordered_categories =
  425. test_helper->GetOrderedResultCategories();
  426. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  427. ordered_categories->push_back(ash::AppListSearchResultCategory::kApps);
  428. ordered_categories->push_back(ash::AppListSearchResultCategory::kWeb);
  429. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, false,
  430. SearchResult::Category::kApps);
  431. SetUpSearchResults(results, 1 + kDefaultSearchItems, kDefaultSearchItems, 1,
  432. false, SearchResult::Category::kWeb);
  433. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  434. // Verify result container visibility.
  435. EXPECT_EQ(GetVisibleResultContainers(), (std::vector<size_t>{2, 3}));
  436. // Verify title labels are correctly updated.
  437. EXPECT_EQ(GetListLabel(result_containers[0]), u"");
  438. EXPECT_EQ(GetListLabel(result_containers[1]), u"Best Match");
  439. EXPECT_EQ(GetListLabel(result_containers[2]), u"Apps");
  440. EXPECT_EQ(GetListLabel(result_containers[3]), u"Websites");
  441. // Verify result container ordering.
  442. EXPECT_EQ(GetListType(result_containers[0]),
  443. SearchResultListView::SearchResultListType::kAnswerCard);
  444. EXPECT_EQ(GetListType(result_containers[1]),
  445. SearchResultListView::SearchResultListType::kBestMatch);
  446. EXPECT_EQ(GetListType(result_containers[2]),
  447. SearchResultListView::SearchResultListType::kApps);
  448. EXPECT_EQ(GetListType(result_containers[3]),
  449. SearchResultListView::SearchResultListType::kWeb);
  450. // Create categorized results and order categories as {kWeb, kApps}.
  451. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  452. ordered_categories->push_back(ash::AppListSearchResultCategory::kWeb);
  453. ordered_categories->push_back(ash::AppListSearchResultCategory::kApps);
  454. SetUpSearchResults(results, 1, kDefaultSearchItems, 1, false,
  455. SearchResult::Category::kApps);
  456. SetUpSearchResults(results, 1 + kDefaultSearchItems, kDefaultSearchItems, 100,
  457. false, SearchResult::Category::kWeb);
  458. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  459. // Verify result container visibility.
  460. EXPECT_EQ(GetVisibleResultContainers(), (std::vector<size_t>{2, 3}));
  461. // Verify title labels are correctly updated.
  462. EXPECT_EQ(GetListLabel(result_containers[0]), u"");
  463. EXPECT_EQ(GetListLabel(result_containers[1]), u"Best Match");
  464. EXPECT_EQ(GetListLabel(result_containers[2]), u"Websites");
  465. EXPECT_EQ(GetListLabel(result_containers[3]), u"Apps");
  466. // Verify result container ordering.
  467. result_containers =
  468. GetProductivityLauncherSearchView()->result_container_views_for_test();
  469. EXPECT_EQ(GetListType(result_containers[0]),
  470. SearchResultListView::SearchResultListType::kAnswerCard);
  471. EXPECT_EQ(GetListType(result_containers[1]),
  472. SearchResultListView::SearchResultListType::kBestMatch);
  473. EXPECT_EQ(GetListType(result_containers[2]),
  474. SearchResultListView::SearchResultListType::kWeb);
  475. EXPECT_EQ(GetListType(result_containers[3]),
  476. SearchResultListView::SearchResultListType::kApps);
  477. SetUpAnswerCardResult(results, 1, 1);
  478. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  479. EXPECT_EQ(GetVisibleResultContainers(), (std::vector<size_t>{0, 2, 3}));
  480. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  481. // Adding results will schedule Update().
  482. base::RunLoop().RunUntilIdle();
  483. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  484. EXPECT_EQ(GetVisibleResultContainers(), (std::vector<size_t>{}));
  485. }
  486. TEST_P(ProductivityLauncherSearchViewTest, SearchResultA11y) {
  487. auto* test_helper = GetAppListTestHelper();
  488. test_helper->ShowAppList();
  489. // Press a key to start a search.
  490. PressAndReleaseKey(ui::VKEY_A);
  491. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  492. // Create |kDefaultSearchItems| new search results for us to cycle through.
  493. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, true,
  494. SearchResult::Category::kApps);
  495. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  496. // Check result container visibility.
  497. std::vector<SearchResultContainerView*> result_containers =
  498. GetProductivityLauncherSearchView()->result_container_views_for_test();
  499. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  500. EXPECT_TRUE(result_containers[1]->GetVisible());
  501. views::test::AXEventCounter ax_counter(views::AXEventManager::Get());
  502. // Pressing down should not generate a selection accessibility event because
  503. // A11Y announcements are delayed since the results list just changed.
  504. PressAndReleaseKey(ui::VKEY_DOWN);
  505. EXPECT_EQ(0, ax_counter.GetCount(ax::mojom::Event::kActiveDescendantChanged));
  506. // Advance time to fire the timer to stop ignoring A11Y announcements.
  507. task_environment()->FastForwardBy(base::Milliseconds(5000));
  508. // A selection event is generated when the timer fires.
  509. EXPECT_EQ(1, ax_counter.GetCount(ax::mojom::Event::kActiveDescendantChanged));
  510. // Successive up/down key presses should generate additional selection events.
  511. PressAndReleaseKey(ui::VKEY_DOWN);
  512. EXPECT_EQ(2, ax_counter.GetCount(ax::mojom::Event::kActiveDescendantChanged));
  513. PressAndReleaseKey(ui::VKEY_UP);
  514. EXPECT_EQ(3, ax_counter.GetCount(ax::mojom::Event::kActiveDescendantChanged));
  515. PressAndReleaseKey(ui::VKEY_DOWN);
  516. EXPECT_EQ(4, ax_counter.GetCount(ax::mojom::Event::kActiveDescendantChanged));
  517. PressAndReleaseKey(ui::VKEY_DOWN);
  518. EXPECT_EQ(5, ax_counter.GetCount(ax::mojom::Event::kActiveDescendantChanged));
  519. }
  520. TEST_P(ProductivityLauncherSearchViewTest, SearchPageA11y) {
  521. auto* test_helper = GetAppListTestHelper();
  522. test_helper->ShowAppList();
  523. // Press a key to start a search.
  524. PressAndReleaseKey(ui::VKEY_A);
  525. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  526. // Delete all results and verify the bubble search page's A11yNodeData.
  527. AppListModelProvider::Get()->search_model()->DeleteAllResults();
  528. auto* search_view = GetProductivityLauncherSearchView();
  529. search_view->OnSearchResultContainerResultsChanged();
  530. // Check result container visibility.
  531. std::vector<SearchResultContainerView*> result_containers =
  532. search_view->result_container_views_for_test();
  533. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  534. // Container view should not be shown if no result is present.
  535. EXPECT_FALSE(result_containers[0]->GetVisible());
  536. EXPECT_TRUE(search_view->GetVisible());
  537. ui::AXNodeData data;
  538. search_view->GetAccessibleNodeData(&data);
  539. EXPECT_EQ("Displaying 0 results for a",
  540. data.GetStringAttribute(ax::mojom::StringAttribute::kValue));
  541. // Create a single search result and and verify A11yNodeData.
  542. SetUpSearchResults(results, 1, 1, 100, true, SearchResult::Category::kApps);
  543. search_view->OnSearchResultContainerResultsChanged();
  544. search_view->GetAccessibleNodeData(&data);
  545. EXPECT_EQ("Displaying 1 result for a",
  546. data.GetStringAttribute(ax::mojom::StringAttribute::kValue));
  547. // Create new search results and and and verify A11yNodeData.
  548. SetUpSearchResults(results, 2, kDefaultSearchItems - 1, 100, true,
  549. SearchResult::Category::kApps);
  550. search_view->OnSearchResultContainerResultsChanged();
  551. ui::AXNodeData data2;
  552. search_view->GetAccessibleNodeData(&data);
  553. EXPECT_EQ("Displaying 3 results for a",
  554. data.GetStringAttribute(ax::mojom::StringAttribute::kValue));
  555. }
  556. TEST_P(ProductivityLauncherSearchViewTest, SearchClearedOnModelUpdate) {
  557. auto* test_helper = GetAppListTestHelper();
  558. test_helper->ShowAppList();
  559. // Press a key to start a search.
  560. PressAndReleaseKey(ui::VKEY_A);
  561. SearchModel::SearchResults* results = test_helper->GetSearchResults();
  562. // Create |kDefaultSearchItems| new search results for us to cycle through.
  563. SetUpSearchResults(results, 1, kDefaultSearchItems, 100, true,
  564. SearchResult::Category::kApps);
  565. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  566. // Check result container visibility.
  567. std::vector<SearchResultContainerView*> result_containers =
  568. GetProductivityLauncherSearchView()->result_container_views_for_test();
  569. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  570. EXPECT_TRUE(result_containers[1]->GetVisible());
  571. // Update the app list and search model, and verify the results page gets
  572. // hidden.
  573. auto app_list_model_override = std::make_unique<test::AppListTestModel>();
  574. auto search_model_override = std::make_unique<SearchModel>();
  575. Shell::Get()->app_list_controller()->SetActiveModel(
  576. /*profile_id=*/1, app_list_model_override.get(),
  577. search_model_override.get());
  578. EXPECT_FALSE(IsSearchResultPageVisible());
  579. EXPECT_EQ(u"", GetSearchBoxView()->search_box()->GetText());
  580. // Press a key to start a search.
  581. PressAndReleaseKey(ui::VKEY_A);
  582. SetUpSearchResults(search_model_override->results(), 2, 1, 100, true,
  583. SearchResult::Category::kApps);
  584. GetProductivityLauncherSearchView()->OnSearchResultContainerResultsChanged();
  585. result_containers =
  586. GetProductivityLauncherSearchView()->result_container_views_for_test();
  587. ASSERT_EQ(static_cast<int>(result_containers.size()), kResultContainersCount);
  588. EXPECT_TRUE(result_containers[1]->GetVisible());
  589. EXPECT_EQ(1, result_containers[1]->num_results());
  590. EXPECT_EQ(u"Result 2",
  591. result_containers[1]->GetResultViewAt(0)->result()->title());
  592. Shell::Get()->app_list_controller()->ClearActiveModel();
  593. }
  594. } // namespace ash