blob: 565e6b340aaf9de11dc2c77a4d16c5094eafa8df [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.app.bookmarks;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.pressBack;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
import static org.chromium.components.browser_ui.widget.highlight.ViewHighlighterTestUtils.checkHighlightOff;
import static org.chromium.components.browser_ui.widget.highlight.ViewHighlighterTestUtils.checkHighlightPulse;
import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.lifecycle.Stage;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.params.ParameterAnnotations;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.ApplicationTestUtils;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.DoNotBatch;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.metrics.LaunchCauseMetrics;
import org.chromium.chrome.browser.bookmarks.BookmarkDelegate;
import org.chromium.chrome.browser.bookmarks.BookmarkFolderRow;
import org.chromium.chrome.browser.bookmarks.BookmarkItemRow;
import org.chromium.chrome.browser.bookmarks.BookmarkManagerCoordinator;
import org.chromium.chrome.browser.bookmarks.BookmarkModel;
import org.chromium.chrome.browser.bookmarks.BookmarkModelObserver;
import org.chromium.chrome.browser.bookmarks.BookmarkPage;
import org.chromium.chrome.browser.bookmarks.BookmarkPromoHeader;
import org.chromium.chrome.browser.bookmarks.BookmarkRow;
import org.chromium.chrome.browser.bookmarks.BookmarkToolbar;
import org.chromium.chrome.browser.bookmarks.BookmarkUiState;
import org.chromium.chrome.browser.bookmarks.BookmarkUiState.BookmarkUiMode;
import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
import org.chromium.chrome.browser.bookmarks.PowerBookmarkShoppingItemRow;
import org.chromium.chrome.browser.bookmarks.TestingDelegate;
import org.chromium.chrome.browser.commerce.ShoppingFeatures;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.sync.SyncService;
import org.chromium.chrome.browser.sync.SyncService.SyncStateChangedListener;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.ui.signin.SyncPromoController.SyncPromoState;
import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.R;
import org.chromium.chrome.test.util.ActivityTestUtils;
import org.chromium.chrome.test.util.BookmarkTestUtil;
import org.chromium.chrome.test.util.ChromeRenderTestRule;
import org.chromium.chrome.test.util.MenuUtils;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.bookmarks.BookmarkId;
import org.chromium.components.bookmarks.BookmarkItem;
import org.chromium.components.bookmarks.BookmarkType;
import org.chromium.components.browser_ui.widget.RecyclerViewTestUtils;
import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableRecyclerViewAdapter;
import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
import org.chromium.components.browser_ui.widget.selectable_list.SelectableListToolbar;
import org.chromium.components.browser_ui.widget.selectable_list.SelectableListToolbar.ViewType;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.power_bookmarks.PowerBookmarkMeta;
import org.chromium.components.power_bookmarks.ShoppingSpecifics;
import org.chromium.components.profile_metrics.BrowserProfileType;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.content_public.browser.test.util.TouchCommon;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.ui.test.util.NightModeTestUtils;
import org.chromium.ui.test.util.UiRestriction;
import org.chromium.url.GURL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
/** Tests for the bookmark manager. */
// clang-format off
@RunWith(ParameterizedRunner.class)
@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
// TODO(1406059): Disabling the shopping CPA should not be a requirement for these tests.
@Features.DisableFeatures({ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING})
// TODO(crbug.com/1426138): Investigate batching.
@DoNotBatch(reason = "BookmarkTest has behaviours and thus can't be batched.")
public class BookmarkTest {
// clang-format on
private static final String TEST_PAGE_URL_GOOGLE = "/chrome/test/data/android/google.html";
private static final String TEST_PAGE_TITLE_GOOGLE = "The Google";
private static final String TEST_PAGE_TITLE_GOOGLE2 = "Google";
private static final String TEST_PAGE_URL_FOO = "/chrome/test/data/android/test.html";
private static final String TEST_PAGE_TITLE_FOO = "Foo";
private static final String TEST_FOLDER_TITLE = "Test folder";
private static final String TEST_FOLDER_TITLE2 = "Test folder 2";
private static final String TEST_TITLE_A = "a";
private static final int TEST_PORT = 12345;
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@Rule
public TestRule mProcessor = new Features.JUnitProcessor();
@Rule
public ChromeRenderTestRule mRenderTestRule =
ChromeRenderTestRule.Builder.withPublicCorpus()
.setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS)
.build();
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private SyncService mSyncService;
@Captor
private ArgumentCaptor<SyncStateChangedListener> mSyncStateChangedListenerCaptor;
private BookmarkModel mBookmarkModel;
// Constant but can only be initialized after parameterized test runner setup because this would
// trigger native load / CommandLineFlag setup.
private GURL mTestUrlA;
private GURL mTestPage;
private GURL mTestPageFoo;
private EmbeddedTestServer mTestServer;
// Page/Activity specific, set/updated when bookmarks UI is opened.
private @Nullable BookmarkActivity mBookmarkActivity;
private BookmarkManagerCoordinator mBookmarkManagerCoordinator;
private RecyclerView mItemsContainer;
private BookmarkDelegate mDelegate;
private DragReorderableRecyclerViewAdapter mAdapter;
private BookmarkToolbar mToolbar;
@BeforeClass
public static void setUpBeforeActivityLaunched() {
ChromeNightModeTestUtils.setUpNightModeBeforeChromeActivityLaunched();
}
@ParameterAnnotations.UseMethodParameterBefore(NightModeTestUtils.NightModeParams.class)
public void setupNightMode(boolean nightModeEnabled) {
ChromeNightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled);
mRenderTestRule.setNightModeEnabled(nightModeEnabled);
}
@Before
public void setUp() {
ShoppingFeatures.setShoppingListEligibleForTesting(false);
mActivityTestRule.startMainActivityOnBlankPage();
runOnUiThreadBlocking(() -> {
mBookmarkModel = mActivityTestRule.getActivity().getBookmarkModelForTesting();
SyncService.overrideForTests(mSyncService);
});
// Use a custom port so the links are consistent for render tests.
mActivityTestRule.getEmbeddedTestServerRule().setServerPort(TEST_PORT);
mTestServer = mActivityTestRule.getTestServer();
mTestUrlA = new GURL("http://a.com");
mTestPage = new GURL(mTestServer.getURL(TEST_PAGE_URL_GOOGLE));
mTestPageFoo = new GURL(mTestServer.getURL(TEST_PAGE_URL_FOO));
}
@After
public void tearDown() throws Exception {
if (mBookmarkActivity != null) ApplicationTestUtils.finishActivity(mBookmarkActivity);
}
@AfterClass
public static void tearDownAfterActivityDestroyed() {
ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed();
}
@Test
@SmallTest
public void testAddBookmark() throws Exception {
mActivityTestRule.loadUrl(mTestPage);
// Check partner bookmarks are lazily loaded.
assertFalse(mBookmarkModel.isBookmarkModelLoaded());
// Click star button to bookmark the current tab.
MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
mActivityTestRule.getActivity(), R.id.bookmark_this_page_id);
BookmarkTestUtil.waitForBookmarkModelLoaded();
// All actions with BookmarkModel needs to run on UI thread.
runOnUiThreadBlocking(() -> {
BookmarkId id = mBookmarkModel.getUserBookmarkIdForTab(
mActivityTestRule.getActivity().getActivityTabProvider().get());
assertTrue("The test page is not added as bookmark: ",
mBookmarkModel.doesBookmarkExist(id));
BookmarkItem item = mBookmarkModel.getBookmarkById(id);
assertEquals(mBookmarkModel.getDefaultFolder(), item.getParentId());
assertEquals(mTestPage, item.getUrl());
assertEquals(TEST_PAGE_TITLE_GOOGLE, item.getTitle());
});
BookmarkTestUtil.waitForOfflinePageSaved(mTestPage);
// Click the star button again to launch the edit activity.
MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
mActivityTestRule.getActivity(), R.id.bookmark_this_page_id);
BookmarkTestUtil.waitForEditActivity().finish();
}
@Test
@SmallTest
public void testAddBookmarkToOtherFolder() {
mActivityTestRule.loadUrl(mTestPage);
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
// Set default folder as "Other Folder".
runOnUiThreadBlocking(() -> {
SharedPreferencesManager.getInstance().writeString(
ChromePreferenceKeys.BOOKMARKS_LAST_USED_PARENT,
mBookmarkModel.getOtherFolderId().toString());
});
// Click star button to bookmark the current tab.
MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
mActivityTestRule.getActivity(), R.id.bookmark_this_page_id);
BookmarkTestUtil.waitForBookmarkModelLoaded();
// All actions with BookmarkModel needs to run on UI thread.
runOnUiThreadBlocking(() -> {
BookmarkId id = mBookmarkModel.getUserBookmarkIdForTab(
mActivityTestRule.getActivity().getActivityTabProvider().get());
assertTrue("The test page is not added as bookmark: ",
mBookmarkModel.doesBookmarkExist(id));
BookmarkItem item = mBookmarkModel.getBookmarkById(id);
assertEquals("Bookmark added in a wrong default folder.",
mBookmarkModel.getOtherFolderId(), item.getParentId());
});
}
@Test
@SmallTest
public void testOpenBookmark() throws InterruptedException, ExecutionException {
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
assertTrue("Grid view does not contain added bookmark: ",
isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
final View title = getViewWithText(mItemsContainer, TEST_PAGE_TITLE_GOOGLE);
runOnUiThreadBlocking(() -> TouchCommon.singleClickView(title));
ChromeTabbedActivity activity = BookmarkTestUtil.waitForTabbedActivity();
CriteriaHelper.pollUiThread(() -> {
Tab activityTab = activity.getActivityTab();
Criteria.checkThat(activityTab, Matchers.notNullValue());
Criteria.checkThat(activityTab.getUrl(), Matchers.notNullValue());
Criteria.checkThat(activityTab.getUrl(), Matchers.is(mTestPage));
});
}
@Test
@SmallTest
public void testUrlComposition() {
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
runOnUiThreadBlocking(() -> {
BookmarkId mobileId = mBookmarkModel.getMobileFolderId();
BookmarkId bookmarkBarId = mBookmarkModel.getDesktopFolderId();
BookmarkId otherId = mBookmarkModel.getOtherFolderId();
assertEquals("chrome-native://bookmarks/folder/" + mobileId,
BookmarkUiState.createFolderUrl(mobileId).toString());
assertEquals("chrome-native://bookmarks/folder/" + bookmarkBarId,
BookmarkUiState.createFolderUrl(bookmarkBarId).toString());
assertEquals("chrome-native://bookmarks/folder/" + otherId,
BookmarkUiState.createFolderUrl(otherId).toString());
});
}
@Test
@SmallTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testShowBookmarkManager_Phone() throws InterruptedException {
BookmarkTestUtil.loadEmptyPartnerBookmarksForTesting(mBookmarkModel);
BookmarkTestUtil.waitForBookmarkModelLoaded();
runOnUiThreadBlocking(() -> {
BookmarkUtils.showBookmarkManager(mActivityTestRule.getActivity(),
mBookmarkModel.getMobileFolderId(), /*isIncognito=*/false);
});
BookmarkTestUtil.waitForBookmarkActivity();
// Assign so it's cleaned up after the test.
mBookmarkActivity = (BookmarkActivity) ApplicationStatus.getLastTrackedFocusedActivity();
}
@Test
@SmallTest
public void testOpenBookmarkManagerFolder() throws InterruptedException {
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
BookmarkTestUtil.waitForBookmarkModelLoaded();
assertEquals(BookmarkUiMode.FOLDER, mDelegate.getCurrentUiMode());
assertEquals("chrome-native://bookmarks/folder/3",
BookmarkUtils.getLastUsedUrl(mActivityTestRule.getActivity()));
}
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testFolderNavigation_Phone() throws InterruptedException, ExecutionException {
BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
// Check that we are in the mobile bookmarks folder.
assertEquals("Mobile bookmarks", mToolbar.getTitle());
assertEquals(SelectableListToolbar.NavigationButton.BACK,
mToolbar.getNavigationButtonForTests());
assertFalse(mToolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
// Open the new test folder.
runOnUiThreadBlocking(() -> mDelegate.openFolder(testFolder));
// Check that we are in the editable test folder.
assertEquals(TEST_FOLDER_TITLE, mToolbar.getTitle());
assertEquals(SelectableListToolbar.NavigationButton.BACK,
mToolbar.getNavigationButtonForTests());
assertTrue(mToolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
runOnUiThreadBlocking(
() -> mBookmarkModel.setBookmarkTitle(testFolder, TEST_FOLDER_TITLE2));
// Check that the test folder reflects name changes.
assertEquals(TEST_FOLDER_TITLE2, mToolbar.getTitle());
// Call BookmarkToolbar#onClick() to activate the navigation button.
runOnUiThreadBlocking(() -> mToolbar.onClick(mToolbar));
// Check that we are back in the mobile folder
assertEquals("Mobile bookmarks", mToolbar.getTitle());
assertEquals(SelectableListToolbar.NavigationButton.BACK,
mToolbar.getNavigationButtonForTests());
assertFalse(mToolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
// Call BookmarkToolbar#onClick() to activate the navigation button.
runOnUiThreadBlocking(() -> mToolbar.onClick(mToolbar));
// Check that we are in the root folder.
assertEquals("Bookmarks", mToolbar.getTitle());
assertEquals(SelectableListToolbar.NavigationButton.NONE,
mToolbar.getNavigationButtonForTests());
assertFalse(mToolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
}
// TODO(twellington): Write a folder navigation test for tablets that waits for the Tab hosting
// the native page to update its url after navigations.
@Test
@MediumTest
public void testSearchBookmarks() throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
BookmarkId folder = addFolder(TEST_FOLDER_TITLE);
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder);
addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(folder);
assertEquals(BookmarkUiMode.FOLDER, mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items before starting search.", 3, mAdapter.getItemCount());
runOnUiThreadBlocking(mDelegate::openSearchUi);
assertEquals(BookmarkUiMode.SEARCHING, mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items after showing search UI. The promo should be hidden.",
2, mAdapter.getItemCount());
searchBookmarks("Google");
assertEquals("Wrong number of items after searching.", 1, mAdapter.getItemCount());
BookmarkId newBookmark = addBookmark(TEST_PAGE_TITLE_GOOGLE2, mTestPage);
assertEquals("Wrong number of items after bookmark added while searching.", 2,
mAdapter.getItemCount());
removeBookmark(newBookmark);
assertEquals("Wrong number of items after bookmark removed while searching.", 1,
mAdapter.getItemCount());
searchBookmarks("Non-existent page");
assertEquals("Wrong number of items after searching for non-existent item.", 0,
mAdapter.getItemCount());
runOnUiThreadBlocking(() -> mToolbar.hideSearchView());
assertEquals("Wrong number of items after closing search UI.", 3, mAdapter.getItemCount());
assertEquals(BookmarkUiMode.FOLDER, mDelegate.getCurrentUiMode());
assertEquals(TEST_FOLDER_TITLE, mToolbar.getTitle());
}
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testSearchBookmarks_pressBack() throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
BookmarkId folder = addFolder(TEST_FOLDER_TITLE);
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder);
addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(folder);
assertEquals(Boolean.TRUE,
mBookmarkManagerCoordinator.getHandleBackPressChangedSupplier().get());
runOnUiThreadBlocking(mDelegate::openSearchUi);
assertEquals(BookmarkUiMode.SEARCHING, mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items after showing search UI. The promo should be hidden.",
2, mAdapter.getItemCount());
assertEquals(Boolean.TRUE,
mBookmarkManagerCoordinator.getHandleBackPressChangedSupplier().get());
// Exit search UI.
runOnUiThreadBlocking(mBookmarkActivity.getOnBackPressedDispatcher()::onBackPressed);
assertNotEquals(BookmarkUiMode.SEARCHING, mDelegate.getCurrentUiMode());
// Enter search UI again.
runOnUiThreadBlocking(mDelegate::openSearchUi);
searchBookmarks("Google");
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
assertEquals("Wrong number of items after searching.", 1, mAdapter.getItemCount());
BookmarkRow itemView =
(BookmarkRow) mItemsContainer.findViewHolderForLayoutPosition(0).itemView;
toggleSelectionAndEndAnimation(getIdByPosition(0), itemView);
// Make sure the Item "test" is selected.
CriteriaHelper.pollUiThread(
itemView::isChecked, "Expected item \"test\" to become selected");
runOnUiThreadBlocking(mBookmarkActivity.getOnBackPressedDispatcher()::onBackPressed);
// Clear selection but still in search UI.
CriteriaHelper.pollUiThread(
() -> !itemView.isChecked(), "Expected item \"test\" to become not selected");
assertEquals(BookmarkUiMode.SEARCHING, mDelegate.getCurrentUiMode());
assertEquals(Boolean.TRUE,
mBookmarkManagerCoordinator.getHandleBackPressChangedSupplier().get());
// Exit search UI.
runOnUiThreadBlocking(mBookmarkActivity.getOnBackPressedDispatcher()::onBackPressed);
assertEquals(BookmarkUiMode.FOLDER, mDelegate.getCurrentUiMode());
// Exit folder.
assertEquals(Boolean.TRUE,
mBookmarkManagerCoordinator.getHandleBackPressChangedSupplier().get());
runOnUiThreadBlocking(mBookmarkActivity.getOnBackPressedDispatcher()::onBackPressed);
assertEquals(BookmarkUiMode.FOLDER, mDelegate.getCurrentUiMode());
// Exit bookmark activity.
assertEquals(Boolean.FALSE,
mBookmarkManagerCoordinator.getHandleBackPressChangedSupplier().get());
runOnUiThreadBlocking(mBookmarkActivity.getOnBackPressedDispatcher()::onBackPressed);
ApplicationTestUtils.waitForActivityState(mBookmarkActivity, Stage.DESTROYED);
}
@Test
@MediumTest
public void testSearchBookmarks_Delete_FromInitialQuery() throws Exception {
// Inspired by https://crbug.com/1434600. Selected item deletion happens during the initial
// query that's still showing the folder's children.
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE);
BookmarkId testFolder2 = addFolder(TEST_FOLDER_TITLE2);
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, testFolder);
addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, testFolder2);
openBookmarkManager();
openFolder(testFolder);
View search_view = mToolbar.findViewById(R.id.search_view);
clickToolbarMenuItem(R.id.search_menu_id);
// Despite being in search mode, this is the initial query state, and the previous 1
// bookmark inside of testFolder should be shown.
assertEquals(search_view.getVisibility(), View.VISIBLE);
assertEquals(1, mAdapter.getItemCount());
BookmarkRow itemView = (BookmarkRow) mBookmarkManagerCoordinator.getRecyclerViewForTesting()
.findViewHolderForAdapterPosition(0)
.itemView;
toggleSelectionAndEndAnimation(getIdByPosition(0), itemView);
// Selecting an item should cause the search view to be hidden, replaced with menu items
// that operate on the selected rows.
assertNotEquals(search_view.getVisibility(), View.VISIBLE);
clickToolbarMenuItem(R.id.selection_mode_delete_menu_id);
// Should now be kicked back into an empty search string query, not the initial query. This
// is why 3 items should now be visible, the two folders and the other url bookmark.
assertEquals(search_view.getVisibility(), View.VISIBLE);
assertEquals(3, mAdapter.getItemCount());
}
@Test
@MediumTest
public void testSearchBookmarks_Delete() throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE);
BookmarkId testFolder2 = addFolder(TEST_FOLDER_TITLE2, testFolder);
BookmarkId testBookmark = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, testFolder);
addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, testFolder);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(testFolder);
assertEquals("Wrong state, should be in folder", BookmarkUiMode.FOLDER,
mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items before starting search.", 3, mAdapter.getItemCount());
// Start searching without entering a query. This won't change the items displayed which
// are currently testFolder's children (3).
runOnUiThreadBlocking(mDelegate::openSearchUi);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
assertEquals("Wrong state, should be searching", BookmarkUiMode.SEARCHING,
mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items before starting search.", 3, mAdapter.getItemCount());
// Select testFolder2 and delete it. This deletion will refresh the current search, which
// right now is the empty string. This will return all bookmarks (3).
toggleSelectionAndEndAnimation(testFolder2,
(BookmarkRow) mItemsContainer.findViewHolderForLayoutPosition(2).itemView);
clickToolbarMenuItem(R.id.selection_mode_delete_menu_id);
// Should still be searching with the folder gone.
assertEquals("Wrong number of items.", 3, mAdapter.getItemCount());
// Start searching, enter a query. This query will match all remaining bookmarks (1).
searchBookmarks("Google");
assertEquals("Wrong number of items after searching.", 1, mAdapter.getItemCount());
// Remove the bookmark.
removeBookmark(testBookmark);
// The user should still be searching, and the bookmark should be gone. We're refreshing
// the search query again here, but in this case it's now "Google".
assertEquals("Wrong state, should be searching", BookmarkUiMode.SEARCHING,
mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items after searching.", 0, mAdapter.getItemCount());
// Undo the deletion.
runOnUiThreadBlocking(
() -> mBookmarkManagerCoordinator.getUndoControllerForTesting().onAction(null));
// The user should still be searching, and the bookmark should reappear. Refreshing the
// search yet again, now with the "Google" search matching returning 1 result.
assertEquals("Wrong state, should be searching", BookmarkUiMode.SEARCHING,
mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items after searching.", 1, mAdapter.getItemCount());
}
@Test
@MediumTest
@Features.DisableFeatures({ChromeFeatureList.SHOPPING_LIST})
public void testSearchBookmarks_DeleteFolderWithChildrenInResults() throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE);
addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, testFolder);
openBookmarkManager();
// Start searching, enter a query.
runOnUiThreadBlocking(mDelegate::openSearchUi);
assertEquals("Wrong state, should be searching", BookmarkUiMode.SEARCHING,
mDelegate.getCurrentUiMode());
searchBookmarks("test");
assertEquals("Wrong number of items after searching.", 2, mAdapter.getItemCount());
// Remove the bookmark.
removeBookmark(testFolder);
// The user should still be searching, and the bookmark should be gone.
assertEquals("Wrong state, should be searching", BookmarkUiMode.SEARCHING,
mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items after searching.", 0, mAdapter.getItemCount());
// Undo the deletion.
runOnUiThreadBlocking(
() -> mBookmarkManagerCoordinator.getUndoControllerForTesting().onAction(null));
// The user should still be searching, and the bookmark should reappear.
assertEquals("Wrong state, should be searching", BookmarkUiMode.SEARCHING,
mDelegate.getCurrentUiMode());
assertEquals("Wrong number of items after searching.", 2, mAdapter.getItemCount());
}
@Test
@MediumTest
@Feature({"RenderTest"})
@ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
public void testBookmarkFolderIcon(boolean nightModeEnabled) throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
addFolder(TEST_FOLDER_TITLE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
mRenderTestRule.render(
mBookmarkManagerCoordinator.getView(), "bookmark_manager_one_folder");
BookmarkRow itemView = (BookmarkRow) mBookmarkManagerCoordinator.getRecyclerViewForTesting()
.findViewHolderForAdapterPosition(0)
.itemView;
toggleSelectionAndEndAnimation(getIdByPosition(0), itemView);
// Make sure the Item "test" is selected.
CriteriaHelper.pollUiThread(
itemView::isChecked, "Expected item \"test\" to become selected");
mRenderTestRule.render(
mBookmarkManagerCoordinator.getView(), "bookmark_manager_folder_selected");
}
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) // Tablets don't have a close button.
public void testCloseBookmarksWhileStillLoading() throws Exception {
BookmarkManagerCoordinator.preventLoadingForTesting(true);
openBookmarkManager();
clickToolbarMenuItem(R.id.close_menu_id);
ApplicationTestUtils.waitForActivityState(mBookmarkActivity, Stage.DESTROYED);
BookmarkManagerCoordinator.preventLoadingForTesting(false);
}
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) // see crbug.com/1429025
public void testEditHiddenWhileStillLoading() throws Exception {
BookmarkManagerCoordinator.preventLoadingForTesting(true);
openBookmarkManager();
assertFalse(mToolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
BookmarkManagerCoordinator.preventLoadingForTesting(false);
}
@Test
@MediumTest
public void testEndIconVisibilityInSelectionMode() throws Exception {
BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
addBookmark(TEST_TITLE_A, mTestUrlA);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
BookmarkRow test =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView;
View testMoreButton = test.findViewById(R.id.more);
View testDragHandle = test.getDragHandleViewForTesting();
BookmarkRow testFolderA =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
View aMoreButton = testFolderA.findViewById(R.id.more);
View aDragHandle = testFolderA.getDragHandleViewForTesting();
toggleSelectionAndEndAnimation(testId, test);
// Callback occurs when Item "test" is selected.
CriteriaHelper.pollUiThread(test::isChecked, "Expected item \"test\" to become selected");
assertEquals("Expected bookmark toolbar to be selection mode",
mToolbar.getCurrentViewType(), ViewType.SELECTION_VIEW);
assertEquals("Expected more button of selected item to be gone when drag is active.",
View.GONE, testMoreButton.getVisibility());
assertEquals("Expected drag handle of selected item to be visible when drag is active.",
View.VISIBLE, testDragHandle.getVisibility());
assertTrue("Expected drag handle to be enabled when drag is active.",
testDragHandle.isEnabled());
assertEquals("Expected more button of unselected item to be gone when drag is active.",
View.GONE, aMoreButton.getVisibility());
assertEquals("Expected drag handle of unselected item to be visible when drag is active.",
View.VISIBLE, aDragHandle.getVisibility());
assertFalse("Expected drag handle of unselected item to be disabled when drag is active.",
aDragHandle.isEnabled());
}
@Test
@MediumTest
public void testEndIconVisibilityInSearchMode() throws Exception {
BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
addFolder(TEST_TITLE_A);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
BookmarkRow test =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView;
View testMoreButton = test.findViewById(R.id.more);
View testDragHandle = test.getDragHandleViewForTesting();
BookmarkRow a = (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
View aMoreButton = a.findViewById(R.id.more);
View aDragHandle = a.getDragHandleViewForTesting();
clickToolbarMenuItem(R.id.search_menu_id);
// Callback occurs when Item "test" is selected.
CriteriaHelper.pollUiThread(() -> mToolbar.isSearching(), "Expected to enter search mode");
toggleSelectionAndEndAnimation(testId, test);
// Callback occurs when Item "test" is selected.
CriteriaHelper.pollUiThread(test::isChecked, "Expected item \"test\" to become selected");
assertEquals("Expected drag handle of selected item to be gone "
+ "when selection mode is activated from search.",
View.GONE, testDragHandle.getVisibility());
assertEquals("Expected more button of selected item to be visible "
+ "when selection mode is activated from search.",
View.VISIBLE, testMoreButton.getVisibility());
assertFalse("Expected more button of selected item to be disabled "
+ "when selection mode is activated from search.",
testMoreButton.isEnabled());
assertEquals("Expected drag handle of unselected item to be gone "
+ "when selection mode is activated from search.",
View.GONE, aDragHandle.getVisibility());
assertEquals("Expected more button of unselected item to be visible "
+ "when selection mode is activated from search.",
View.VISIBLE, aMoreButton.getVisibility());
assertFalse("Expected more button of unselected item to be disabled "
+ "when selection mode is activated from search.",
aMoreButton.isEnabled());
}
@Test
@MediumTest
public void testSmallDrag_Up_BookmarksOnly() throws Exception {
List<BookmarkId> initial = new ArrayList<>();
List<BookmarkId> expected = new ArrayList<>();
BookmarkId fooId = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo);
BookmarkId googleId = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
BookmarkId aId = addBookmark(TEST_TITLE_A, mTestUrlA);
// When bookmarks are added, they are added to the top of the list.
// The current bookmark order is the reverse of the order in which they were added.
initial.add(aId);
initial.add(googleId);
initial.add(fooId);
runOnUiThreadBlocking(() -> {
assertEquals("Bookmarks were not added in the expected order.", initial,
mBookmarkModel.getChildIds(mBookmarkModel.getDefaultFolder()).subList(0, 3));
});
expected.add(fooId);
expected.add(aId);
expected.add(googleId);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
// Callback occurs upon changes inside of the bookmark model.
CallbackHelper modelReorderHelper = new CallbackHelper();
BookmarkModelObserver bookmarkModelObserver =
new BookmarkModelObserver() {
@Override
public void bookmarkModelChanged() {
modelReorderHelper.notifyCalled();
}
};
// Perform registration to make callbacks work.
runOnUiThreadBlocking(() -> { mBookmarkModel.addObserver(bookmarkModelObserver); });
BookmarkRow foo =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(3).itemView;
assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_FOO, foo.getTitle());
toggleSelectionAndEndAnimation(fooId, foo);
// Starts as last bookmark (2nd index) and ends as 0th bookmark (promo header not included).
simulateDragForTestsOnUiThread(3, 1);
modelReorderHelper.waitForCallback(0, 1);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
runOnUiThreadBlocking(() -> {
List<BookmarkId> observed =
mBookmarkModel.getChildIds(mBookmarkModel.getDefaultFolder());
// Exclude partner bookmarks folder
assertEquals(expected, observed.subList(0, 3));
assertTrue("The selected item should stay selected", foo.isItemSelected());
});
// After a drag is finished, the toolbar menu items should still reflect the selected state.
// Check inspired by https://crbug.com/1434566.
assertTrue(mToolbar.getMenu().findItem(R.id.selection_mode_edit_menu_id).isVisible());
assertTrue(mToolbar.getMenu().findItem(R.id.selection_mode_move_menu_id).isVisible());
assertTrue(mToolbar.getMenu().findItem(R.id.selection_mode_delete_menu_id).isVisible());
assertTrue(mToolbar.getMenu().findItem(R.id.selection_open_in_new_tab_id).isVisible());
assertTrue(
mToolbar.getMenu().findItem(R.id.selection_open_in_incognito_tab_id).isVisible());
}
@Test
@MediumTest
public void testSmallDrag_Down_FoldersOnly() throws Exception {
List<BookmarkId> initial = new ArrayList<>();
List<BookmarkId> expected = new ArrayList<>();
BookmarkId aId = addFolder("a");
BookmarkId bId = addFolder("b");
BookmarkId cId = addFolder("c");
BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
initial.add(testId);
initial.add(cId);
initial.add(bId);
initial.add(aId);
runOnUiThreadBlocking(() -> {
assertEquals("Bookmarks were not added in the expected order.", initial,
mBookmarkModel.getChildIds(mBookmarkModel.getDefaultFolder()).subList(0, 4));
});
expected.add(cId);
expected.add(bId);
expected.add(aId);
expected.add(testId);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
// Callback occurs upon changes inside of the bookmark model.
CallbackHelper modelReorderHelper = new CallbackHelper();
BookmarkModelObserver bookmarkModelObserver =
new BookmarkModelObserver() {
@Override
public void bookmarkModelChanged() {
modelReorderHelper.notifyCalled();
}
};
// Perform registration to make callbacks work.
runOnUiThreadBlocking(() -> { mBookmarkModel.addObserver(bookmarkModelObserver); });
BookmarkFolderRow test =
(BookmarkFolderRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, test.getTitle());
toggleSelectionAndEndAnimation(testId, test);
// Starts as 0th bookmark (not counting promo header) and ends as last (index 3).
simulateDragForTestsOnUiThread(1, 4);
modelReorderHelper.waitForCallback(0, 1);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
runOnUiThreadBlocking(() -> {
List<BookmarkId> observed =
mBookmarkModel.getChildIds(mBookmarkModel.getDefaultFolder());
// Exclude partner bookmarks folder
assertEquals(expected, observed.subList(0, 4));
assertTrue("The selected item should stay selected", test.isItemSelected());
});
}
@Test
@MediumTest
public void testSmallDrag_Down_MixedFoldersAndBookmarks() throws Exception {
List<BookmarkId> initial = new ArrayList<>();
List<BookmarkId> expected = new ArrayList<>();
BookmarkId aId = addFolder("a");
BookmarkId bId = addBookmark("b", new GURL("http://b.com"));
BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
initial.add(testId);
initial.add(bId);
initial.add(aId);
runOnUiThreadBlocking(() -> {
assertEquals("Bookmarks were not added in the expected order.", initial,
mBookmarkModel.getChildIds(mBookmarkModel.getDefaultFolder()).subList(0, 3));
});
expected.add(bId);
expected.add(testId);
expected.add(aId);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
// Callback occurs upon changes inside of the bookmark model.
CallbackHelper modelReorderHelper = new CallbackHelper();
BookmarkModelObserver bookmarkModelObserver =
new BookmarkModelObserver() {
@Override
public void bookmarkModelChanged() {
modelReorderHelper.notifyCalled();
}
};
// Perform registration to make callbacks work.
runOnUiThreadBlocking(() -> { mBookmarkModel.addObserver(bookmarkModelObserver); });
BookmarkFolderRow test =
(BookmarkFolderRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, test.getTitle());
toggleSelectionAndEndAnimation(testId, test);
// Starts as 0th bookmark (not counting promo header) and ends at the 1st index.
simulateDragForTestsOnUiThread(1, 2);
modelReorderHelper.waitForCallback(0, 1);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
runOnUiThreadBlocking(() -> {
List<BookmarkId> observed =
mBookmarkModel.getChildIds(mBookmarkModel.getDefaultFolder());
// Exclude partner bookmarks folder
assertEquals(expected, observed.subList(0, 3));
assertTrue("The selected item should stay selected", test.isItemSelected());
});
}
@Test
@MediumTest
public void testPromoDraggability() throws Exception {
BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
ViewHolder promo = mItemsContainer.findViewHolderForAdapterPosition(0);
toggleSelectionAndEndAnimation(
testId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView);
assertFalse("Promo header should not be passively draggable",
isViewHolderPassivelyDraggable(promo));
assertFalse("Promo header should not be actively draggable",
isViewHoldersActivelyDraggable(promo));
}
@Test
@MediumTest
public void testPartnerFolderDraggability() throws Exception {
BookmarkId testId = addFolderWithPartner(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
ViewHolder partner = mItemsContainer.findViewHolderForAdapterPosition(2);
toggleSelectionAndEndAnimation(
testId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView);
assertFalse("Partner bookmarks folder should not be passively draggable",
isViewHolderPassivelyDraggable(partner));
assertFalse("Partner bookmarks folder should not be actively draggable",
isViewHoldersActivelyDraggable(partner));
}
@Test
@MediumTest
public void testUnselectedItemDraggability() throws Exception {
BookmarkId aId = addBookmark("a", mTestUrlA);
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
ViewHolder test = mItemsContainer.findViewHolderForAdapterPosition(1);
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
((BookmarkFolderRow) test.itemView).getTitle());
toggleSelectionAndEndAnimation(
aId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView);
assertTrue("Unselected rows should be passively draggable",
isViewHolderPassivelyDraggable(test));
assertFalse("Unselected rows should not be actively draggable",
isViewHoldersActivelyDraggable(test));
}
@Test
@MediumTest
public void testCannotSelectPromo() throws Exception {
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
View promo = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
TouchCommon.longPressView(promo);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
assertFalse("Expected that we would not be in selection mode "
+ "after long pressing on promo view.",
mDelegate.getSelectionDelegate().isSelectionEnabled());
}
@Test
@MediumTest
public void testCannotSelectPartner() throws Exception {
addFolderWithPartner(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
View partner = mItemsContainer.findViewHolderForAdapterPosition(2).itemView;
TouchCommon.longPressView(partner);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
assertFalse("Expected that we would not be in selection mode "
+ "after long pressing on partner bookmark.",
mDelegate.getSelectionDelegate().isSelectionEnabled());
}
@Test
@MediumTest
public void testMoveUpMenuItem() throws Exception {
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestUrlA);
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
View google = mItemsContainer.findViewHolderForAdapterPosition(2).itemView;
assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_GOOGLE,
((BookmarkItemRow) google).getTitle());
View more = google.findViewById(R.id.more);
runOnUiThreadBlocking(more::callOnClick);
onView(withText("Move up")).perform(click());
// Confirm that the "Google" bookmark is now on top, and that the "test" folder is 2nd
assertTrue(((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView)
.getTitle()
.equals(TEST_PAGE_TITLE_GOOGLE));
assertTrue(((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView)
.getTitle()
.equals(TEST_FOLDER_TITLE));
}
@Test
@MediumTest
public void testMoveDownMenuItem() throws Exception {
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestUrlA);
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
((BookmarkFolderRow) testFolder).getTitle());
ListMenuButton more = testFolder.findViewById(R.id.more);
runOnUiThreadBlocking(more::callOnClick);
onView(withText("Move down")).perform(click());
// Confirm that the "Google" bookmark is now on top, and that the "test" folder is 2nd
assertTrue(((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView)
.getTitle()
.equals(TEST_PAGE_TITLE_GOOGLE));
assertTrue(((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView)
.getTitle()
.equals(TEST_FOLDER_TITLE));
}
@Test
@MediumTest
public void testMoveDownGoneForBottomElement() throws Exception {
addBookmarkWithPartner(TEST_PAGE_TITLE_GOOGLE, mTestUrlA);
addFolderWithPartner(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
View google = mItemsContainer.findViewHolderForAdapterPosition(2).itemView;
assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_GOOGLE,
((BookmarkItemRow) google).getTitle());
View more = google.findViewById(R.id.more);
runOnUiThreadBlocking(more::callOnClick);
onView(withText("Move down")).check(doesNotExist());
}
@Test
@MediumTest
public void testMoveUpGoneForTopElement() throws Exception {
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestUrlA);
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
((BookmarkFolderRow) testFolder).getTitle());
ListMenuButton more = testFolder.findViewById(R.id.more);
runOnUiThreadBlocking(more::callOnClick);
onView(withText("Move up")).check(doesNotExist());
}
@Test
@MediumTest
@DisabledTest(message = "crbug.com/1046653")
public void testMoveButtonsGoneInSearchMode() throws Exception {
addFolder(TEST_FOLDER_TITLE);
openBookmarkManager();
clickToolbarMenuItem(R.id.search_menu_id);
// Callback occurs when Item "test" is selected.
CriteriaHelper.pollUiThread(() -> mToolbar.isSearching(), "Expected to enter search mode");
View testFolder = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
((BookmarkFolderRow) testFolder).getTitle());
View more = testFolder.findViewById(R.id.more);
runOnUiThreadBlocking(more::callOnClick);
onView(withText("Move up")).check(doesNotExist());
onView(withText("Move down")).check(doesNotExist());
}
@Test
@MediumTest
public void testMoveButtonsGoneWithOneBookmark() throws Exception {
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
((BookmarkFolderRow) testFolder).getTitle());
View more = testFolder.findViewById(R.id.more);
runOnUiThreadBlocking(more::callOnClick);
onView(withText("Move up")).check(doesNotExist());
onView(withText("Move down")).check(doesNotExist());
}
@Test
@MediumTest
public void testMoveButtonsGoneForPartnerBookmarks() throws Exception {
loadFakePartnerBookmarkShimForTesting();
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
// Open partner bookmarks folder.
runOnUiThreadBlocking(() -> mDelegate.openFolder(mBookmarkModel.getPartnerFolderId()));
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
assertEquals(
"Wrong number of items in partner bookmark folder.", 2, mAdapter.getItemCount());
// Verify that bookmark 1 is editable (so more button can be triggered) but not movable.
BookmarkId partnerBookmarkId1 = getIdByPosition(0);
runOnUiThreadBlocking(() -> {
BookmarkItem partnerBookmarkItem1 = mBookmarkModel.getBookmarkById(partnerBookmarkId1);
partnerBookmarkItem1.forceEditableForTesting();
assertEquals("Incorrect bookmark type for item 1", BookmarkType.PARTNER,
partnerBookmarkId1.getType());
assertFalse("Partner item 1 should not be movable",
BookmarkUtils.isMovable(partnerBookmarkItem1));
assertTrue("Partner item 1 should be editable", partnerBookmarkItem1.isEditable());
});
// Verify that bookmark 2 is editable (so more button can be triggered) but not movable.
View partnerBookmarkView1 = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
View more1 = partnerBookmarkView1.findViewById(R.id.more);
runOnUiThreadBlocking(more1::callOnClick);
onView(withText("Move up")).check(doesNotExist());
onView(withText("Move down")).check(doesNotExist());
// Verify that bookmark 2 is not movable.
BookmarkId partnerBookmarkId2 = getIdByPosition(1);
runOnUiThreadBlocking(() -> {
BookmarkItem partnerBookmarkItem2 = mBookmarkModel.getBookmarkById(partnerBookmarkId2);
partnerBookmarkItem2.forceEditableForTesting();
assertEquals("Incorrect bookmark type for item 2", BookmarkType.PARTNER,
partnerBookmarkId2.getType());
assertFalse("Partner item 2 should not be movable",
BookmarkUtils.isMovable(partnerBookmarkItem2));
assertTrue("Partner item 2 should be editable", partnerBookmarkItem2.isEditable());
});
// Verify that bookmark 2 does not have move up/down items.
View partnerBookmarkView2 = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
View more2 = partnerBookmarkView2.findViewById(R.id.more);
runOnUiThreadBlocking(more2::callOnClick);
onView(withText("Move up")).check(doesNotExist());
onView(withText("Move down")).check(doesNotExist());
}
@Test
@MediumTest
@Features.DisableFeatures({ChromeFeatureList.SHOPPING_LIST})
public void testTopLevelFolderUpdateAfterSync() throws Exception {
// Set up the test and open the bookmark manager to the Mobile Bookmarks folder.
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
openBookmarkManager();
// Add a bookmark to the Other Bookmarks folder.
runOnUiThreadBlocking(() -> {
assertNotNull(mBookmarkModel.addBookmark(
mBookmarkModel.getOtherFolderId(), 0, TEST_TITLE_A, mTestUrlA));
});
verify(mSyncService, atLeast(1))
.addSyncStateChangedListener(mSyncStateChangedListenerCaptor.capture());
for (SyncStateChangedListener syncStateChangedListener :
mSyncStateChangedListenerCaptor.getAllValues()) {
runOnUiThreadBlocking(syncStateChangedListener::syncStateChanged);
}
runOnUiThreadBlocking(getTestingDelegate()::simulateSignInForTesting);
assertEquals(
"Expected promo, \"Reading List\", \"Mobile Bookmarks\" and \"Other Bookmarks\" folder to appear!",
4, mAdapter.getItemCount());
}
@Test
@MediumTest
@DisabledTest(message = "crbug.com/1369091")
public void testShowInFolder_NoScroll() throws Exception {
addFolder(TEST_FOLDER_TITLE);
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
// Enter search mode.
enterSearch();
// Click "Show in folder".
View testFolder = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
clickMoreButtonOnFirstItem(TEST_FOLDER_TITLE);
onView(withText("Show in folder")).perform(click());
// Assert that the view pulses.
assertTrue("Expected bookmark row to pulse after clicking \"show in folder\"!",
checkHighlightPulse(testFolder));
// Enter search mode again.
enterSearch();
assertTrue("Expected bookmark row to not be highlighted "
+ "after entering search mode",
checkHighlightOff(testFolder));
// Click "Show in folder" again.
clickMoreButtonOnFirstItem(TEST_FOLDER_TITLE);
onView(withText("Show in folder")).perform(click());
assertTrue("Expected bookmark row to pulse after clicking \"show in folder\" a 2nd time!",
checkHighlightPulse(testFolder));
}
@Test
@MediumTest
@DisabledTest(message = "crbug.com/1434777")
public void testShowInFolder_Scroll() throws Exception {
addFolder(TEST_FOLDER_TITLE); // Index 8
addBookmark(TEST_TITLE_A, mTestUrlA);
addBookmark(TEST_PAGE_TITLE_FOO, new GURL("http://foo.com"));
addFolder(TEST_PAGE_TITLE_GOOGLE2);
addFolder("B");
addFolder("C");
addFolder("D");
addFolder("E"); // Index 1
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
// Enter search mode.
enterSearch();
runOnUiThreadBlocking(
() -> mBookmarkManagerCoordinator.onSearchTextChanged(TEST_FOLDER_TITLE));
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
// This should be the only (& therefore 0-indexed) item.
clickMoreButtonOnFirstItem(TEST_FOLDER_TITLE);
// Show in folder.
onView(withText("Show in folder")).perform(click());
// This should be in the 8th position now.
ViewHolder testFolderInList = mItemsContainer.findViewHolderForAdapterPosition(8);
assertFalse("Expected list to scroll bookmark item into view", testFolderInList == null);
assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
((BookmarkFolderRow) testFolderInList.itemView).getTitle());
assertTrue("Expected highlight to pulse on after scrolling to the item!",
checkHighlightPulse(testFolderInList.itemView));
}
@Test
@MediumTest
@DisabledTest(message = "crbug.com/1434777")
public void testShowInFolder_OpenOtherFolder() throws Exception {
BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
runOnUiThreadBlocking(() -> mBookmarkModel.addBookmark(testId, 0, TEST_TITLE_A, mTestUrlA));
BookmarkPromoHeader.forcePromoStateForTesting(
SyncPromoState.PROMO_FOR_SYNC_TURNED_OFF_STATE);
openBookmarkManager();
// Enter search mode.
enterSearch();
runOnUiThreadBlocking(
() -> mBookmarkManagerCoordinator.onSearchTextChanged(mTestUrlA.getSpec()));
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
// This should be the only (& therefore 0-indexed) item.
clickMoreButtonOnFirstItem(TEST_TITLE_A);
// Show in folder.
onView(withText("Show in folder")).perform(click());
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
// Make sure that we're in the right folder (index 1 because of promo).
View itemA = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_TITLE_A,
((BookmarkItemRow) itemA).getTitle());
assertTrue("Expected highlight to pulse after opening an item in another folder!",
checkHighlightPulse(itemA));
// Open mobile bookmarks folder, then go back to the subfolder.
runOnUiThreadBlocking(() -> {
mDelegate.openFolder(mBookmarkModel.getMobileFolderId());
mDelegate.openFolder(testId);
});
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
View itemASecondView = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
assertEquals("Wrong bookmark item selected.", TEST_TITLE_A,
((BookmarkItemRow) itemASecondView).getTitle());
assertTrue("Expected highlight to not be highlighted after exiting and re-entering folder!",
checkHighlightOff(itemASecondView));
}
@Test
@SmallTest
public void testAddBookmarkInBackgroundWithSelection() throws Exception {
BookmarkId folder = addFolder(TEST_FOLDER_TITLE);
BookmarkId id = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder);
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(folder);
assertEquals(1, mAdapter.getItemCount());
BookmarkRow row =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
toggleSelectionAndEndAnimation(id, row);
runOnUiThreadBlocking(() -> {
mBookmarkModel.addBookmark(folder, 1, TEST_PAGE_TITLE_GOOGLE, mTestPage);
});
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
runOnUiThreadBlocking(() -> {
assertTrue(isItemPresentInBookmarkList(TEST_PAGE_TITLE_FOO));
assertTrue(isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
assertEquals(2, mAdapter.getItemCount());
assertTrue("The selected row should be kept selected", row.isItemSelected());
});
}
@Test
@SmallTest
public void testDeleteAllSelectedBookmarksInBackground() throws Exception {
// Select one bookmark and then remove that in background.
// In the meantime, the toolbar changes from selection mode to normal mode.
BookmarkId folder = addFolder(TEST_FOLDER_TITLE);
BookmarkId fooId = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder);
BookmarkId googleId = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder);
BookmarkId aId = addBookmark(TEST_TITLE_A, mTestUrlA, folder);
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(folder);
assertEquals(3, mAdapter.getItemCount());
BookmarkRow row =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
toggleSelectionAndEndAnimation(googleId, row);
CallbackHelper helper = new CallbackHelper();
runOnUiThreadBlocking(() -> {
mDelegate.getSelectionDelegate().addObserver((x) -> helper.notifyCalled());
});
removeBookmark(googleId);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
helper.waitForCallback(0, 1);
runOnUiThreadBlocking(() -> {
assertFalse("Item is not deleted", isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
assertEquals(2, mAdapter.getItemCount());
assertEquals("Bookmark View should be back to normal view",
mToolbar.getCurrentViewType(), ViewType.NORMAL_VIEW);
});
}
@Test
@SmallTest
public void testDeleteSomeSelectedBookmarksInBackground() throws Exception {
// selected on bookmarks and then remove one of them in background
// in the meantime, the toolbar stays in selection mode
BookmarkId folder = addFolder(TEST_FOLDER_TITLE);
addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder);
BookmarkId googleId = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage, folder);
BookmarkId aId = addBookmark(TEST_TITLE_A, mTestUrlA, folder);
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(folder);
assertEquals(3, mAdapter.getItemCount());
BookmarkRow row =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
toggleSelectionAndEndAnimation(googleId, row);
BookmarkRow aRow =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
toggleSelectionAndEndAnimation(aId, aRow);
CallbackHelper helper = new CallbackHelper();
runOnUiThreadBlocking(() -> {
mDelegate.getSelectionDelegate().addObserver((x) -> helper.notifyCalled());
});
removeBookmark(googleId);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
helper.waitForCallback(0, 1);
runOnUiThreadBlocking(() -> {
assertFalse("Item is not deleted", isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
assertEquals(2, mAdapter.getItemCount());
assertTrue("Item selected should not be cleared", aRow.isItemSelected());
assertEquals("Should stay in selection mode because there is one selected",
mToolbar.getCurrentViewType(), ViewType.SELECTION_VIEW);
});
}
@Test
@SmallTest
public void testUpdateSelectedBookmarkInBackground() throws Exception {
BookmarkId folder = addFolder(TEST_FOLDER_TITLE);
BookmarkId id = addBookmark(TEST_PAGE_TITLE_FOO, mTestPageFoo, folder);
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
// Open the new folder where these bookmarks were created.
openFolder(folder);
assertEquals(1, mAdapter.getItemCount());
BookmarkRow row =
(BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
toggleSelectionAndEndAnimation(id, row);
CallbackHelper helper = new CallbackHelper();
runOnUiThreadBlocking(() -> mBookmarkModel.addObserver(new BookmarkModelObserver() {
@Override
public void bookmarkModelChanged() {
helper.notifyCalled();
}
}));
runOnUiThreadBlocking(() -> mBookmarkModel.setBookmarkTitle(id, TEST_PAGE_TITLE_GOOGLE));
helper.waitForCallback(0, 1);
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
runOnUiThreadBlocking(() -> {
assertFalse(isItemPresentInBookmarkList(TEST_PAGE_TITLE_FOO));
assertTrue(isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
assertEquals(1, mAdapter.getItemCount());
assertTrue("The selected row should stay selected", row.isItemSelected());
});
}
@Test
@MediumTest
public void testBookmarksDoesNotRecordLaunchMetrics() throws Throwable {
assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM));
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
openBookmarkManager();
pressBack();
BookmarkTestUtil.waitForTabbedActivity();
assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM));
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
onView(withText(TEST_PAGE_TITLE_GOOGLE)).perform(click());
BookmarkTestUtil.waitForTabbedActivity();
assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM));
}
/**
* Test that we record Bookmarks.BookmarkTestUtil.openBookmarkManager.PerProfileType when
* R.id.all_bookmarks_menu_id is clicked in regular mode.
*
* Please note that this test doesn't run for tablet because of the way bookmark manager is
* opened for tablets via BookmarkTestUtil.openBookmarkManager test method which circumvents the
* click of R.id.all_bookmarks_menu_id, this doesn't happen in actual case and the metric indeed
* gets recorded in tablets.
*/
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testRecordsHistogramWhenBookmarkManagerOpened_InRegular() throws Throwable {
assertEquals(0,
RecordHistogram.getHistogramTotalCountForTesting(
"Bookmarks.OpenBookmarkManager.PerProfileType"));
openBookmarkManager();
pressBack();
BookmarkTestUtil.waitForTabbedActivity();
assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
"Bookmarks.OpenBookmarkManager.PerProfileType"));
assertEquals(1,
RecordHistogram.getHistogramValueCountForTesting(
"Bookmarks.OpenBookmarkManager.PerProfileType",
BrowserProfileType.REGULAR));
}
/**
* Test that we record Bookmarks.OpenBookmarkManager.PerProfileType when
* R.id.all_bookmarks_menu_id is clicked in Incognito mode.
*
* Please note that this test doesn't run for tablet because of the way bookmark manager is
* opened for tablets via openBookmarkManager test method which circumvents the click of
* R.id.all_bookmarks_menu_id. This doesn't happen in actual case and the metric indeed gets
* recorded in tablets.
*/
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testRecordsHistogramWhenBookmarkManagerOpened_InIncognito() throws Throwable {
assertEquals(0,
RecordHistogram.getHistogramTotalCountForTesting(
"Bookmarks.OpenBookmarkManager.PerProfileType"));
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/true);
openBookmarkManager();
pressBack();
BookmarkTestUtil.waitForTabbedActivity();
assertEquals(1,
RecordHistogram.getHistogramTotalCountForTesting(
"Bookmarks.OpenBookmarkManager.PerProfileType"));
assertEquals(1,
RecordHistogram.getHistogramValueCountForTesting(
"Bookmarks.OpenBookmarkManager.PerProfileType",
BrowserProfileType.INCOGNITO));
}
@Test
@MediumTest
@Feature({"RenderTest"})
public void testBookmarksVisualRefreshFolders() throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
addFolder(TEST_FOLDER_TITLE);
addFolder(TEST_FOLDER_TITLE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
mRenderTestRule.render(
mBookmarkManagerCoordinator.getView(), "bookmarks_visual_refresh_folders");
BookmarkRow itemView = (BookmarkRow) mBookmarkManagerCoordinator.getRecyclerViewForTesting()
.findViewHolderForAdapterPosition(0)
.itemView;
toggleSelectionAndEndAnimation(getIdByPosition(0), itemView);
// Make sure the Item "test" is selected.
CriteriaHelper.pollUiThread(
itemView::isChecked, "Expected item \"test\" to become selected");
mRenderTestRule.render(
mBookmarkManagerCoordinator.getView(), "bookmarks_visual_refresh_folders_selected");
}
@Test
@MediumTest
@Feature({"RenderTest"})
public void testBookmarksVisualRefreshBookmarksAndFolder() throws Exception {
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
addFolder(TEST_FOLDER_TITLE);
addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
addFolder(TEST_FOLDER_TITLE);
openBookmarkManager();
BookmarkTestUtil.openMobileBookmarks(mItemsContainer, mDelegate, mBookmarkModel);
mRenderTestRule.render(mBookmarkManagerCoordinator.getView(),
"bookmarks_visual_refresh_bookmarksandfolders");
BookmarkRow itemView1 =
(BookmarkRow) mBookmarkManagerCoordinator.getRecyclerViewForTesting()
.findViewHolderForAdapterPosition(0)
.itemView;
BookmarkRow itemView2 =
(BookmarkRow) mBookmarkManagerCoordinator.getRecyclerViewForTesting()
.findViewHolderForAdapterPosition(1)
.itemView;
toggleSelectionAndEndAnimation(getIdByPosition(0), itemView1);
toggleSelectionAndEndAnimation(getIdByPosition(1), itemView2);
// Make sure the Item "test" is selected.
CriteriaHelper.pollUiThread(
itemView1::isChecked, "Expected item \"test\" to become selected");
CriteriaHelper.pollUiThread(
itemView2::isChecked, "Expected item \"test\" to become selected");
mRenderTestRule.render(mBookmarkManagerCoordinator.getView(),
"bookmarks_compact_visual_refresh_bookmarksandfolders_selected");
}
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testShoppingFilterInBookmarks() throws InterruptedException, ExecutionException {
ShoppingFeatures.setShoppingListEligibleForTesting(true);
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
BookmarkTestUtil.waitForBookmarkModelLoaded();
runOnUiThreadBlocking(() -> { mDelegate.openFolder(mBookmarkModel.getRootFolderId()); });
onView(withText("Tracked products")).perform(click());
// Check that we are in the mobile bookmarks folder.
assertEquals("Tracked products", mToolbar.getTitle());
assertEquals(SelectableListToolbar.NavigationButton.BACK,
mToolbar.getNavigationButtonForTests());
}
@Test
@MediumTest
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void testShoppingDataPresentButFeatureDisabled()
throws InterruptedException, ExecutionException {
ShoppingFeatures.setShoppingListEligibleForTesting(true);
BookmarkId id = addBookmark(TEST_PAGE_TITLE_GOOGLE, mTestPage);
PowerBookmarkMeta.Builder meta = PowerBookmarkMeta.newBuilder().setShoppingSpecifics(
ShoppingSpecifics.newBuilder().setProductClusterId(1234L).build());
runOnUiThreadBlocking(() -> { mBookmarkModel.setPowerBookmarkMeta(id, meta.build()); });
BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO);
openBookmarkManager();
BookmarkTestUtil.waitForBookmarkModelLoaded();
BookmarkRow itemView = (BookmarkRow) mBookmarkManagerCoordinator.getRecyclerViewForTesting()
.findViewHolderForAdapterPosition(0)
.itemView;
assertNotEquals(PowerBookmarkShoppingItemRow.class, itemView.getClass());
}
/**
* Loads a non-empty partner bookmarks folder for testing. The partner bookmarks folder will
* appear in the mobile bookmarks folder.
*/
private void loadFakePartnerBookmarkShimForTesting() {
runOnUiThreadBlocking(() -> { mBookmarkModel.loadFakePartnerBookmarkShimForTesting(); });
BookmarkTestUtil.waitForBookmarkModelLoaded();
}
private void openBookmarkManager() throws InterruptedException {
if (mActivityTestRule.getActivity().isTablet()) {
mActivityTestRule.loadUrl(UrlConstants.BOOKMARKS_URL);
mItemsContainer = mActivityTestRule.getActivity().findViewById(
R.id.selectable_list_recycler_view);
mItemsContainer.setItemAnimator(null); // Disable animation to reduce flakiness.
mBookmarkManagerCoordinator = ((BookmarkPage) mActivityTestRule.getActivity()
.getActivityTab()
.getNativePage())
.getManagerForTesting();
} else {
// Phone.
mBookmarkActivity = ActivityTestUtils.waitForActivity(
InstrumentationRegistry.getInstrumentation(), BookmarkActivity.class,
new MenuUtils.MenuActivityTrigger(InstrumentationRegistry.getInstrumentation(),
mActivityTestRule.getActivity(), R.id.all_bookmarks_menu_id));
mItemsContainer = mBookmarkActivity.findViewById(R.id.selectable_list_recycler_view);
mItemsContainer.setItemAnimator(null); // Disable animation to reduce flakiness.
mBookmarkManagerCoordinator = mBookmarkActivity.getManagerForTesting();
}
mDelegate = mBookmarkManagerCoordinator.getBookmarkDelegateForTesting();
mAdapter = (DragReorderableRecyclerViewAdapter) mItemsContainer.getAdapter();
mToolbar = mBookmarkManagerCoordinator.getToolbarForTesting();
runOnUiThreadBlocking(() -> mDelegate.getDragStateDelegate().setA11yStateForTesting(false));
}
private boolean isItemPresentInBookmarkList(final String expectedTitle) {
return TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
@Override
public Boolean call() {
for (int i = 0; i < mAdapter.getItemCount(); i++) {
BookmarkId item = getIdByPosition(i);
if (item == null) continue;
String actualTitle = mBookmarkModel.getBookmarkTitle(item);
if (TextUtils.equals(actualTitle, expectedTitle)) {
return true;
}
}
return false;
}
});
}
/**
* Adds a bookmark in the scenario where we have partner bookmarks.
*
* @param title The title of the bookmark to add.
* @param url The url of the bookmark to add.
* @return The BookmarkId of the added bookmark.
* @throws ExecutionException If something goes wrong while we are trying to add the bookmark.
*/
private BookmarkId addBookmarkWithPartner(String title, GURL url) throws ExecutionException {
BookmarkTestUtil.loadEmptyPartnerBookmarksForTesting(mBookmarkModel);
return runOnUiThreadBlocking(
() -> mBookmarkModel.addBookmark(mBookmarkModel.getDefaultFolder(), 0, title, url));
}
/**
* Adds a folder in the scenario where we have partner bookmarks.
*
* @param title The title of the folder to add.
* @return The BookmarkId of the added folder.
* @throws ExecutionException If something goes wrong while we are trying to add the bookmark.
*/
private BookmarkId addFolderWithPartner(String title) throws ExecutionException {
BookmarkTestUtil.loadEmptyPartnerBookmarksForTesting(mBookmarkModel);
return runOnUiThreadBlocking(
() -> mBookmarkModel.addFolder(mBookmarkModel.getDefaultFolder(), 0, title));
}
private void simulateDragForTestsOnUiThread(int start, int end) {
runOnUiThreadBlocking(() -> mAdapter.simulateDragForTests(start, end));
}
private boolean isViewHolderPassivelyDraggable(ViewHolder viewHolder) {
return TestThreadUtils.runOnUiThreadBlockingNoException(
() -> mAdapter.isPassivelyDraggable(viewHolder));
}
private boolean isViewHoldersActivelyDraggable(ViewHolder viewHolder) {
return TestThreadUtils.runOnUiThreadBlockingNoException(
() -> mAdapter.isActivelyDraggable(viewHolder));
}
private TestingDelegate getTestingDelegate() {
return mBookmarkManagerCoordinator.getTestingDelegate();
}
private void enterSearch() throws Exception {
clickToolbarMenuItem(R.id.search_menu_id);
CriteriaHelper.pollUiThread(
() -> { return mToolbar.isSearching(); }, "Expected to enter search mode");
}
private void clickMoreButtonOnFirstItem(String expectedBookmarkItemTitle) throws Exception {
View firstItem = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
assertEquals("Wrong bookmark item selected.", expectedBookmarkItemTitle,
firstItem instanceof BookmarkItemRow ? ((BookmarkItemRow) firstItem).getTitle()
: ((BookmarkFolderRow) firstItem).getTitle());
View more = firstItem.findViewById(R.id.more);
runOnUiThreadBlocking(more::performClick);
}
/**
* Returns the View that has the given text.
*
* @param viewGroup The group to which the view belongs.
* @param expectedText The expected description text.
* @return The unique view, if one exists. Throws an exception if one doesn't exist.
*/
private static View getViewWithText(final ViewGroup viewGroup, final String expectedText) {
return TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<View>() {
@Override
public View call() {
ArrayList<View> outViews = new ArrayList<>();
ArrayList<View> matchingViews = new ArrayList<>();
viewGroup.findViewsWithText(outViews, expectedText, View.FIND_VIEWS_WITH_TEXT);
// outViews includes all views whose text contains expectedText as a
// case-insensitive substring. Filter these views to find only exact string matches.
for (View v : outViews) {
if (TextUtils.equals(((TextView) v).getText().toString(), expectedText)) {
matchingViews.add(v);
}
}
assertEquals("Exactly one item should be present.", 1, matchingViews.size());
return matchingViews.get(0);
}
});
}
private void toggleSelectionAndEndAnimation(BookmarkId id, BookmarkRow view) {
runOnUiThreadBlocking(() -> {
mDelegate.getSelectionDelegate().toggleSelectionForItem(id);
view.endAnimationsForTests();
mToolbar.endAnimationsForTesting();
});
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
}
private BookmarkId addBookmark(final String title, GURL url, BookmarkId parent)
throws ExecutionException {
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
return runOnUiThreadBlocking(() -> mBookmarkModel.addBookmark(parent, 0, title, url));
}
private BookmarkId addBookmark(final String title, final GURL url) throws ExecutionException {
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
return runOnUiThreadBlocking(
() -> mBookmarkModel.addBookmark(mBookmarkModel.getDefaultFolder(), 0, title, url));
}
private BookmarkId addFolder(final String title) throws ExecutionException {
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
return runOnUiThreadBlocking(
() -> mBookmarkModel.addFolder(mBookmarkModel.getDefaultFolder(), 0, title));
}
private BookmarkId addFolder(final String title, BookmarkId parent) throws ExecutionException {
BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
return runOnUiThreadBlocking(() -> mBookmarkModel.addFolder(parent, 0, title));
}
private void removeBookmark(final BookmarkId bookmarkId) {
runOnUiThreadBlocking(() -> mBookmarkModel.deleteBookmark(bookmarkId));
}
private BookmarkId getIdByPosition(int pos) {
return getTestingDelegate().getIdByPositionForTesting(pos);
}
private void searchBookmarks(final String query) {
runOnUiThreadBlocking(() -> getTestingDelegate().searchForTesting(query));
}
private void openFolder(BookmarkId folder) {
runOnUiThreadBlocking(() -> mDelegate.openFolder(folder));
RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
}
private void clickToolbarMenuItem(@IdRes int menuId) throws ExecutionException {
runOnUiThreadBlocking(() -> mToolbar.onMenuItemClick(mToolbar.getMenu().findItem(menuId)));
}
}