1 // Copyright 2015 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 5 package org.chromium.chrome.browser.bookmarks; 6 7 import static androidx.test.espresso.Espresso.onView; 8 import static androidx.test.espresso.action.ViewActions.click; 9 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; 10 import static androidx.test.espresso.assertion.ViewAssertions.matches; 11 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; 12 import static androidx.test.espresso.matcher.ViewMatchers.withText; 13 14 import static org.mockito.Mockito.any; 15 import static org.mockito.Mockito.doNothing; 16 import static org.mockito.Mockito.when; 17 18 import static org.chromium.components.browser_ui.widget.highlight.ViewHighlighterTestUtils.checkHighlightOff; 19 import static org.chromium.components.browser_ui.widget.highlight.ViewHighlighterTestUtils.checkHighlightPulse; 20 21 import android.support.test.InstrumentationRegistry; 22 import android.support.test.runner.lifecycle.Stage; 23 import android.text.TextUtils; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.widget.TextView; 27 28 import androidx.annotation.Nullable; 29 import androidx.recyclerview.widget.RecyclerView; 30 import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver; 31 import androidx.recyclerview.widget.RecyclerView.ViewHolder; 32 import androidx.test.filters.MediumTest; 33 import androidx.test.filters.SmallTest; 34 35 import org.hamcrest.Matchers; 36 import org.hamcrest.core.IsInstanceOf; 37 import org.junit.After; 38 import org.junit.AfterClass; 39 import org.junit.Assert; 40 import org.junit.Before; 41 import org.junit.BeforeClass; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.Mock; 46 import org.mockito.junit.MockitoJUnit; 47 import org.mockito.junit.MockitoRule; 48 49 import org.chromium.base.ApplicationStatus; 50 import org.chromium.base.test.params.ParameterAnnotations; 51 import org.chromium.base.test.params.ParameterizedRunner; 52 import org.chromium.base.test.util.ApplicationTestUtils; 53 import org.chromium.base.test.util.CallbackHelper; 54 import org.chromium.base.test.util.CommandLineFlags; 55 import org.chromium.base.test.util.Criteria; 56 import org.chromium.base.test.util.CriteriaHelper; 57 import org.chromium.base.test.util.DisabledTest; 58 import org.chromium.base.test.util.Feature; 59 import org.chromium.base.test.util.FlakyTest; 60 import org.chromium.base.test.util.Restriction; 61 import org.chromium.chrome.R; 62 import org.chromium.chrome.browser.ChromeTabbedActivity; 63 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; 64 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver; 65 import org.chromium.chrome.browser.bookmarks.BookmarkPromoHeader.PromoState; 66 import org.chromium.chrome.browser.flags.ChromeFeatureList; 67 import org.chromium.chrome.browser.flags.ChromeSwitches; 68 import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils; 69 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; 70 import org.chromium.chrome.browser.offlinepages.OfflinePageItem; 71 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim; 72 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; 73 import org.chromium.chrome.browser.preferences.SharedPreferencesManager; 74 import org.chromium.chrome.browser.profiles.Profile; 75 import org.chromium.chrome.browser.sync.AndroidSyncSettings; 76 import org.chromium.chrome.browser.sync.AndroidSyncSettings.AndroidSyncSettingsObserver; 77 import org.chromium.chrome.browser.tab.Tab; 78 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar; 79 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; 80 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; 81 import org.chromium.chrome.test.ChromeTabbedActivityTestRule; 82 import org.chromium.chrome.test.util.ActivityUtils; 83 import org.chromium.chrome.test.util.BookmarkTestUtil; 84 import org.chromium.chrome.test.util.ChromeRenderTestRule; 85 import org.chromium.chrome.test.util.MenuUtils; 86 import org.chromium.chrome.test.util.browser.Features; 87 import org.chromium.chrome.test.util.browser.Features.EnableFeatures; 88 import org.chromium.components.bookmarks.BookmarkId; 89 import org.chromium.components.bookmarks.BookmarkType; 90 import org.chromium.components.browser_ui.widget.RecyclerViewTestUtils; 91 import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton; 92 import org.chromium.components.browser_ui.widget.selectable_list.SelectableListToolbar; 93 import org.chromium.components.browser_ui.widget.selectable_list.SelectableListToolbar.ViewType; 94 import org.chromium.components.embedder_support.util.UrlConstants; 95 import org.chromium.content_public.browser.test.util.TestThreadUtils; 96 import org.chromium.content_public.browser.test.util.TouchCommon; 97 import org.chromium.net.test.EmbeddedTestServer; 98 import org.chromium.ui.test.util.NightModeTestUtils; 99 import org.chromium.ui.test.util.UiRestriction; 100 101 import java.util.ArrayList; 102 import java.util.List; 103 import java.util.concurrent.Callable; 104 import java.util.concurrent.ExecutionException; 105 106 /** 107 * Tests for the bookmark manager. 108 */ 109 // clang-format off 110 @RunWith(ParameterizedRunner.class) 111 @ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) 112 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) 113 public class BookmarkTest { 114 // clang-format on 115 @Rule 116 public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); 117 118 @Rule 119 public ChromeRenderTestRule mRenderTestRule = 120 ChromeRenderTestRule.Builder.withPublicCorpus().build(); 121 @Rule 122 public final MockitoRule mMockitoRule = MockitoJUnit.rule(); 123 124 private static final String TEST_PAGE_URL_GOOGLE = "/chrome/test/data/android/google.html"; 125 private static final String TEST_PAGE_TITLE_GOOGLE = "The Google"; 126 private static final String TEST_PAGE_TITLE_GOOGLE2 = "Google"; 127 private static final String TEST_PAGE_URL_FOO = "/chrome/test/data/android/test.html"; 128 private static final String TEST_PAGE_TITLE_FOO = "Foo"; 129 private static final String TEST_FOLDER_TITLE = "Test folder"; 130 private static final String TEST_FOLDER_TITLE2 = "Test folder 2"; 131 private static final String TEST_TITLE_A = "a"; 132 private static final String TEST_URL_A = "http://a.com"; 133 134 private BookmarkManager mManager; 135 private BookmarkModel mBookmarkModel; 136 private BookmarkBridge mBookmarkBridge; 137 private RecyclerView mItemsContainer; 138 private String mTestPage; 139 private String mTestPageFoo; 140 private EmbeddedTestServer mTestServer; 141 private @Nullable BookmarkActivity mBookmarkActivity; 142 @Mock 143 private AndroidSyncSettings mAndroidSyncSettings; 144 145 @BeforeClass setUpBeforeActivityLaunched()146 public static void setUpBeforeActivityLaunched() { 147 ChromeNightModeTestUtils.setUpNightModeBeforeChromeActivityLaunched(); 148 } 149 150 @ParameterAnnotations.UseMethodParameterBefore(NightModeTestUtils.NightModeParams.class) setupNightMode(boolean nightModeEnabled)151 public void setupNightMode(boolean nightModeEnabled) { 152 ChromeNightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled); 153 mRenderTestRule.setNightModeEnabled(nightModeEnabled); 154 } 155 156 @Before setUp()157 public void setUp() { 158 mActivityTestRule.startMainActivityOnBlankPage(); 159 TestThreadUtils.runOnUiThreadBlocking(() -> { 160 mBookmarkModel = new BookmarkModel(Profile.fromWebContents( 161 mActivityTestRule.getActivity().getActivityTab().getWebContents())); 162 mBookmarkBridge = mActivityTestRule.getActivity().getBookmarkBridgeForTesting(); 163 164 // Stub AndroidSyncSettings state to make sure promos aren't suppressed. 165 when(mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync()).thenReturn(true); 166 when(mAndroidSyncSettings.isSyncEnabled()).thenReturn(false); 167 when(mAndroidSyncSettings.isChromeSyncEnabled()).thenReturn(false); 168 doNothing() 169 .when(mAndroidSyncSettings) 170 .registerObserver(any(AndroidSyncSettingsObserver.class)); 171 doNothing() 172 .when(mAndroidSyncSettings) 173 .unregisterObserver(any(AndroidSyncSettingsObserver.class)); 174 AndroidSyncSettings.overrideForTests(mAndroidSyncSettings); 175 }); 176 mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); 177 mTestPage = mTestServer.getURL(TEST_PAGE_URL_GOOGLE); 178 mTestPageFoo = mTestServer.getURL(TEST_PAGE_URL_FOO); 179 } 180 readPartnerBookmarks()181 private void readPartnerBookmarks() { 182 // Do not read partner bookmarks in setUp(), so that the lazy reading is covered. 183 TestThreadUtils.runOnUiThreadBlocking( 184 () -> PartnerBookmarksShim.kickOffReading(mActivityTestRule.getActivity())); 185 BookmarkTestUtil.waitForBookmarkModelLoaded(); 186 } 187 188 /** 189 * Loads an empty partner bookmarks folder for testing. The partner bookmarks folder will appear 190 * in the mobile bookmarks folder. 191 * 192 */ loadEmptyPartnerBookmarksForTesting()193 private void loadEmptyPartnerBookmarksForTesting() { 194 TestThreadUtils.runOnUiThreadBlocking( 195 () -> { mBookmarkModel.loadEmptyPartnerBookmarkShimForTesting(); }); 196 BookmarkTestUtil.waitForBookmarkModelLoaded(); 197 } 198 199 /** 200 * Loads a non-empty partner bookmarks folder for testing. The partner bookmarks folder will 201 * appear in the mobile bookmarks folder. 202 */ loadFakePartnerBookmarkShimForTesting()203 private void loadFakePartnerBookmarkShimForTesting() { 204 TestThreadUtils.runOnUiThreadBlocking( 205 () -> { mBookmarkModel.loadFakePartnerBookmarkShimForTesting(); }); 206 BookmarkTestUtil.waitForBookmarkModelLoaded(); 207 } 208 209 @After tearDown()210 public void tearDown() { 211 if (mTestServer != null) mTestServer.stopAndDestroyServer(); 212 } 213 214 @AfterClass tearDownAfterActivityDestroyed()215 public static void tearDownAfterActivityDestroyed() { 216 ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed(); 217 } 218 openBookmarkManager()219 private void openBookmarkManager() throws InterruptedException { 220 if (mActivityTestRule.getActivity().isTablet()) { 221 mActivityTestRule.loadUrl(UrlConstants.BOOKMARKS_URL); 222 mItemsContainer = mActivityTestRule.getActivity().findViewById(R.id.recycler_view); 223 mItemsContainer.setItemAnimator(null); // Disable animation to reduce flakiness. 224 mManager = ((BookmarkPage) mActivityTestRule.getActivity() 225 .getActivityTab() 226 .getNativePage()) 227 .getManagerForTesting(); 228 } else { 229 // phone 230 mBookmarkActivity = ActivityUtils.waitForActivity( 231 InstrumentationRegistry.getInstrumentation(), BookmarkActivity.class, 232 new MenuUtils.MenuActivityTrigger(InstrumentationRegistry.getInstrumentation(), 233 mActivityTestRule.getActivity(), R.id.all_bookmarks_menu_id)); 234 mItemsContainer = mBookmarkActivity.findViewById(R.id.recycler_view); 235 mItemsContainer.setItemAnimator(null); // Disable animation to reduce flakiness. 236 mManager = mBookmarkActivity.getManagerForTesting(); 237 } 238 239 TestThreadUtils.runOnUiThreadBlocking( 240 () -> mManager.getDragStateDelegate().setA11yStateForTesting(false)); 241 } 242 isItemPresentInBookmarkList(final String expectedTitle)243 private boolean isItemPresentInBookmarkList(final String expectedTitle) { 244 return TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { 245 @Override 246 public Boolean call() { 247 for (int i = 0; i < mItemsContainer.getAdapter().getItemCount(); i++) { 248 BookmarkId item = getIdByPosition(i); 249 250 if (item == null) continue; 251 252 String actualTitle = mBookmarkModel.getBookmarkTitle(item); 253 if (TextUtils.equals(actualTitle, expectedTitle)) { 254 return true; 255 } 256 } 257 return false; 258 } 259 }); 260 } 261 262 private void waitForOfflinePageSaved(String url) throws Exception { 263 CallbackHelper callbackHelper = new CallbackHelper(); 264 TestThreadUtils.runOnUiThreadBlocking(() -> { 265 OfflinePageBridge bridge = 266 OfflinePageBridge.getForProfile(Profile.getLastUsedRegularProfile()); 267 bridge.getAllPages((items) -> { 268 for (OfflinePageItem item : items) { 269 if (url.startsWith(item.getUrl())) { 270 callbackHelper.notifyCalled(); 271 } 272 } 273 }); 274 }); 275 callbackHelper.waitForFirst(); 276 } 277 278 @Test 279 @SmallTest testAddBookmark()280 public void testAddBookmark() throws Exception { 281 mActivityTestRule.loadUrl(mTestPage); 282 // Check partner bookmarks are lazily loaded. 283 Assert.assertFalse(mBookmarkModel.isBookmarkModelLoaded()); 284 285 // Click star button to bookmark the current tab. 286 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 287 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); 288 BookmarkTestUtil.waitForBookmarkModelLoaded(); 289 // All actions with BookmarkModel needs to run on UI thread. 290 TestThreadUtils.runOnUiThreadBlocking(() -> { 291 long bookmarkIdLong = mBookmarkBridge.getUserBookmarkIdForTab( 292 mActivityTestRule.getActivity().getActivityTabProvider().get()); 293 BookmarkId id = new BookmarkId(bookmarkIdLong, BookmarkType.NORMAL); 294 Assert.assertTrue("The test page is not added as bookmark: ", 295 mBookmarkModel.doesBookmarkExist(id)); 296 BookmarkItem item = mBookmarkModel.getBookmarkById(id); 297 Assert.assertEquals(mBookmarkModel.getDefaultFolder(), item.getParentId()); 298 Assert.assertEquals(mTestPage, item.getUrl()); 299 Assert.assertEquals(TEST_PAGE_TITLE_GOOGLE, item.getTitle()); 300 }); 301 302 waitForOfflinePageSaved(mTestPage); 303 304 // Click the star button again to launch the edit activity. 305 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 306 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); 307 waitForEditActivity(); 308 } 309 310 @Test 311 @SmallTest testAddBookmarkSnackbar()312 public void testAddBookmarkSnackbar() { 313 mActivityTestRule.loadUrl(mTestPage); 314 // Check partner bookmarks are lazily loaded. 315 Assert.assertFalse(mBookmarkModel.isBookmarkModelLoaded()); 316 // Arbitrarily long duration to validate appearance of snackbar. 317 SnackbarManager.setDurationForTesting(50000); 318 319 // Click star button to bookmark the current tab. 320 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 321 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); 322 BookmarkTestUtil.waitForBookmarkModelLoaded(); 323 // All actions with BookmarkModel needs to run on UI thread. 324 TestThreadUtils.runOnUiThreadBlocking(() -> { 325 long bookmarkIdLong = mBookmarkBridge.getUserBookmarkIdForTab( 326 mActivityTestRule.getActivity().getActivityTabProvider().get()); 327 BookmarkId id = new BookmarkId(bookmarkIdLong, BookmarkType.NORMAL); 328 Assert.assertTrue("The test page is not added as bookmark: ", 329 mBookmarkModel.doesBookmarkExist(id)); 330 331 SnackbarManager snackbarManager = mActivityTestRule.getActivity().getSnackbarManager(); 332 Snackbar currentSnackbar = snackbarManager.getCurrentSnackbarForTesting(); 333 Assert.assertEquals("Add bookmark snackbar not shown.", Snackbar.UMA_BOOKMARK_ADDED, 334 currentSnackbar.getIdentifierForTesting()); 335 currentSnackbar.getController().onAction(null); 336 }); 337 338 waitForEditActivity(); 339 SnackbarManager.setDurationForTesting(0); 340 } 341 342 @Test 343 @SmallTest testAddBookmarkToOtherFolder()344 public void testAddBookmarkToOtherFolder() { 345 mActivityTestRule.loadUrl(mTestPage); 346 readPartnerBookmarks(); 347 // Set default folder as "Other Folder". 348 TestThreadUtils.runOnUiThreadBlocking(() -> { 349 SharedPreferencesManager.getInstance().writeString( 350 ChromePreferenceKeys.BOOKMARKS_LAST_USED_PARENT, 351 mBookmarkModel.getOtherFolderId().toString()); 352 }); 353 // Click star button to bookmark the current tab. 354 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 355 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); 356 BookmarkTestUtil.waitForBookmarkModelLoaded(); 357 // All actions with BookmarkModel needs to run on UI thread. 358 TestThreadUtils.runOnUiThreadBlocking(() -> { 359 long bookmarkIdLong = mBookmarkBridge.getUserBookmarkIdForTab( 360 mActivityTestRule.getActivity().getActivityTabProvider().get()); 361 BookmarkId id = new BookmarkId(bookmarkIdLong, BookmarkType.NORMAL); 362 Assert.assertTrue("The test page is not added as bookmark: ", 363 mBookmarkModel.doesBookmarkExist(id)); 364 BookmarkItem item = mBookmarkModel.getBookmarkById(id); 365 Assert.assertEquals("Bookmark added in a wrong default folder.", 366 mBookmarkModel.getOtherFolderId(), item.getParentId()); 367 }); 368 } 369 370 @Test 371 @SmallTest testOpenBookmark()372 public void testOpenBookmark() throws InterruptedException, ExecutionException { 373 addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage); 374 openBookmarkManager(); 375 Assert.assertTrue("Grid view does not contain added bookmark: ", 376 isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE)); 377 final View title = getViewWithText(mItemsContainer, TEST_PAGE_TITLE_GOOGLE); 378 TestThreadUtils.runOnUiThreadBlocking(() -> TouchCommon.singleClickView(title)); 379 ChromeTabbedActivity activity = waitForTabbedActivity(); 380 CriteriaHelper.pollUiThread(() -> { 381 Tab activityTab = activity.getActivityTab(); 382 Criteria.checkThat(activityTab, Matchers.notNullValue()); 383 Criteria.checkThat(activityTab.getUrl(), Matchers.notNullValue()); 384 Criteria.checkThat(activityTab.getUrl().getSpec(), Matchers.is(mTestPage)); 385 }); 386 } 387 388 @Test 389 @SmallTest testUrlComposition()390 public void testUrlComposition() { 391 readPartnerBookmarks(); 392 TestThreadUtils.runOnUiThreadBlocking(() -> { 393 BookmarkId mobileId = mBookmarkModel.getMobileFolderId(); 394 BookmarkId bookmarkBarId = mBookmarkModel.getDesktopFolderId(); 395 BookmarkId otherId = mBookmarkModel.getOtherFolderId(); 396 Assert.assertEquals("chrome-native://bookmarks/folder/" + mobileId, 397 BookmarkUIState.createFolderUrl(mobileId).toString()); 398 Assert.assertEquals("chrome-native://bookmarks/folder/" + bookmarkBarId, 399 BookmarkUIState.createFolderUrl(bookmarkBarId).toString()); 400 Assert.assertEquals("chrome-native://bookmarks/folder/" + otherId, 401 BookmarkUIState.createFolderUrl(otherId).toString()); 402 }); 403 } 404 405 @Test 406 @SmallTest 407 @FlakyTest(message = "crbug.com/879803") testOpenBookmarkManager()408 public void testOpenBookmarkManager() throws InterruptedException { 409 openBookmarkManager(); 410 BookmarkDelegate delegate = getBookmarkManager(); 411 412 Assert.assertEquals(BookmarkUIState.STATE_FOLDER, delegate.getCurrentState()); 413 Assert.assertEquals("chrome-native://bookmarks/folder/3", 414 BookmarkUtils.getLastUsedUrl(mActivityTestRule.getActivity())); 415 } 416 417 @Test 418 @MediumTest 419 @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) testFolderNavigation_Phone()420 public void testFolderNavigation_Phone() throws InterruptedException, ExecutionException { 421 BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE); 422 openBookmarkManager(); 423 final BookmarkDelegate delegate = getBookmarkManager(); 424 final BookmarkActionBar toolbar = ((BookmarkManager) delegate).getToolbarForTests(); 425 426 // Open the "Mobile bookmarks" folder. 427 TestThreadUtils.runOnUiThreadBlocking( 428 () -> delegate.openFolder(mBookmarkModel.getMobileFolderId())); 429 430 // Check that we are in the mobile bookmarks folder. 431 Assert.assertEquals("Mobile bookmarks", toolbar.getTitle()); 432 Assert.assertEquals(SelectableListToolbar.NAVIGATION_BUTTON_BACK, 433 toolbar.getNavigationButtonForTests()); 434 Assert.assertFalse(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible()); 435 436 // Open the new test folder. 437 TestThreadUtils.runOnUiThreadBlocking(() -> delegate.openFolder(testFolder)); 438 439 // Check that we are in the editable test folder. 440 Assert.assertEquals(TEST_FOLDER_TITLE, toolbar.getTitle()); 441 Assert.assertEquals(SelectableListToolbar.NAVIGATION_BUTTON_BACK, 442 toolbar.getNavigationButtonForTests()); 443 Assert.assertTrue(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible()); 444 445 // Call BookmarkActionBar#onClick() to activate the navigation button. 446 TestThreadUtils.runOnUiThreadBlocking(() -> toolbar.onClick(toolbar)); 447 448 // Check that we are back in the mobile folder 449 Assert.assertEquals("Mobile bookmarks", toolbar.getTitle()); 450 Assert.assertEquals(SelectableListToolbar.NAVIGATION_BUTTON_BACK, 451 toolbar.getNavigationButtonForTests()); 452 Assert.assertFalse(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible()); 453 454 // Call BookmarkActionBar#onClick() to activate the navigation button. 455 TestThreadUtils.runOnUiThreadBlocking(() -> toolbar.onClick(toolbar)); 456 457 // Check that we are in the root folder. 458 Assert.assertEquals("Bookmarks", toolbar.getTitle()); 459 Assert.assertEquals(SelectableListToolbar.NAVIGATION_BUTTON_NONE, 460 toolbar.getNavigationButtonForTests()); 461 Assert.assertFalse(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible()); 462 } 463 464 // TODO(twellington): Write a folder navigation test for tablets that waits for the Tab hosting 465 // the native page to update its url after navigations. 466 467 @Test 468 @MediumTest testSearchBookmarks()469 public void testSearchBookmarks() throws Exception { 470 BookmarkPromoHeader.forcePromoStateForTests(BookmarkPromoHeader.PromoState.PROMO_SYNC); 471 BookmarkId folder = addFolder(TEST_FOLDER_TITLE); 472 addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder); 473 addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder); 474 openBookmarkManager(); 475 476 RecyclerView.Adapter adapter = getAdapter(); 477 final BookmarkDelegate delegate = getBookmarkManager(); 478 479 // Open the new folder where these bookmarks were created. 480 openFolder(folder); 481 482 Assert.assertEquals(BookmarkUIState.STATE_FOLDER, delegate.getCurrentState()); 483 Assert.assertEquals( 484 "Wrong number of items before starting search.", 3, adapter.getItemCount()); 485 486 TestThreadUtils.runOnUiThreadBlocking(delegate::openSearchUI); 487 488 Assert.assertEquals(BookmarkUIState.STATE_SEARCHING, delegate.getCurrentState()); 489 Assert.assertEquals( 490 "Wrong number of items after showing search UI. The promo should be hidden.", 2, 491 adapter.getItemCount()); 492 493 searchBookmarks("Google"); 494 Assert.assertEquals("Wrong number of items after searching.", 1, 495 mItemsContainer.getAdapter().getItemCount()); 496 497 BookmarkId newBookmark = addBookmark(TEST_PAGE_TITLE_GOOGLE2, mTestPage); 498 Assert.assertEquals("Wrong number of items after bookmark added while searching.", 2, 499 mItemsContainer.getAdapter().getItemCount()); 500 501 removeBookmark(newBookmark); 502 Assert.assertEquals("Wrong number of items after bookmark removed while searching.", 1, 503 mItemsContainer.getAdapter().getItemCount()); 504 505 searchBookmarks("Non-existent page"); 506 Assert.assertEquals("Wrong number of items after searching for non-existent item.", 0, 507 mItemsContainer.getAdapter().getItemCount()); 508 509 TestThreadUtils.runOnUiThreadBlocking( 510 () -> ((BookmarkManager) delegate).getToolbarForTests().hideSearchView()); 511 Assert.assertEquals("Wrong number of items after closing search UI.", 3, 512 mItemsContainer.getAdapter().getItemCount()); 513 Assert.assertEquals(BookmarkUIState.STATE_FOLDER, delegate.getCurrentState()); 514 } 515 516 @Test 517 @MediumTest testSearchBookmarks_Delete()518 public void testSearchBookmarks_Delete() throws Exception { 519 BookmarkPromoHeader.forcePromoStateForTests(BookmarkPromoHeader.PromoState.PROMO_NONE); 520 BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE); 521 BookmarkId testFolder2 = addFolder(TEST_FOLDER_TITLE2, testFolder); 522 BookmarkId testBookmark = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, testFolder); 523 addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, testFolder); 524 openBookmarkManager(); 525 526 RecyclerView.Adapter adapter = getAdapter(); 527 BookmarkManager manager = getBookmarkManager(); 528 529 // Open the new folder where these bookmarks were created. 530 openFolder(testFolder); 531 532 Assert.assertEquals("Wrong state, should be in folder", BookmarkUIState.STATE_FOLDER, 533 manager.getCurrentState()); 534 Assert.assertEquals( 535 "Wrong number of items before starting search.", 3, adapter.getItemCount()); 536 537 // Start searching without entering a query. 538 TestThreadUtils.runOnUiThreadBlocking(manager::openSearchUI); 539 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 540 Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING, 541 manager.getCurrentState()); 542 543 // Select testFolder2 and delete it. 544 toggleSelectionAndEndAnimation(testFolder2, 545 (BookmarkRow) mItemsContainer.findViewHolderForLayoutPosition(2).itemView); 546 TestThreadUtils.runOnUiThreadBlocking( 547 () 548 -> manager.getToolbarForTests().onMenuItemClick( 549 manager.getToolbarForTests().getMenu().findItem( 550 R.id.selection_mode_delete_menu_id))); 551 552 // Search should be exited and the folder should be gone. 553 Assert.assertEquals("Wrong state, should be in folder", BookmarkUIState.STATE_FOLDER, 554 manager.getCurrentState()); 555 Assert.assertEquals( 556 "Wrong number of items before starting search.", 2, adapter.getItemCount()); 557 558 // Start searching, enter a query. 559 TestThreadUtils.runOnUiThreadBlocking(manager::openSearchUI); 560 Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING, 561 manager.getCurrentState()); 562 searchBookmarks("Google"); 563 Assert.assertEquals("Wrong number of items after searching.", 1, 564 mItemsContainer.getAdapter().getItemCount()); 565 566 // Remove the bookmark. 567 removeBookmark(testBookmark); 568 569 // The user should still be searching, and the bookmark should be gone. 570 Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING, 571 manager.getCurrentState()); 572 Assert.assertEquals("Wrong number of items after searching.", 0, 573 mItemsContainer.getAdapter().getItemCount()); 574 575 // Undo the deletion. 576 TestThreadUtils.runOnUiThreadBlocking( 577 () -> manager.getUndoControllerForTests().onAction(null)); 578 579 // The user should still be searching, and the bookmark should reappear. 580 Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING, 581 manager.getCurrentState()); 582 Assert.assertEquals("Wrong number of items after searching.", 1, 583 mItemsContainer.getAdapter().getItemCount()); 584 } 585 586 @Test 587 @MediumTest 588 @Feature({"RenderTest"}) 589 @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) testBookmarkFolderIcon(boolean nightModeEnabled)590 public void testBookmarkFolderIcon(boolean nightModeEnabled) throws Exception { 591 BookmarkPromoHeader.forcePromoStateForTests(BookmarkPromoHeader.PromoState.PROMO_NONE); 592 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 593 openBookmarkManager(); 594 595 RecyclerView.Adapter adapter = getAdapter(); 596 final BookmarkManager manager = getBookmarkManager(); 597 598 mRenderTestRule.render(manager.getView(), "bookmark_manager_one_folder"); 599 600 BookmarkRow itemView = (BookmarkRow) manager.getRecyclerViewForTests() 601 .findViewHolderForAdapterPosition(0) 602 .itemView; 603 604 toggleSelectionAndEndAnimation(getIdByPosition(0), itemView); 605 606 // Make sure the Item "test" is selected. 607 CriteriaHelper.pollUiThread( 608 itemView::isChecked, "Expected item \"test\" to become selected"); 609 610 mRenderTestRule.render(manager.getView(), "bookmark_manager_folder_selected"); 611 toggleSelectionAndEndAnimation(getIdByPosition(0), itemView); 612 mRenderTestRule.render(manager.getView(), "bookmark_manager_one_folder"); 613 } 614 615 @Test 616 @MediumTest 617 @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) // Tablets don't have a close button. testCloseBookmarksWhileStillLoading()618 public void testCloseBookmarksWhileStillLoading() throws Exception { 619 BookmarkManager.preventLoadingForTesting(true); 620 621 openBookmarkManager(); 622 623 final BookmarkActionBar toolbar = mManager.getToolbarForTests(); 624 625 TestThreadUtils.runOnUiThreadBlocking( 626 () -> toolbar.onMenuItemClick(toolbar.getMenu().findItem(R.id.close_menu_id))); 627 628 ApplicationTestUtils.waitForActivityState(mBookmarkActivity, Stage.DESTROYED); 629 630 BookmarkManager.preventLoadingForTesting(false); 631 } 632 633 @Test 634 @MediumTest testEditHiddenWhileStillLoading()635 public void testEditHiddenWhileStillLoading() throws Exception { 636 BookmarkManager.preventLoadingForTesting(true); 637 638 openBookmarkManager(); 639 640 BookmarkActionBar toolbar = mManager.getToolbarForTests(); 641 Assert.assertFalse(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible()); 642 643 BookmarkManager.preventLoadingForTesting(false); 644 } 645 646 @Test 647 @MediumTest testEndIconVisibilityInSelectionMode()648 public void testEndIconVisibilityInSelectionMode() throws Exception { 649 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 650 addBookmark(TEST_TITLE_A, TEST_URL_A); 651 652 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 653 openBookmarkManager(); 654 655 BookmarkRow test = 656 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView; 657 View testMoreButton = test.findViewById(R.id.more); 658 View testDragHandle = test.getDragHandleViewForTests(); 659 660 BookmarkRow testFolderA = 661 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 662 View aMoreButton = testFolderA.findViewById(R.id.more); 663 View aDragHandle = testFolderA.getDragHandleViewForTests(); 664 665 toggleSelectionAndEndAnimation(testId, test); 666 667 // Callback occurs when Item "test" is selected. 668 CriteriaHelper.pollUiThread(test::isChecked, "Expected item \"test\" to become selected"); 669 670 Assert.assertEquals("Expected bookmark toolbar to be selection mode", 671 mManager.getToolbarForTests().getCurrentViewType(), ViewType.SELECTION_VIEW); 672 Assert.assertEquals("Expected more button of selected item to be gone when drag is active.", 673 View.GONE, testMoreButton.getVisibility()); 674 Assert.assertEquals( 675 "Expected drag handle of selected item to be visible when drag is active.", 676 View.VISIBLE, testDragHandle.getVisibility()); 677 Assert.assertTrue("Expected drag handle to be enabled when drag is active.", 678 testDragHandle.isEnabled()); 679 680 Assert.assertEquals( 681 "Expected more button of unselected item to be gone when drag is active.", 682 View.GONE, aMoreButton.getVisibility()); 683 Assert.assertEquals( 684 "Expected drag handle of unselected item to be visible when drag is active.", 685 View.VISIBLE, aDragHandle.getVisibility()); 686 Assert.assertFalse( 687 "Expected drag handle of unselected item to be disabled when drag is active.", 688 aDragHandle.isEnabled()); 689 } 690 691 @Test 692 @MediumTest 693 @FlakyTest(message = "crbug.com/1075804") testEndIconVisiblityInSearchMode()694 public void testEndIconVisiblityInSearchMode() throws Exception { 695 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 696 addFolder(TEST_TITLE_A); 697 698 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 699 openBookmarkManager(); 700 701 View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id); 702 703 BookmarkRow test = 704 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView; 705 View testMoreButton = test.findViewById(R.id.more); 706 View testDragHandle = test.getDragHandleViewForTests(); 707 708 BookmarkRow a = (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 709 View aMoreButton = a.findViewById(R.id.more); 710 View aDragHandle = a.getDragHandleViewForTests(); 711 712 TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick); 713 714 // Callback occurs when Item "test" is selected. 715 CriteriaHelper.pollUiThread( 716 () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode"); 717 718 toggleSelectionAndEndAnimation(testId, test); 719 720 // Callback occurs when Item "test" is selected. 721 CriteriaHelper.pollUiThread(test::isChecked, "Expected item \"test\" to become selected"); 722 723 Assert.assertEquals("Expected drag handle of selected item to be gone " 724 + "when selection mode is activated from search.", 725 View.GONE, testDragHandle.getVisibility()); 726 Assert.assertEquals("Expected more button of selected item to be visible " 727 + "when selection mode is activated from search.", 728 View.VISIBLE, testMoreButton.getVisibility()); 729 Assert.assertFalse("Expected more button of selected item to be disabled " 730 + "when selection mode is activated from search.", 731 testMoreButton.isEnabled()); 732 733 Assert.assertEquals("Expected drag handle of unselected item to be gone " 734 + "when selection mode is activated from search.", 735 View.GONE, aDragHandle.getVisibility()); 736 Assert.assertEquals("Expected more button of unselected item to be visible " 737 + "when selection mode is activated from search.", 738 View.VISIBLE, aMoreButton.getVisibility()); 739 Assert.assertFalse("Expected more button of unselected item to be disabled " 740 + "when selection mode is activated from search.", 741 aMoreButton.isEnabled()); 742 } 743 744 @Test 745 @MediumTest testSmallDrag_Up_BookmarksOnly()746 public void testSmallDrag_Up_BookmarksOnly() throws Exception { 747 List<BookmarkId> initial = new ArrayList<>(); 748 List<BookmarkId> expected = new ArrayList<>(); 749 BookmarkId fooId = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo); 750 BookmarkId googleId = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage); 751 BookmarkId aId = addBookmark(TEST_TITLE_A, TEST_URL_A); 752 753 // When bookmarks are added, they are added to the top of the list. 754 // The current bookmark order is the reverse of the order in which they were added. 755 initial.add(aId); 756 initial.add(googleId); 757 initial.add(fooId); 758 759 TestThreadUtils.runOnUiThreadBlocking(() -> { 760 Assert.assertEquals("Bookmarks were not added in the expected order.", initial, 761 mBookmarkModel.getChildIDs(mBookmarkModel.getDefaultFolder()).subList(0, 3)); 762 }); 763 764 expected.add(fooId); 765 expected.add(aId); 766 expected.add(googleId); 767 768 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 769 openBookmarkManager(); 770 771 // Callback occurs upon changes inside of the bookmark model. 772 CallbackHelper modelReorderHelper = new CallbackHelper(); 773 BookmarkBridge.BookmarkModelObserver bookmarkModelObserver = 774 new BookmarkBridge.BookmarkModelObserver() { 775 @Override 776 public void bookmarkModelChanged() { 777 modelReorderHelper.notifyCalled(); 778 } 779 }; 780 781 // Perform registration to make callbacks work. 782 TestThreadUtils.runOnUiThreadBlocking( 783 () -> { mBookmarkModel.addObserver(bookmarkModelObserver); }); 784 785 BookmarkRow foo = 786 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(3).itemView; 787 Assert.assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_FOO, foo.getTitle()); 788 toggleSelectionAndEndAnimation(fooId, foo); 789 790 // Starts as last bookmark (2nd index) and ends as 0th bookmark (promo header not included). 791 TestThreadUtils.runOnUiThreadBlocking(() -> { 792 ((BookmarkItemsAdapter) mItemsContainer.getAdapter()).simulateDragForTests(3, 1); 793 }); 794 795 modelReorderHelper.waitForCallback(0, 1); 796 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 797 798 TestThreadUtils.runOnUiThreadBlocking(() -> { 799 List<BookmarkId> observed = 800 mBookmarkModel.getChildIDs(mBookmarkModel.getDefaultFolder()); 801 // Exclude partner bookmarks folder 802 Assert.assertEquals(expected, observed.subList(0, 3)); 803 Assert.assertTrue("The selected item should stay selected", foo.isItemSelected()); 804 }); 805 } 806 807 @Test 808 @MediumTest testSmallDrag_Down_FoldersOnly()809 public void testSmallDrag_Down_FoldersOnly() throws Exception { 810 List<BookmarkId> initial = new ArrayList<>(); 811 List<BookmarkId> expected = new ArrayList<>(); 812 BookmarkId aId = addFolder("a"); 813 BookmarkId bId = addFolder("b"); 814 BookmarkId cId = addFolder("c"); 815 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 816 817 initial.add(testId); 818 initial.add(cId); 819 initial.add(bId); 820 initial.add(aId); 821 822 TestThreadUtils.runOnUiThreadBlocking(() -> { 823 Assert.assertEquals("Bookmarks were not added in the expected order.", initial, 824 mBookmarkModel.getChildIDs(mBookmarkModel.getDefaultFolder()).subList(0, 4)); 825 }); 826 827 expected.add(cId); 828 expected.add(bId); 829 expected.add(aId); 830 expected.add(testId); 831 832 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 833 openBookmarkManager(); 834 835 // Callback occurs upon changes inside of the bookmark model. 836 CallbackHelper modelReorderHelper = new CallbackHelper(); 837 BookmarkBridge.BookmarkModelObserver bookmarkModelObserver = 838 new BookmarkBridge.BookmarkModelObserver() { 839 @Override 840 public void bookmarkModelChanged() { 841 modelReorderHelper.notifyCalled(); 842 } 843 }; 844 845 // Perform registration to make callbacks work. 846 TestThreadUtils.runOnUiThreadBlocking( 847 () -> { mBookmarkModel.addObserver(bookmarkModelObserver); }); 848 849 BookmarkFolderRow test = 850 (BookmarkFolderRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 851 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, test.getTitle()); 852 853 toggleSelectionAndEndAnimation(testId, test); 854 855 // Starts as 0th bookmark (not counting promo header) and ends as last (index 3). 856 TestThreadUtils.runOnUiThreadBlocking(() -> { 857 ((BookmarkItemsAdapter) mItemsContainer.getAdapter()).simulateDragForTests(1, 4); 858 }); 859 860 modelReorderHelper.waitForCallback(0, 1); 861 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 862 863 TestThreadUtils.runOnUiThreadBlocking(() -> { 864 List<BookmarkId> observed = 865 mBookmarkModel.getChildIDs(mBookmarkModel.getDefaultFolder()); 866 // Exclude partner bookmarks folder 867 Assert.assertEquals(expected, observed.subList(0, 4)); 868 Assert.assertTrue("The selected item should stay selected", test.isItemSelected()); 869 }); 870 } 871 872 @Test 873 @MediumTest testSmallDrag_Down_MixedFoldersAndBookmarks()874 public void testSmallDrag_Down_MixedFoldersAndBookmarks() throws Exception { 875 List<BookmarkId> initial = new ArrayList<>(); 876 List<BookmarkId> expected = new ArrayList<>(); 877 BookmarkId aId = addFolder("a"); 878 BookmarkId bId = addBookmark("b", "http://b.com"); 879 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 880 881 initial.add(testId); 882 initial.add(bId); 883 initial.add(aId); 884 885 TestThreadUtils.runOnUiThreadBlocking(() -> { 886 Assert.assertEquals("Bookmarks were not added in the expected order.", initial, 887 mBookmarkModel.getChildIDs(mBookmarkModel.getDefaultFolder()).subList(0, 3)); 888 }); 889 890 expected.add(bId); 891 expected.add(testId); 892 expected.add(aId); 893 894 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 895 openBookmarkManager(); 896 897 // Callback occurs upon changes inside of the bookmark model. 898 CallbackHelper modelReorderHelper = new CallbackHelper(); 899 BookmarkBridge.BookmarkModelObserver bookmarkModelObserver = 900 new BookmarkBridge.BookmarkModelObserver() { 901 @Override 902 public void bookmarkModelChanged() { 903 modelReorderHelper.notifyCalled(); 904 } 905 }; 906 // Perform registration to make callbacks work. 907 TestThreadUtils.runOnUiThreadBlocking( 908 () -> { mBookmarkModel.addObserver(bookmarkModelObserver); }); 909 910 BookmarkFolderRow test = 911 (BookmarkFolderRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 912 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, test.getTitle()); 913 914 toggleSelectionAndEndAnimation(testId, test); 915 916 // Starts as 0th bookmark (not counting promo header) and ends at the 1st index. 917 TestThreadUtils.runOnUiThreadBlocking(() -> { 918 ((BookmarkItemsAdapter) mItemsContainer.getAdapter()).simulateDragForTests(1, 2); 919 }); 920 921 modelReorderHelper.waitForCallback(0, 1); 922 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 923 924 TestThreadUtils.runOnUiThreadBlocking(() -> { 925 List<BookmarkId> observed = 926 mBookmarkModel.getChildIDs(mBookmarkModel.getDefaultFolder()); 927 // Exclude partner bookmarks folder 928 Assert.assertEquals(expected, observed.subList(0, 3)); 929 Assert.assertTrue("The selected item should stay selected", test.isItemSelected()); 930 }); 931 } 932 933 @Test 934 @MediumTest testPromoDraggability()935 public void testPromoDraggability() throws Exception { 936 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 937 938 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 939 openBookmarkManager(); 940 941 ViewHolder promo = mItemsContainer.findViewHolderForAdapterPosition(0); 942 943 toggleSelectionAndEndAnimation( 944 testId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView); 945 946 BookmarkItemsAdapter adapter = ((BookmarkItemsAdapter) mItemsContainer.getAdapter()); 947 Assert.assertFalse("Promo header should not be passively draggable", 948 adapter.isPassivelyDraggable(promo)); 949 Assert.assertFalse("Promo header should not be actively draggable", 950 adapter.isActivelyDraggable(promo)); 951 } 952 953 @Test 954 @MediumTest testPartnerFolderDraggability()955 public void testPartnerFolderDraggability() throws Exception { 956 BookmarkId testId = addFolderWithPartner(TEST_FOLDER_TITLE); 957 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 958 openBookmarkManager(); 959 960 ViewHolder partner = mItemsContainer.findViewHolderForAdapterPosition(2); 961 962 toggleSelectionAndEndAnimation( 963 testId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView); 964 965 BookmarkItemsAdapter adapter = ((BookmarkItemsAdapter) mItemsContainer.getAdapter()); 966 Assert.assertFalse("Partner bookmarks folder should not be passively draggable", 967 adapter.isPassivelyDraggable(partner)); 968 Assert.assertFalse("Partner bookmarks folder should not be actively draggable", 969 adapter.isActivelyDraggable(partner)); 970 } 971 972 @Test 973 @MediumTest testUnselectedItemDraggability()974 public void testUnselectedItemDraggability() throws Exception { 975 BookmarkId aId = addBookmark("a", "http://a.com"); 976 addFolder(TEST_FOLDER_TITLE); 977 978 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 979 openBookmarkManager(); 980 981 ViewHolder test = mItemsContainer.findViewHolderForAdapterPosition(1); 982 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, 983 ((BookmarkFolderRow) test.itemView).getTitle()); 984 985 toggleSelectionAndEndAnimation( 986 aId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView); 987 988 BookmarkItemsAdapter adapter = ((BookmarkItemsAdapter) mItemsContainer.getAdapter()); 989 Assert.assertTrue("Unselected rows should be passively draggable", 990 adapter.isPassivelyDraggable(test)); 991 Assert.assertFalse("Unselected rows should not be actively draggable", 992 adapter.isActivelyDraggable(test)); 993 } 994 995 @Test 996 @MediumTest testCannotSelectPromo()997 public void testCannotSelectPromo() throws Exception { 998 addFolder(TEST_FOLDER_TITLE); 999 1000 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1001 openBookmarkManager(); 1002 1003 View promo = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1004 TouchCommon.longPressView(promo); 1005 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1006 Assert.assertFalse("Expected that we would not be in selection mode " 1007 + "after long pressing on promo view.", 1008 mManager.getSelectionDelegate().isSelectionEnabled()); 1009 } 1010 1011 @Test 1012 @MediumTest testCannotSelectPartner()1013 public void testCannotSelectPartner() throws Exception { 1014 addFolderWithPartner(TEST_FOLDER_TITLE); 1015 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1016 openBookmarkManager(); 1017 1018 View partner = mItemsContainer.findViewHolderForAdapterPosition(2).itemView; 1019 TouchCommon.longPressView(partner); 1020 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1021 Assert.assertFalse("Expected that we would not be in selection mode " 1022 + "after long pressing on partner bookmark.", 1023 mManager.getSelectionDelegate().isSelectionEnabled()); 1024 } 1025 1026 @Test 1027 @SmallTest 1028 @Features.EnableFeatures({ChromeFeatureList.READ_LATER}) testReadingListItemsInSelectionMode()1029 public void testReadingListItemsInSelectionMode() throws Exception { 1030 addReadingListBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); 1031 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1032 openBookmarkManager(); 1033 TestThreadUtils.runOnUiThreadBlocking( 1034 () -> mManager.openFolder(mBookmarkModel.getRootFolderId())); 1035 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1036 1037 // Open the "Reading list" folder. 1038 onView(withText("Reading list")).perform(click()); 1039 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1040 1041 // Select a reading list item. Verify the toolbar menu buttons being shown. 1042 BookmarkRow bookmarkRow = 1043 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1044 TouchCommon.longPressView(bookmarkRow); 1045 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1046 BookmarkActionBar toolbar = mManager.getToolbarForTests(); 1047 Assert.assertFalse("Read later items shouldn't have move option", 1048 toolbar.getMenu().findItem(R.id.selection_mode_move_menu_id).isVisible()); 1049 Assert.assertFalse("Read later items shouldn't have edit option", 1050 toolbar.getMenu().findItem(R.id.selection_mode_edit_menu_id).isVisible()); 1051 Assert.assertTrue("Read later items should have delete option", 1052 toolbar.getMenu().findItem(R.id.selection_mode_delete_menu_id).isVisible()); 1053 } 1054 1055 @Test 1056 @SmallTest 1057 @Features.EnableFeatures({ChromeFeatureList.READ_LATER}) testReadingListItemMenuItems()1058 public void testReadingListItemMenuItems() throws Exception { 1059 addReadingListBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); 1060 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1061 openBookmarkManager(); 1062 TestThreadUtils.runOnUiThreadBlocking( 1063 () -> mManager.openFolder(mBookmarkModel.getRootFolderId())); 1064 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1065 1066 // Open the "Reading list" folder. 1067 onView(withText("Reading list")).perform(click()); 1068 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1069 1070 // Open the three-dot menu and verify the menu options being shown. 1071 View readingListItem = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1072 View more = readingListItem.findViewById(R.id.more); 1073 1074 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1075 onView(withText("Select")).check(matches(isDisplayed())); 1076 onView(withText("Edit")).check(doesNotExist()); 1077 onView(withText("Delete")).check(matches(isDisplayed())); 1078 onView(withText("Mark as read")).check(matches(isDisplayed())); 1079 onView(withText("Move up")).check(doesNotExist()); 1080 onView(withText("Move down")).check(doesNotExist()); 1081 1082 // Click "Mark as read". The page should be moved to read section. 1083 onView(withText("Mark as read")).perform(click()); 1084 onView(withText("Read")).check(matches(isDisplayed())); 1085 1086 // A read page should not have "Mark as read" menu option. 1087 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1088 onView(withText("Select")).check(matches(isDisplayed())); 1089 onView(withText("Edit")).check(doesNotExist()); 1090 onView(withText("Delete")).check(matches(isDisplayed())); 1091 onView(withText("Mark as read")).check(doesNotExist()); 1092 onView(withText("Move up")).check(doesNotExist()); 1093 onView(withText("Move down")).check(doesNotExist()); 1094 } 1095 1096 @Test 1097 @MediumTest testMoveUpMenuItem()1098 public void testMoveUpMenuItem() throws Exception { 1099 addBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); 1100 addFolder(TEST_FOLDER_TITLE); 1101 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1102 openBookmarkManager(); 1103 1104 View google = mItemsContainer.findViewHolderForAdapterPosition(2).itemView; 1105 Assert.assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_GOOGLE, 1106 ((BookmarkItemRow) google).getTitle()); 1107 View more = google.findViewById(R.id.more); 1108 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1109 onView(withText("Move up")).perform(click()); 1110 1111 // Confirm that the "Google" bookmark is now on top, and that the "test" folder is 2nd 1112 Assert.assertTrue( 1113 ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView) 1114 .getTitle() 1115 .equals(TEST_PAGE_TITLE_GOOGLE)); 1116 Assert.assertTrue( 1117 ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView) 1118 .getTitle() 1119 .equals(TEST_FOLDER_TITLE)); 1120 } 1121 1122 @Test 1123 @MediumTest testMoveDownMenuItem()1124 public void testMoveDownMenuItem() throws Exception { 1125 addBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); 1126 addFolder(TEST_FOLDER_TITLE); 1127 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1128 openBookmarkManager(); 1129 1130 View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1131 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, 1132 ((BookmarkFolderRow) testFolder).getTitle()); 1133 ListMenuButton more = testFolder.findViewById(R.id.more); 1134 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1135 onView(withText("Move down")).perform(click()); 1136 1137 // Confirm that the "Google" bookmark is now on top, and that the "test" folder is 2nd 1138 Assert.assertTrue( 1139 ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView) 1140 .getTitle() 1141 .equals(TEST_PAGE_TITLE_GOOGLE)); 1142 Assert.assertTrue( 1143 ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView) 1144 .getTitle() 1145 .equals(TEST_FOLDER_TITLE)); 1146 } 1147 1148 @Test 1149 @MediumTest testMoveDownGoneForBottomElement()1150 public void testMoveDownGoneForBottomElement() throws Exception { 1151 addBookmarkWithPartner(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); 1152 addFolderWithPartner(TEST_FOLDER_TITLE); 1153 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1154 openBookmarkManager(); 1155 1156 View google = mItemsContainer.findViewHolderForAdapterPosition(2).itemView; 1157 Assert.assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_GOOGLE, 1158 ((BookmarkItemRow) google).getTitle()); 1159 View more = google.findViewById(R.id.more); 1160 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1161 onView(withText("Move down")).check(doesNotExist()); 1162 } 1163 1164 @Test 1165 @MediumTest testMoveUpGoneForTopElement()1166 public void testMoveUpGoneForTopElement() throws Exception { 1167 addBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); 1168 addFolder(TEST_FOLDER_TITLE); 1169 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1170 openBookmarkManager(); 1171 1172 View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1173 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, 1174 ((BookmarkFolderRow) testFolder).getTitle()); 1175 ListMenuButton more = testFolder.findViewById(R.id.more); 1176 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1177 onView(withText("Move up")).check(doesNotExist()); 1178 } 1179 1180 @Test 1181 @MediumTest 1182 @DisabledTest(message = "crbug.com/1046653") testMoveButtonsGoneInSearchMode()1183 public void testMoveButtonsGoneInSearchMode() throws Exception { 1184 addFolder(TEST_FOLDER_TITLE); 1185 openBookmarkManager(); 1186 1187 View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id); 1188 TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick); 1189 1190 // Callback occurs when Item "test" is selected. 1191 CriteriaHelper.pollUiThread( 1192 () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode"); 1193 1194 View testFolder = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1195 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, 1196 ((BookmarkFolderRow) testFolder).getTitle()); 1197 View more = testFolder.findViewById(R.id.more); 1198 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1199 1200 onView(withText("Move up")).check(doesNotExist()); 1201 onView(withText("Move down")).check(doesNotExist()); 1202 } 1203 1204 @Test 1205 @MediumTest testMoveButtonsGoneWithOneBookmark()1206 public void testMoveButtonsGoneWithOneBookmark() throws Exception { 1207 addFolder(TEST_FOLDER_TITLE); 1208 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1209 openBookmarkManager(); 1210 1211 View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1212 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, 1213 ((BookmarkFolderRow) testFolder).getTitle()); 1214 View more = testFolder.findViewById(R.id.more); 1215 TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); 1216 1217 onView(withText("Move up")).check(doesNotExist()); 1218 onView(withText("Move down")).check(doesNotExist()); 1219 } 1220 1221 @Test 1222 @MediumTest testMoveButtonsGoneForPartnerBookmarks()1223 public void testMoveButtonsGoneForPartnerBookmarks() throws Exception { 1224 loadFakePartnerBookmarkShimForTesting(); 1225 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1226 openBookmarkManager(); 1227 1228 // Open partner bookmarks folder. 1229 TestThreadUtils.runOnUiThreadBlocking( 1230 () -> mManager.openFolder(mBookmarkModel.getPartnerFolderId())); 1231 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1232 1233 Assert.assertEquals("Wrong number of items in partner bookmark folder.", 2, 1234 getAdapter().getItemCount()); 1235 1236 // Verify that bookmark 1 is editable (so more button can be triggered) but not movable. 1237 BookmarkId partnerBookmarkId1 = getReorderAdapter().getIdByPosition(0); 1238 TestThreadUtils.runOnUiThreadBlocking(() -> { 1239 BookmarkBridge.BookmarkItem partnerBookmarkItem1 = 1240 mBookmarkModel.getBookmarkById(partnerBookmarkId1); 1241 partnerBookmarkItem1.forceEditableForTesting(); 1242 Assert.assertEquals("Incorrect bookmark type for item 1", BookmarkType.PARTNER, 1243 partnerBookmarkId1.getType()); 1244 Assert.assertFalse( 1245 "Partner item 1 should not be movable", partnerBookmarkItem1.isMovable()); 1246 Assert.assertTrue( 1247 "Partner item 1 should be editable", partnerBookmarkItem1.isEditable()); 1248 }); 1249 1250 // Verify that bookmark 2 is editable (so more button can be triggered) but not movable. 1251 View partnerBookmarkView1 = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1252 View more1 = partnerBookmarkView1.findViewById(R.id.more); 1253 TestThreadUtils.runOnUiThreadBlocking(more1::callOnClick); 1254 onView(withText("Move up")).check(doesNotExist()); 1255 onView(withText("Move down")).check(doesNotExist()); 1256 1257 // Verify that bookmark 2 is not movable. 1258 BookmarkId partnerBookmarkId2 = getReorderAdapter().getIdByPosition(1); 1259 TestThreadUtils.runOnUiThreadBlocking(() -> { 1260 BookmarkBridge.BookmarkItem partnerBookmarkItem2 = 1261 mBookmarkModel.getBookmarkById(partnerBookmarkId2); 1262 partnerBookmarkItem2.forceEditableForTesting(); 1263 Assert.assertEquals("Incorrect bookmark type for item 2", BookmarkType.PARTNER, 1264 partnerBookmarkId2.getType()); 1265 Assert.assertFalse( 1266 "Partner item 2 should not be movable", partnerBookmarkItem2.isMovable()); 1267 Assert.assertTrue( 1268 "Partner item 2 should be editable", partnerBookmarkItem2.isEditable()); 1269 }); 1270 1271 // Verify that bookmark 2 does not have move up/down items. 1272 View partnerBookmarkView2 = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1273 View more2 = partnerBookmarkView2.findViewById(R.id.more); 1274 TestThreadUtils.runOnUiThreadBlocking(more2::callOnClick); 1275 onView(withText("Move up")).check(doesNotExist()); 1276 onView(withText("Move down")).check(doesNotExist()); 1277 } 1278 1279 @Test 1280 @MediumTest testTopLevelFolderUpdateAfterSync()1281 public void testTopLevelFolderUpdateAfterSync() throws Exception { 1282 // Set up the test and open the bookmark manager to the Mobile Bookmarks folder. 1283 readPartnerBookmarks(); 1284 openBookmarkManager(); 1285 BookmarkItemsAdapter adapter = getReorderAdapter(); 1286 1287 // Open the root folder. 1288 TestThreadUtils.runOnUiThreadBlocking( 1289 () -> mManager.openFolder(mBookmarkModel.getRootFolderId())); 1290 1291 // Add a bookmark to the Other Bookmarks folder. 1292 TestThreadUtils.runOnUiThreadBlocking(() -> { 1293 mBookmarkModel.addBookmark( 1294 mBookmarkModel.getOtherFolderId(), 0, TEST_TITLE_A, TEST_URL_A); 1295 }); 1296 1297 TestThreadUtils.runOnUiThreadBlocking(adapter::simulateSignInForTests); 1298 Assert.assertEquals("Expected promo and \"Other Bookmarks\" folder to appear!", 3, 1299 adapter.getItemCount()); 1300 } 1301 1302 @Test 1303 @MediumTest testShowInFolder_NoScroll()1304 public void testShowInFolder_NoScroll() throws Exception { 1305 addFolder(TEST_FOLDER_TITLE); 1306 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1307 openBookmarkManager(); 1308 1309 // Enter search mode. 1310 enterSearch(); 1311 1312 // Click "Show in folder". 1313 View testFolder = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1314 clickMoreButtonOnFirstItem(TEST_FOLDER_TITLE); 1315 onView(withText("Show in folder")).perform(click()); 1316 1317 // Assert that the view pulses. 1318 Assert.assertTrue("Expected bookmark row to pulse after clicking \"show in folder\"!", 1319 checkHighlightPulse(testFolder)); 1320 1321 // Enter search mode again. 1322 enterSearch(); 1323 1324 Assert.assertTrue("Expected bookmark row to not be highlighted " 1325 + "after entering search mode", 1326 checkHighlightOff(testFolder)); 1327 1328 // Click "Show in folder" again. 1329 clickMoreButtonOnFirstItem(TEST_FOLDER_TITLE); 1330 onView(withText("Show in folder")).perform(click()); 1331 Assert.assertTrue( 1332 "Expected bookmark row to pulse after clicking \"show in folder\" a 2nd time!", 1333 checkHighlightPulse(testFolder)); 1334 } 1335 1336 @Test 1337 @MediumTest testShowInFolder_Scroll()1338 public void testShowInFolder_Scroll() throws Exception { 1339 addFolder(TEST_FOLDER_TITLE); // Index 8 1340 addBookmark(TEST_TITLE_A, TEST_URL_A); 1341 addBookmark(TEST_PAGE_TITLE_FOO, "http://foo.com"); 1342 addFolder(TEST_PAGE_TITLE_GOOGLE2); 1343 addFolder("B"); 1344 addFolder("C"); 1345 addFolder("D"); 1346 addFolder("E"); // Index 1 1347 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1348 openBookmarkManager(); 1349 1350 // Enter search mode. 1351 enterSearch(); 1352 1353 TestThreadUtils.runOnUiThreadBlocking( 1354 () -> mManager.onSearchTextChanged(TEST_FOLDER_TITLE)); 1355 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1356 1357 // This should be the only (& therefore 0-indexed) item. 1358 clickMoreButtonOnFirstItem(TEST_FOLDER_TITLE); 1359 1360 // Show in folder. 1361 onView(withText("Show in folder")).perform(click()); 1362 1363 // This should be in the 8th position now. 1364 ViewHolder testFolderInList = mItemsContainer.findViewHolderForAdapterPosition(8); 1365 Assert.assertFalse( 1366 "Expected list to scroll bookmark item into view", testFolderInList == null); 1367 Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, 1368 ((BookmarkFolderRow) testFolderInList.itemView).getTitle()); 1369 Assert.assertTrue("Expected highlight to pulse on after scrolling to the item!", 1370 checkHighlightPulse(testFolderInList.itemView)); 1371 } 1372 1373 @Test 1374 @MediumTest testShowInFolder_OpenOtherFolder()1375 public void testShowInFolder_OpenOtherFolder() throws Exception { 1376 BookmarkId testId = addFolder(TEST_FOLDER_TITLE); 1377 TestThreadUtils.runOnUiThreadBlocking( 1378 () -> mBookmarkModel.addBookmark(testId, 0, TEST_TITLE_A, TEST_URL_A)); 1379 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_SYNC); 1380 openBookmarkManager(); 1381 1382 // Enter search mode. 1383 enterSearch(); 1384 TestThreadUtils.runOnUiThreadBlocking(() -> mManager.onSearchTextChanged(TEST_URL_A)); 1385 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1386 1387 // This should be the only (& therefore 0-indexed) item. 1388 clickMoreButtonOnFirstItem(TEST_TITLE_A); 1389 1390 // Show in folder. 1391 onView(withText("Show in folder")).perform(click()); 1392 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1393 1394 // Make sure that we're in the right folder (index 1 because of promo). 1395 View itemA = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1396 Assert.assertEquals("Wrong bookmark item selected.", TEST_TITLE_A, 1397 ((BookmarkItemRow) itemA).getTitle()); 1398 1399 Assert.assertTrue("Expected highlight to pulse after opening an item in another folder!", 1400 checkHighlightPulse(itemA)); 1401 1402 // Open mobile bookmarks folder, then go back to the subfolder. 1403 TestThreadUtils.runOnUiThreadBlocking(() -> { 1404 mManager.openFolder(mBookmarkModel.getMobileFolderId()); 1405 mManager.openFolder(testId); 1406 }); 1407 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1408 1409 View itemASecondView = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1410 Assert.assertEquals("Wrong bookmark item selected.", TEST_TITLE_A, 1411 ((BookmarkItemRow) itemASecondView).getTitle()); 1412 Assert.assertTrue( 1413 "Expected highlight to not be highlighted after exiting and re-entering folder!", 1414 checkHighlightOff(itemASecondView)); 1415 } 1416 1417 @Test 1418 @SmallTest testAddBookmarkInBackgroundWithSelection()1419 public void testAddBookmarkInBackgroundWithSelection() throws Exception { 1420 BookmarkId folder = addFolder(TEST_FOLDER_TITLE); 1421 BookmarkId id = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder); 1422 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1423 openBookmarkManager(); 1424 1425 // Open the new folder where these bookmarks were created. 1426 openFolder(folder); 1427 1428 Assert.assertEquals(1, getAdapter().getItemCount()); 1429 BookmarkRow row = 1430 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1431 toggleSelectionAndEndAnimation(id, row); 1432 CallbackHelper helper = new CallbackHelper(); 1433 getAdapter().registerAdapterDataObserver(new AdapterDataObserver() { 1434 @Override 1435 public void onChanged() { 1436 helper.notifyCalled(); 1437 } 1438 }); 1439 1440 TestThreadUtils.runOnUiThreadBlocking(() -> { 1441 mBookmarkModel.addBookmark(folder, 1, TEST_PAGE_TITLE_GOOGLE, mTestPage); 1442 }); 1443 1444 helper.waitForCallback(0, 1); 1445 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1446 TestThreadUtils.runOnUiThreadBlocking(() -> { 1447 Assert.assertTrue(isItemPresentInBookmarkList(TEST_PAGE_TITLE_FOO)); 1448 Assert.assertTrue(isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE)); 1449 Assert.assertEquals(2, getAdapter().getItemCount()); 1450 Assert.assertTrue("The selected row should be kept selected", row.isItemSelected()); 1451 }); 1452 } 1453 1454 @Test 1455 @SmallTest testDeleteAllSelectedBookmarksInBackground()1456 public void testDeleteAllSelectedBookmarksInBackground() throws Exception { 1457 // Select one bookmark and then remove that in background. 1458 // In the meantime, the toolbar changes from selection mode to normal mode. 1459 BookmarkId folder = addFolder(TEST_FOLDER_TITLE); 1460 BookmarkId fooId = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder); 1461 BookmarkId googleId = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder); 1462 BookmarkId aId = addBookmark(TEST_TITLE_A, TEST_URL_A, folder); 1463 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1464 openBookmarkManager(); 1465 1466 // Open the new folder where these bookmarks were created. 1467 openFolder(folder); 1468 1469 Assert.assertEquals(3, getAdapter().getItemCount()); 1470 BookmarkRow row = 1471 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1472 toggleSelectionAndEndAnimation(googleId, row); 1473 CallbackHelper helper = new CallbackHelper(); 1474 mManager.getSelectionDelegate().addObserver((x) -> { helper.notifyCalled(); }); 1475 1476 removeBookmark(googleId); 1477 1478 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1479 helper.waitForCallback(0, 1); 1480 TestThreadUtils.runOnUiThreadBlocking(() -> { 1481 Assert.assertFalse( 1482 "Item is not deleted", isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE)); 1483 Assert.assertEquals(2, getReorderAdapter().getItemCount()); 1484 Assert.assertEquals("Bookmark View should be back to normal view", 1485 mManager.getToolbarForTests().getCurrentViewType(), ViewType.NORMAL_VIEW); 1486 }); 1487 } 1488 1489 @Test 1490 @SmallTest testDeleteSomeSelectedBookmarksInBackground()1491 public void testDeleteSomeSelectedBookmarksInBackground() throws Exception { 1492 // selected on bookmarks and then remove one of them in background 1493 // in the meantime, the toolbar stays in selection mode 1494 BookmarkId folder = addFolder(TEST_FOLDER_TITLE); 1495 BookmarkId fooId = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder); 1496 BookmarkId googleId = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder); 1497 BookmarkId aId = addBookmark(TEST_TITLE_A, TEST_URL_A, folder); 1498 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1499 openBookmarkManager(); 1500 1501 // Open the new folder where these bookmarks were created. 1502 openFolder(folder); 1503 1504 Assert.assertEquals(3, getAdapter().getItemCount()); 1505 BookmarkRow row = 1506 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView; 1507 toggleSelectionAndEndAnimation(googleId, row); 1508 BookmarkRow aRow = 1509 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1510 toggleSelectionAndEndAnimation(aId, aRow); 1511 CallbackHelper helper = new CallbackHelper(); 1512 mManager.getSelectionDelegate().addObserver((x) -> { helper.notifyCalled(); }); 1513 1514 removeBookmark(googleId); 1515 1516 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1517 helper.waitForCallback(0, 1); 1518 TestThreadUtils.runOnUiThreadBlocking(() -> { 1519 Assert.assertFalse( 1520 "Item is not deleted", isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE)); 1521 Assert.assertEquals(2, getReorderAdapter().getItemCount()); 1522 Assert.assertTrue("Item selected should not be cleared", aRow.isItemSelected()); 1523 Assert.assertEquals("Should stay in selection mode because there is one selected", 1524 mManager.getToolbarForTests().getCurrentViewType(), ViewType.SELECTION_VIEW); 1525 }); 1526 } 1527 1528 @Test 1529 @SmallTest testUpdateSelectedBookmarkInBackground()1530 public void testUpdateSelectedBookmarkInBackground() throws Exception { 1531 BookmarkId folder = addFolder(TEST_FOLDER_TITLE); 1532 BookmarkId id = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder); 1533 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1534 openBookmarkManager(); 1535 1536 // Open the new folder where these bookmarks were created. 1537 openFolder(folder); 1538 1539 Assert.assertEquals(1, getAdapter().getItemCount()); 1540 BookmarkRow row = 1541 (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1542 toggleSelectionAndEndAnimation(id, row); 1543 CallbackHelper helper = new CallbackHelper(); 1544 TestThreadUtils.runOnUiThreadBlocking( 1545 () -> mBookmarkModel.addObserver(new BookmarkModelObserver() { 1546 @Override 1547 public void bookmarkModelChanged() { 1548 helper.notifyCalled(); 1549 } 1550 })); 1551 1552 TestThreadUtils.runOnUiThreadBlocking( 1553 () -> mBookmarkModel.setBookmarkTitle(id, TEST_PAGE_TITLE_GOOGLE)); 1554 1555 helper.waitForCallback(0, 1); 1556 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1557 TestThreadUtils.runOnUiThreadBlocking(() -> { 1558 Assert.assertFalse(isItemPresentInBookmarkList(TEST_PAGE_TITLE_FOO)); 1559 Assert.assertTrue(isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE)); 1560 Assert.assertEquals(1, getAdapter().getItemCount()); 1561 Assert.assertTrue("The selected row should stay selected", row.isItemSelected()); 1562 }); 1563 } 1564 1565 /** 1566 * Verifies the top level elements with the reading list folder. 1567 * Layout: 1568 * - Reading list folder. 1569 * - Divider 1570 * - Mobile bookmark folder. 1571 */ 1572 @Test 1573 @SmallTest 1574 @Features.EnableFeatures({ChromeFeatureList.READ_LATER}) testReadingListFolderShown()1575 public void testReadingListFolderShown() throws Exception { 1576 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1577 openBookmarkManager(); 1578 TestThreadUtils.runOnUiThreadBlocking( 1579 () -> mManager.openFolder(mBookmarkModel.getRootFolderId())); 1580 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1581 Assert.assertEquals("Wrong number of top level elements.", 3, getAdapter().getItemCount()); 1582 1583 // Reading list should show in the root folder. 1584 View readingListRow = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1585 Assert.assertEquals("No overflow menu for reading list folder.", View.GONE, 1586 readingListRow.findViewById(R.id.more).getVisibility()); 1587 Assert.assertEquals("The 1st view should be reading list.", BookmarkType.READING_LIST, 1588 getIdByPosition(0).getType()); 1589 onView(withText("Reading list")).check(matches(isDisplayed())); 1590 1591 Assert.assertEquals("The 2nd view should be a divider.", BookmarkListEntry.ViewType.DIVIDER, 1592 getAdapter().getItemViewType(1)); 1593 Assert.assertEquals("The 3rd view should be a normal folder.", 1594 BookmarkListEntry.ViewType.FOLDER, getAdapter().getItemViewType(2)); 1595 } 1596 1597 @Test 1598 @SmallTest 1599 @Features.EnableFeatures({ChromeFeatureList.READ_LATER}) testReadingListFolderShownOneUnreadPage()1600 public void testReadingListFolderShownOneUnreadPage() throws Exception { 1601 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1602 openBookmarkManager(); 1603 TestThreadUtils.runOnUiThreadBlocking(() -> { 1604 mBookmarkModel.addToReadingList("a", "https://a.com/reading_list_0"); 1605 mManager.openFolder(mBookmarkModel.getRootFolderId()); 1606 }); 1607 onView(withText("Reading list")).check(matches(isDisplayed())); 1608 onView(withText("1 unread page")).check(matches(isDisplayed())); 1609 } 1610 1611 @Test 1612 @SmallTest 1613 @Features.EnableFeatures({ChromeFeatureList.READ_LATER}) testReadingListFolderShownMultipleUnreadPages()1614 public void testReadingListFolderShownMultipleUnreadPages() throws Exception { 1615 BookmarkPromoHeader.forcePromoStateForTests(PromoState.PROMO_NONE); 1616 openBookmarkManager(); 1617 TestThreadUtils.runOnUiThreadBlocking(() -> { 1618 mBookmarkModel.addToReadingList("a", "https://a.com/reading_list_0"); 1619 mBookmarkModel.addToReadingList("b", "https://a.com/reading_list_1"); 1620 mManager.openFolder(mBookmarkModel.getRootFolderId()); 1621 }); 1622 onView(withText("Reading list")).check(matches(isDisplayed())); 1623 onView(withText("2 unread pages")).check(matches(isDisplayed())); 1624 } 1625 1626 @Test 1627 @MediumTest 1628 @Features.EnableFeatures({ChromeFeatureList.READ_LATER}) testAddReadingListItemFromBottomSheet()1629 public void testAddReadingListItemFromBottomSheet() throws Exception { 1630 mActivityTestRule.loadUrl(mTestPage); 1631 TestThreadUtils.runOnUiThreadBlocking( 1632 () -> mBookmarkModel.loadEmptyPartnerBookmarkShimForTesting()); 1633 BookmarkTestUtil.waitForBookmarkModelLoaded(); 1634 1635 // Click the star icon to trigger bookmark bottom sheet. 1636 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 1637 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); 1638 1639 // Click the reading list folder in the bottom sheet, and wait for reading list item added. 1640 onView(withText("Reading list")).check(matches(isDisplayed())).perform(click()); 1641 CriteriaHelper.pollUiThread(() -> mBookmarkModel.getReadingListItem(mTestPage) != null); 1642 1643 TestThreadUtils.runOnUiThreadBlocking(() -> { 1644 // Check reading list item states. 1645 BookmarkItem readingListItem = mBookmarkModel.getReadingListItem(mTestPage); 1646 Assert.assertEquals(mTestPage, readingListItem.getUrl()); 1647 Assert.assertEquals(TEST_PAGE_TITLE_GOOGLE, readingListItem.getTitle()); 1648 Assert.assertFalse(readingListItem.isRead()); 1649 1650 // Snackbar has been shown. 1651 SnackbarManager snackbarManager = mActivityTestRule.getActivity().getSnackbarManager(); 1652 Snackbar currentSnackbar = snackbarManager.getCurrentSnackbarForTesting(); 1653 Assert.assertEquals("Add to reading list snackbar not shown.", 1654 Snackbar.UMA_READING_LIST_BOOKMARK_ADDED, 1655 currentSnackbar.getIdentifierForTesting()); 1656 }); 1657 1658 waitForOfflinePageSaved(mTestPage); 1659 1660 // Click the star button again to launch the edit activity. 1661 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 1662 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); 1663 waitForEditActivity(); 1664 } 1665 1666 @Test 1667 @MediumTest 1668 @EnableFeatures({ChromeFeatureList.READ_LATER, 1669 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR + "<Study"}) 1670 @CommandLineFlags.Add({"force-fieldtrials=Study/Group", 1671 "force-fieldtrial-params=Study.Group:three_button_action_bar/add_to_option"}) 1672 public void testAddReadingListItemFromAddToOption()1673 testAddReadingListItemFromAddToOption() throws Exception { 1674 mActivityTestRule.loadUrl(mTestPage); 1675 TestThreadUtils.runOnUiThreadBlocking( 1676 () -> mBookmarkModel.loadEmptyPartnerBookmarkShimForTesting()); 1677 BookmarkTestUtil.waitForBookmarkModelLoaded(); 1678 1679 MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), 1680 mActivityTestRule.getActivity(), R.id.add_to_reading_list_menu_id); 1681 CriteriaHelper.pollUiThread(() -> mBookmarkModel.getReadingListItem(mTestPage) != null); 1682 TestThreadUtils.runOnUiThreadBlocking(() -> { 1683 // Check reading list item states. 1684 BookmarkItem readingListItem = mBookmarkModel.getReadingListItem(mTestPage); 1685 Assert.assertEquals(mTestPage, readingListItem.getUrl()); 1686 Assert.assertEquals(TEST_PAGE_TITLE_GOOGLE, readingListItem.getTitle()); 1687 Assert.assertFalse(readingListItem.isRead()); 1688 1689 // Reading list snackbar has shown. 1690 SnackbarManager snackbarManager = mActivityTestRule.getActivity().getSnackbarManager(); 1691 Snackbar currentSnackbar = snackbarManager.getCurrentSnackbarForTesting(); 1692 Assert.assertEquals("Add to reading list snackbar not shown.", 1693 Snackbar.UMA_READING_LIST_BOOKMARK_ADDED, 1694 currentSnackbar.getIdentifierForTesting()); 1695 }); 1696 } 1697 1698 1699 /** 1700 * Adds a bookmark in the scenario where we have partner bookmarks. 1701 * 1702 * @param title The title of the bookmark to add. 1703 * @param url The url of the bookmark to add. 1704 * @return The BookmarkId of the added bookmark. 1705 * @throws ExecutionException If something goes wrong while we are trying to add the bookmark. 1706 */ addBookmarkWithPartner(String title, String url)1707 private BookmarkId addBookmarkWithPartner(String title, String url) throws ExecutionException { 1708 loadEmptyPartnerBookmarksForTesting(); 1709 return TestThreadUtils.runOnUiThreadBlocking( 1710 () -> mBookmarkModel.addBookmark(mBookmarkModel.getDefaultFolder(), 0, title, url)); 1711 } 1712 1713 /** 1714 * Adds a folder in the scenario where we have partner bookmarks. 1715 * 1716 * @param title The title of the folder to add. 1717 * @return The BookmarkId of the added folder. 1718 * @throws ExecutionException If something goes wrong while we are trying to add the bookmark. 1719 */ addFolderWithPartner(String title)1720 private BookmarkId addFolderWithPartner(String title) throws ExecutionException { 1721 loadEmptyPartnerBookmarksForTesting(); 1722 return TestThreadUtils.runOnUiThreadBlocking( 1723 () -> mBookmarkModel.addFolder(mBookmarkModel.getDefaultFolder(), 0, title)); 1724 } 1725 getReorderAdapter()1726 private BookmarkItemsAdapter getReorderAdapter() { 1727 return (BookmarkItemsAdapter) getAdapter(); 1728 } 1729 enterSearch()1730 private void enterSearch() throws Exception { 1731 View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id); 1732 TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick); 1733 CriteriaHelper.pollUiThread( 1734 () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode"); 1735 } 1736 clickMoreButtonOnFirstItem(String expectedBookmarkItemTitle)1737 private void clickMoreButtonOnFirstItem(String expectedBookmarkItemTitle) throws Exception { 1738 View firstItem = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; 1739 Assert.assertEquals("Wrong bookmark item selected.", expectedBookmarkItemTitle, 1740 firstItem instanceof BookmarkItemRow ? ((BookmarkItemRow) firstItem).getTitle() 1741 : ((BookmarkFolderRow) firstItem).getTitle()); 1742 View more = firstItem.findViewById(R.id.more); 1743 TestThreadUtils.runOnUiThreadBlocking(more::performClick); 1744 } 1745 1746 /** 1747 * Returns the View that has the given text. 1748 * 1749 * @param viewGroup The group to which the view belongs. 1750 * @param expectedText The expected description text. 1751 * @return The unique view, if one exists. Throws an exception if one doesn't exist. 1752 */ getViewWithText(final ViewGroup viewGroup, final String expectedText)1753 private static View getViewWithText(final ViewGroup viewGroup, final String expectedText) { 1754 return TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<View>() { 1755 @Override 1756 public View call() { 1757 ArrayList<View> outViews = new ArrayList<>(); 1758 ArrayList<View> matchingViews = new ArrayList<>(); 1759 viewGroup.findViewsWithText(outViews, expectedText, View.FIND_VIEWS_WITH_TEXT); 1760 // outViews includes all views whose text contains expectedText as a 1761 // case-insensitive substring. Filter these views to find only exact string matches. 1762 for (View v : outViews) { 1763 if (TextUtils.equals(((TextView) v).getText().toString(), expectedText)) { 1764 matchingViews.add(v); 1765 } 1766 } 1767 Assert.assertEquals("Exactly one item should be present.", 1, matchingViews.size()); 1768 return matchingViews.get(0); 1769 } 1770 }); 1771 } 1772 1773 private void toggleSelectionAndEndAnimation(BookmarkId id, BookmarkRow view) { 1774 TestThreadUtils.runOnUiThreadBlocking(() -> { 1775 mManager.getSelectionDelegate().toggleSelectionForItem(id); 1776 view.endAnimationsForTests(); 1777 mManager.getToolbarForTests().endAnimationsForTesting(); 1778 }); 1779 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1780 } 1781 1782 private BookmarkId addBookmark(final String title, final String url, BookmarkId parent) 1783 throws ExecutionException { 1784 readPartnerBookmarks(); 1785 return TestThreadUtils.runOnUiThreadBlocking( 1786 () -> mBookmarkModel.addBookmark(parent, 0, title, url)); 1787 } 1788 1789 private BookmarkId addBookmark(final String title, final String url) throws ExecutionException { 1790 readPartnerBookmarks(); 1791 return TestThreadUtils.runOnUiThreadBlocking( 1792 () -> mBookmarkModel.addBookmark(mBookmarkModel.getDefaultFolder(), 0, title, url)); 1793 } 1794 1795 private BookmarkId addReadingListBookmark(final String title, final String url) 1796 throws ExecutionException { 1797 readPartnerBookmarks(); 1798 return TestThreadUtils.runOnUiThreadBlocking( 1799 () -> mBookmarkModel.addToReadingList(title, url)); 1800 } 1801 1802 private BookmarkId addFolder(final String title) throws ExecutionException { 1803 readPartnerBookmarks(); 1804 return TestThreadUtils.runOnUiThreadBlocking( 1805 () -> mBookmarkModel.addFolder(mBookmarkModel.getDefaultFolder(), 0, title)); 1806 } 1807 1808 private BookmarkId addFolder(final String title, BookmarkId parent) throws ExecutionException { 1809 readPartnerBookmarks(); 1810 return TestThreadUtils.runOnUiThreadBlocking( 1811 () -> mBookmarkModel.addFolder(parent, 0, title)); 1812 } 1813 1814 private void removeBookmark(final BookmarkId bookmarkId) { 1815 TestThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.deleteBookmark(bookmarkId)); 1816 } 1817 1818 private RecyclerView.Adapter getAdapter() { 1819 return mItemsContainer.getAdapter(); 1820 } 1821 1822 private BookmarkManager getBookmarkManager() { 1823 return (BookmarkManager) getReorderAdapter().getDelegateForTesting(); 1824 } 1825 1826 private BookmarkId getIdByPosition(int pos) { 1827 return getReorderAdapter().getIdByPosition(pos); 1828 } 1829 1830 private void searchBookmarks(final String query) { 1831 TestThreadUtils.runOnUiThreadBlocking(() -> getReorderAdapter().search(query)); 1832 } 1833 1834 private void openFolder(BookmarkId folder) { 1835 final BookmarkDelegate delegate = getBookmarkManager(); 1836 TestThreadUtils.runOnUiThreadBlocking(() -> delegate.openFolder(folder)); 1837 RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); 1838 } 1839 1840 private void waitForEditActivity() { 1841 CriteriaHelper.pollUiThread(() -> { 1842 Criteria.checkThat(ApplicationStatus.getLastTrackedFocusedActivity(), 1843 IsInstanceOf.instanceOf(BookmarkEditActivity.class)); 1844 }); 1845 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 1846 } 1847 1848 private ChromeTabbedActivity waitForTabbedActivity() { 1849 CriteriaHelper.pollUiThread(() -> { 1850 Criteria.checkThat(ApplicationStatus.getLastTrackedFocusedActivity(), 1851 IsInstanceOf.instanceOf(ChromeTabbedActivity.class)); 1852 }); 1853 return (ChromeTabbedActivity) ApplicationStatus.getLastTrackedFocusedActivity(); 1854 } 1855 } 1856