Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9764)

Unified Diff: chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..81001e2e0aa4fa7ce191046b3f77351fa0c14042
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -0,0 +1,1523 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// 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.contextualsearch;
+
+import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
+import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_PHONE;
+import static org.chromium.content.browser.test.util.CriteriaHelper.DEFAULT_POLLING_INTERVAL;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.Restriction;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.CompositorChromeActivity;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.PanelState;
+import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanelDelegate;
+import org.chromium.chrome.browser.omnibox.UrlBar;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelUtils;
+import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.chrome.test.ChromeActivityTestCaseBase;
+import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.chrome.test.util.OmniboxTestUtils;
+import org.chromium.chrome.test.util.TestHttpServerClient;
+import org.chromium.content.browser.ContentViewCore;
+import org.chromium.content.browser.test.util.CallbackHelper;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.DOMUtils;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Tests the Contextual Search Manager using instrumentation tests.
+ */
+@CommandLineFlags.Add({
+ ChromeSwitches.ENABLE_CONTEXTUAL_SEARCH_FOR_TESTING
+ })
+public class ContextualSearchManagerTest extends ChromeActivityTestCaseBase<ChromeActivity> {
+
+ private static final String TEST_PAGE =
+ TestHttpServerClient.getUrl("chrome/test/data/android/contextualsearch/tap_test.html");
+ private static final int TEST_TIMEOUT = 15000;
+
+ // TODO(donnd): get these from TemplateURL once the low-priority or Contextual Search API
+ // is fully supported.
+ private static final String NORMAL_PRIORITY_SEARCH_ENDPOINT = "/search?";
+ private static final String LOW_PRIORITY_SEARCH_ENDPOINT = "/s?";
+ private static final String CONTEXTUAL_SEARCH_PREFETCH_PARAM = "&pf=c";
+
+ private ContextualSearchManager mManager;
+ private ContextualSearchFakeServer mFakeServer;
+ private ContextualSearchPanelDelegate mPanelDelegate;
+ private ContextualSearchSelectionController mSelectionController;
+ private ContextualSearchPolicy mPolicy;
+ private ChromePreferenceManager mPreferenceManager;
+
+ public ContextualSearchManagerTest() {
+ super(ChromeActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ ChromeActivity activity = getActivity();
+ if (activity instanceof CompositorChromeActivity) {
+ mManager = ((CompositorChromeActivity) activity).getContextualSearchManager();
+ }
+
+ if (mManager != null) {
+ mFakeServer = new ContextualSearchFakeServer(mManager);
+ mManager.setNetworkCommunicator(mFakeServer);
+ mPanelDelegate = mManager.getContextualSearchPanelDelegate();
+ mSelectionController = mManager.getSelectionController();
+ mPolicy = ContextualSearchPolicy.getInstance(getActivity());
+ mPreferenceManager = ChromePreferenceManager.getInstance(getActivity());
+
+ mPolicy.overrideDecidedStateForTesting(true);
+ resetTapCounters();
+ }
+ }
+
+ @Override
+ public void startMainActivity() throws InterruptedException {
+ startMainActivityWithURL(TEST_PAGE);
+ }
+
+ /**
+ * Simulates a click on the given node.
+ * @param nodeId A string containing the node ID.
+ */
+ private void clickNode(String nodeId) throws InterruptedException, TimeoutException {
+ Tab tab = getActivity().getActivityTab();
+ DOMUtils.clickNode(this, tab.getContentViewCore(), nodeId);
+ }
+
+ /**
+ * Simulates a click on the given word node.
+ * Waits for the bar to peek.
+ * @param nodeId A string containing the node ID.
+ */
+ private void clickWordNode(String nodeId) throws InterruptedException, TimeoutException {
+ clickNode(nodeId);
+ waitForPanelToPeekAndAssert();
+ }
+
+ /**
+ * Simulates a key press.
+ * @param keycode The key's code.
+ */
+ private void pressKey(int keycode) {
+ getInstrumentation().sendKeyDownUpSync(keycode);
+ getInstrumentation().waitForIdleSync();
+ }
+
+ /**
+ * Simulates pressing back button.
+ */
+ private void pressBackButton() {
+ pressKey(KeyEvent.KEYCODE_BACK);
+ }
+
+ /**
+ * @return The selected text.
+ */
+ private String getSelectedText() {
+ return mSelectionController.getSelectedText();
+ }
+
+ /**
+ * Simulates a long-press on the given node.
+ * @param nodeId A string containing the node ID.
+ */
+ private void longPressNode(String nodeId) throws InterruptedException, TimeoutException {
+ Tab tab = getActivity().getActivityTab();
+ DOMUtils.longPressNode(this, tab.getContentViewCore(), nodeId);
+ waitForPanelToPeekAndAssert();
+ }
+
+ /**
+ * Posts a fake response on the Main thread.
+ */
+ private final class FakeResponseOnMainThread implements Runnable {
+
+ private final boolean mIsNetworkUnavailable;
+ private final int mResponseCode;
+ private final String mSearchTerm;
+ private final String mDisplayText;
+ private final String mAlternateTerm;
+ private final boolean mDoPreventPreload;
+
+ public FakeResponseOnMainThread(boolean isNetworkUnavailable, int responseCode,
+ String searchTerm, String displayText, String alternateTerm,
+ boolean doPreventPreload) {
+ mIsNetworkUnavailable = isNetworkUnavailable;
+ mResponseCode = responseCode;
+ mSearchTerm = searchTerm;
+ mDisplayText = displayText;
+ mAlternateTerm = alternateTerm;
+ mDoPreventPreload = doPreventPreload;
+ }
+
+ @Override
+ public void run() {
+ mFakeServer.handleSearchTermResolutionResponse(
+ mIsNetworkUnavailable, mResponseCode, mSearchTerm, mDisplayText,
+ mAlternateTerm, mDoPreventPreload);
+ }
+ }
+
+ /**
+ * Fakes a server response with the parameters given.
+ * {@See ContextualSearchManager#handleSearchTermResolutionResponse}.
+ */
+ private void fakeResponse(boolean isNetworkUnavailable, int responseCode,
+ String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload) {
+ if (mFakeServer.getSearchTermRequested() != null) {
+ getInstrumentation().runOnMainSync(
+ new FakeResponseOnMainThread(isNetworkUnavailable, responseCode, searchTerm,
+ displayText, alternateTerm, doPreventPreload));
+ }
+ }
+
+ private void assertContainsParameters(String searchTerm, String alternateTerm) {
+ assertTrue(mFakeServer == null || mFakeServer.getSearchTermRequested() == null
+ || mFakeServer.getLoadedUrl().contains(searchTerm)
+ && mFakeServer.getLoadedUrl().contains(alternateTerm));
+ }
+
+ private void assertContainsNoParameters() {
+ assertTrue(mFakeServer == null || mFakeServer.getLoadedUrl() == null);
+ }
+
+ private void assertSearchTermRequested() {
+ assertNotNull(mFakeServer.getSearchTermRequested());
+ }
+
+ private void assertSearchTermNotRequested() {
+ assertNull(mFakeServer.getSearchTermRequested());
+ }
+
+ private void assertPanelClosedOrUndefined() {
+ boolean success = false;
+ if (mPanelDelegate == null) {
+ success = true;
+ } else {
+ PanelState panelState = mPanelDelegate.getPanelState();
+ success = panelState == PanelState.CLOSED || panelState == PanelState.UNDEFINED;
+ }
+ assertTrue(success);
+ }
+
+ private void assertLoadedNoUrl() {
+ assertTrue("Requested a search or preload when none was expected!",
+ (mFakeServer == null || mFakeServer.getLoadedUrl() == null));
+ }
+
+ private void assertLoadedLowPriorityUrl() {
+ if (mFakeServer == null) return;
+ String message = "Expected a low priority search request URL, but got "
+ + (mFakeServer.getLoadedUrl() != null ? mFakeServer.getLoadedUrl() : "null");
+ assertTrue(message, mFakeServer.getLoadedUrl() != null
+ && mFakeServer.getLoadedUrl().contains(LOW_PRIORITY_SEARCH_ENDPOINT));
+ assertTrue("Low priority request does not have the required prefetch parameter!",
+ mFakeServer.getLoadedUrl() != null
+ && mFakeServer.getLoadedUrl().contains(CONTEXTUAL_SEARCH_PREFETCH_PARAM));
+ }
+
+ private void assertLoadedNormalPriorityUrl() {
+ if (mFakeServer == null) return;
+ String message = "Expected a normal priority search request URL, but got "
+ + (mFakeServer.getLoadedUrl() != null ? mFakeServer.getLoadedUrl() : "null");
+ assertTrue(message, mFakeServer.getLoadedUrl() != null
+ && mFakeServer.getLoadedUrl().contains(NORMAL_PRIORITY_SEARCH_ENDPOINT));
+ assertTrue("Normal priority request should not have the prefetch parameter, but did!",
+ mFakeServer.getLoadedUrl() != null
+ && !mFakeServer.getLoadedUrl().contains(CONTEXTUAL_SEARCH_PREFETCH_PARAM));
+ }
+
+ private void assertNoSearchesLoaded() {
+ assertEquals(0, mFakeServer.loadedUrlCount());
+ assertLoadedNoUrl();
+ }
+
+ private void assertContentViewCoreCreated() {
+ assertTrue(mFakeServer.isSearchContentViewCreated());
+ }
+
+ private void assertNoContentViewCore() {
+ assertFalse(mFakeServer.isSearchContentViewCreated());
+ }
+
+ /**
+ * Fakes navigation of the Content View with the given httpResult code.
+ * The URL of the navigation is the one requested previously.
+ * @param httpResultCode The result to fake.
+ */
+ private void fakeContentViewDidNavigate(int httpResultCode) {
+ String url = mFakeServer.getLoadedUrl();
+ mFakeServer.handleDidNavigateMainFrame(url, httpResultCode);
+ }
+
+ /**
+ * Waits for the Search Panel (the Search Bar) to peek up from the bottom, and asserts that it
+ * did peek.
+ * @throws InterruptedException
+ */
+ private void waitForPanelToPeekAndAssert() throws InterruptedException {
+ assertTrue("Search Bar did not peek.", waitForPanelToEnterState(PanelState.PEEKED));
+ }
+
+ /**
+ * Waits for the Search Panel to expand, and asserts that it did expand.
+ * @throws InterruptedException
+ */
+ private void waitForPanelToExpandAndAssert() throws InterruptedException {
+ assertTrue("Search Bar did not expand.", waitForPanelToEnterState(PanelState.EXPANDED));
+ }
+
+ /**
+ * Waits for the Search Panel to maximize, and asserts that it did maximize.
+ * @throws InterruptedException
+ */
+ private void waitForPanelToMaximizeAndAssert() throws InterruptedException {
+ assertTrue("Search Bar did not maximize.", waitForPanelToEnterState(PanelState.MAXIMIZED));
+ }
+
+ /**
+ * Waits for the Search Panel to close, and asserts that it did close.
+ * @throws InterruptedException
+ */
+ private void waitForPanelToCloseAndAssert() throws InterruptedException {
+ // TODO(donnd): figure out why using waitForPanelToEnterState here doesn't work.
+ assertTrue("Search Bar did not close.",
+ CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ return !mManager.isSearchPanelShowing();
+ }
+ }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+ }
+
+ /**
+ * Waits for the Search Panel to enter the given {@code PanelState}.
+ * @throws InterruptedException
+ */
+ private boolean waitForPanelToEnterState(final PanelState state) throws InterruptedException {
+ return CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ return mPanelDelegate != null
+ && mPanelDelegate.getPanelState() == state;
+ }
+ }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
+ }
+
+ /**
+ * Waits for the manager to finish processing a gesture.
+ * Tells the manager that a gesture has started, and then waits for it to complete.
+ * @throws InterruptedException
+ */
+ private void waitForGestureProcessingAndAssert() throws InterruptedException {
+ assertTrue("Gesture processing did not complete.",
+ CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ return !mSelectionController.wasAnyTapGestureDetected();
+ }
+ }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+ }
+
+ /**
+ * Shorthand for a common sequence:
+ * 1) Waits for gesture processing,
+ * 2) Waits for the panel to close,
+ * 3) Asserts that there is no selection and that the panel closed.
+ * @throws InterruptedException
+ */
+ private void waitForGestureToClosePanelAndAssertNoSelection() throws InterruptedException {
+ waitForGestureProcessingAndAssert();
+ waitForPanelToCloseAndAssert();
+ assertPanelClosedOrUndefined();
+ assertNull(getSelectedText());
+ }
+
+ /**
+ * Waits for the selected text string to be the given string, and asserts.
+ * @param text The string to wait for the selection to become.
+ */
+ private void waitForSelectionToBe(final String text) throws InterruptedException {
+ assertTrue("Bar never showed desired text.",
+ CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ return TextUtils.equals(text, getSelectedText());
+ }
+ }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+ }
+
+ /**
+ * A ContentViewCore that has some methods stubbed out for testing.
+ */
+ private static final class StubbedContentViewCore extends ContentViewCore {
+ private boolean mIsFocusedNodeEditable;
+
+ public StubbedContentViewCore(Context context) {
+ super(context);
+ }
+
+ public void setIsFocusedNodeEditableForTest(boolean isFocusedNodeEditable) {
+ mIsFocusedNodeEditable = isFocusedNodeEditable;
+ }
+
+ @Override
+ public boolean isFocusedNodeEditable() {
+ return mIsFocusedNodeEditable;
+ }
+ }
+
+ /**
+ * Generate a swipe sequence from the give start/end X,Y percentages, for the given steps.
+ * Works in either landscape or portrait orientation.
+ */
+ private void swipe(float startX, float startY, float endX, float endY, int stepCount) {
+ Point size = new Point();
+ getActivity().getWindowManager().getDefaultDisplay().getSize(size);
+ float dragStartX = size.x * startX;
+ float dragEndX = size.x * endX;
+ float dragStartY = size.y * startY;
+ float dragEndY = size.y * endY;
+ long downTime = SystemClock.uptimeMillis();
+ dragStart(dragStartX, dragStartY, downTime);
+ dragTo(dragStartX, dragEndX, dragStartY, dragEndY, stepCount, downTime);
+ dragEnd(dragEndX, dragEndY, downTime);
+ }
+
+ /**
+ * Swipes the panel up to it's expanded size.
+ */
+ private void swipePanelUp() {
+ swipe(0.5f, 0.95f, 0.5f, 0.55f, 1000);
+ }
+
+ /**
+ * Swipes the panel up to it's maximized size.
+ */
+ private void swipePanelUpToTop() {
+ swipe(0.5f, 0.95f, 0.5f, 0.05f, 1000);
+ }
+
+ /**
+ * Scrolls the base page.
+ */
+ private void scrollBasePage() {
+ swipe(0.f, 0.75f, 0.f, 0.7f, 100);
+ }
+
+ /**
+ * Taps the base page near the top.
+ */
+ private void tapBasePage() throws InterruptedException {
+ tapBasePage(0.1f, 0.1f);
+ }
+
+ /**
+ * Taps the base page at the given x, y position.
+ */
+ private void tapBasePage(float x, float y) throws InterruptedException {
+ Point size = new Point();
+ getActivity().getWindowManager().getDefaultDisplay().getSize(size);
+ x *= size.x;
+ y *= size.y;
+ singleClick(x, y);
+ waitForPanelToCloseAndAssert();
+ }
+
+ /**
+ * Click various places to cause the panel to show, expand, then close.
+ */
+ private void clickToExpandAndClosePanel() throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ tapPeekingBarToExpandAndAssert();
+ tapBasePage();
+ waitForPanelToCloseAndAssert();
+ }
+
+ /**
+ * Generate a click in the panel's bar.
+ * @barHeight The vertical position where the click should take place as a percentage
+ * of the screen size.
+ */
+ private void clickPanelBar(float barPositionVertical) {
+ Point size = new Point();
+ getActivity().getWindowManager().getDefaultDisplay().getSize(size);
+ float w = size.x;
+ float h = size.y;
+ boolean landscape = w > h;
+ float tapX = landscape ? w * barPositionVertical : w / 2f;
+ float tapY = landscape ? h / 2f : h * barPositionVertical;
+
+ singleClick(tapX, tapY);
+ }
+
+ /**
+ * Taps the peeking bar to expand the panel
+ */
+ private void tapPeekingBarToExpandAndAssert() throws InterruptedException {
+ clickPanelBar(0.95f);
+ waitForPanelToExpandAndAssert();
+ }
+
+ /**
+ * Simple sequence useful for checking if a Search Term Resolution request is sent.
+ * Resets the fake server and clicks near to cause a search, then clicks far to let the panel
+ * drop down (taking us back to the same state).
+ */
+ private void clickToTriggerSearchTermResolution()
+ throws InterruptedException, TimeoutException {
+ mFakeServer.reset();
+ clickWordNode("states");
+ clickNode("states-far");
+ waitForPanelToCloseAndAssert();
+ }
+
+ /**
+ * Simple sequence useful for checking if a Search Request is prefetched.
+ * Resets the fake server and clicks near to cause a search, fakes a server response to
+ * trigger a prefetch, then clicks far to let the panel drop down
+ * which takes us back to the starting state except the the fake server knows
+ * if a prefetch occurred.
+ */
+ private void clickToTriggerPrefetch() throws InterruptedException, TimeoutException {
+ mFakeServer.reset();
+ clickWordNode("states");
+ assertSearchTermRequested();
+ fakeResponse(false, 200, "States", "display-text", "alternate-term", false);
+ waitForPanelToPeekAndAssert();
+ clickNode("states-far");
+ }
+
+ /**
+ * Simple sequence to click, resolve, and prefetch. Verifies a prefetch occurred.
+ */
+ private void clickToResolveAndAssertPrefetch() throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ assertLoadedNoUrl();
+ assertSearchTermRequested();
+
+ fakeResponse(false, 200, "states", "United States Intelligence", "alternate-term", false);
+ waitForPanelToPeekAndAssert();
+ assertLoadedLowPriorityUrl();
+ assertContainsParameters("states", "alternate-term");
+ }
+
+ /**
+ * Resets the tap counters on the UI thread.
+ */
+ private void resetTapCounters() throws InterruptedException {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mPolicy.resetTapCounters();
+ // The "Promo" tap counter is never reset outside of testing because it
+ // is used to persistently count the number of peeks *ever* seen by the user
+ // before the first open, and is then frozen in a disabled state to record that
+ // value rather than being reset.
+ // We reset it here to simulate a new user for our feature.
+ mPreferenceManager.setContextualSearchTapTriggeredPromoCount(0);
+ }
+ });
+ CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ return mPolicy.didResetTapCounters();
+ }
+ }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
+ }
+
+ /**
+ * Tests whether the contextual search panel hides when omnibox is clicked.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testHidesWhenOmniboxFocused() throws InterruptedException, TimeoutException {
+ clickWordNode("intelligence");
+
+ assertEquals("Intelligence", mFakeServer.getSearchTermRequested());
+ fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false);
+ assertContainsParameters("Intelligence", "alternate-term");
+ waitForPanelToPeekAndAssert();
+
+ OmniboxTestUtils.toggleUrlBarFocus((UrlBar) getActivity().findViewById(R.id.url_bar), true);
+
+ assertPanelClosedOrUndefined();
+ }
+
+ /**
+ * Tests the doesContainAWord method.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testDoesContainAWord() {
+ assertTrue(mManager.doesContainAWord("word"));
+ assertTrue(mManager.doesContainAWord("word "));
+ assertFalse("Emtpy string should not be considered a word!",
+ mManager.doesContainAWord(""));
+ assertFalse("Special symbols should not be considered a word!",
+ mManager.doesContainAWord("@"));
+ assertFalse("White space should not be considered a word",
+ mManager.doesContainAWord(" "));
+ assertTrue(mManager.doesContainAWord("Q2"));
+ assertTrue(mManager.doesContainAWord("123"));
+ }
+
+ /**
+ * Tests the isValidSelection method.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testIsValidSelection() {
+ StubbedContentViewCore stubbedCvc = new StubbedContentViewCore(
+ getActivity().getBaseContext());
+ assertTrue(mManager.isValidSelection("valid", stubbedCvc));
+ assertFalse(mManager.isValidSelection(" ", stubbedCvc));
+ stubbedCvc.setIsFocusedNodeEditableForTest(true);
+ assertFalse(mManager.isValidSelection("editable", stubbedCvc));
+ stubbedCvc.setIsFocusedNodeEditableForTest(false);
+ String numberString = "0123456789";
+ StringBuilder longStringBuilder = new StringBuilder();
+ for (int i = 0; i < 11; i++) {
+ longStringBuilder.append(numberString);
+ }
+ assertTrue(mManager.isValidSelection(numberString, stubbedCvc));
+ assertFalse(mManager.isValidSelection(longStringBuilder.toString(),
+ stubbedCvc));
+ }
+
+ /**
+ * Tests a simple Tap.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTap() throws InterruptedException, TimeoutException {
+ clickWordNode("intelligence");
+
+ assertEquals("Intelligence", mFakeServer.getSearchTermRequested());
+ fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false);
+ assertContainsParameters("Intelligence", "alternate-term");
+ waitForPanelToPeekAndAssert();
+ assertLoadedLowPriorityUrl();
+ }
+
+ /**
+ * Tests a simple Long-Press gesture, without opening the panel.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testLongPress() throws InterruptedException, TimeoutException {
+ longPressNode("states");
+
+ assertNull(mFakeServer.getSearchTermRequested());
+ waitForPanelToPeekAndAssert();
+ assertLoadedNoUrl();
+ assertNoContentViewCore();
+ }
+
+ /**
+ * Tests swiping the overlay open, after an initial tap that activates the peeking card.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testSwipeExpand() throws InterruptedException, TimeoutException {
+ assertNoSearchesLoaded();
+ clickWordNode("intelligence");
+ assertNoSearchesLoaded();
+
+ // Fake a search term resolution response.
+ fakeResponse(false, 200, "Intelligence", "United States Intelligence", "alternate-term",
+ false);
+ assertContainsParameters("Intelligence", "alternate-term");
+ assertEquals(1, mFakeServer.loadedUrlCount());
+ assertLoadedLowPriorityUrl();
+
+ waitForPanelToPeekAndAssert();
+ swipePanelUp();
+ waitForPanelToExpandAndAssert();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+ assertLoadedLowPriorityUrl();
+ }
+
+ /**
+ * Tests swiping the overlay open, after an initial long-press that activates the peeking card,
+ * followed by closing the panel.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testLongPressSwipeExpand() throws InterruptedException, TimeoutException {
+ longPressNode("intelligence");
+ assertNoContentViewCore();
+
+ // Fake a search term resolution response.
+ fakeResponse(false, 200, "Intelligence", "United States Intelligence", "alternate-term",
+ false);
+ assertContainsParameters("Intelligence", "alternate-term");
+
+ waitForPanelToPeekAndAssert();
+ assertLoadedNoUrl();
+ assertNoContentViewCore();
+ swipePanelUp();
+ waitForPanelToExpandAndAssert();
+ assertContentViewCoreCreated();
+ assertLoadedNormalPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+
+ // tap the base page to close.
+ tapBasePage();
+ waitForPanelToCloseAndAssert();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+ assertNoContentViewCore();
+ }
+
+ /**
+ * Tests a sequence in landscape orientation: swiping the overlay open, after an
+ * initial tap that activates the peeking card.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testSwipeExpandLandscape() throws InterruptedException, TimeoutException {
+ getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ testSwipeExpand();
+ getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ }
+
+ /**
+ * Tests tap to expand, after an initial tap to activate the peeking card.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapExpand() throws InterruptedException, TimeoutException {
+ assertNoSearchesLoaded();
+ clickWordNode("states");
+ assertNoContentViewCore();
+ assertNoSearchesLoaded();
+
+ // Fake a search term resolution response.
+ fakeResponse(false, 200, "states", "United States Intelligence", "alternate-term", false);
+ assertContainsParameters("states", "alternate-term");
+ assertEquals(1, mFakeServer.loadedUrlCount());
+ assertLoadedLowPriorityUrl();
+ assertContentViewCoreCreated();
+ tapPeekingBarToExpandAndAssert();
+ assertLoadedLowPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+
+ // tap the base page to close.
+ tapBasePage();
+ waitForPanelToCloseAndAssert();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+ assertNoContentViewCore();
+ }
+
+ /**
+ * Tests that only a single low-priority request is issued for a Tap/Open sequence.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapCausesOneLowPriorityRequest() throws InterruptedException, TimeoutException {
+ mFakeServer.reset();
+ clickWordNode("states");
+
+ // We should not make a second-request until we get a good response from the first-request.
+ assertLoadedNoUrl();
+ assertEquals(0, mFakeServer.loadedUrlCount());
+ fakeResponse(false, 200, "states", "United States Intelligence", "alternate-term", false);
+ assertLoadedLowPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+
+ // When the second request succeeds, we should not issue a new request.
+ fakeContentViewDidNavigate(200);
+ assertLoadedLowPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+
+ // When the bar opens, we should not make any additional request.
+ tapPeekingBarToExpandAndAssert();
+ assertLoadedLowPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+ assertLoadedLowPriorityUrl();
+ }
+
+ /**
+ * Tests that a failover for a prefetch request is issued after the panel is opened.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testPrefetchFailoverRequestMadeAfterOpen()
+ throws InterruptedException, TimeoutException {
+ mFakeServer.reset();
+ clickWordNode("states");
+
+ // We should not make a SERP request until we get a good response from the resolve request.
+ assertLoadedNoUrl();
+ assertEquals(0, mFakeServer.loadedUrlCount());
+ fakeResponse(false, 200, "states", "United States Intelligence", "alternate-term", false);
+ assertLoadedLowPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+
+ // When the second request fails, we should not issue a new request.
+ fakeContentViewDidNavigate(500);
+ assertLoadedLowPriorityUrl();
+ assertEquals(1, mFakeServer.loadedUrlCount());
+
+ // Once the bar opens, we make a new request at normal priority.
+ tapPeekingBarToExpandAndAssert();
+ assertLoadedNormalPriorityUrl();
+ assertEquals(2, mFakeServer.loadedUrlCount());
+ }
+
+ /**
+ * Tests a simple Tap with disable-preload set.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapDisablePreload() throws InterruptedException, TimeoutException {
+ clickWordNode("intelligence");
+
+ assertSearchTermRequested();
+ fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", true);
+ assertContainsNoParameters();
+ waitForPanelToPeekAndAssert();
+ assertLoadedNoUrl();
+ }
+
+ /**
+ * Tests that long-press selects text, and a subsequent tap will unselect text.
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testLongPressGestureSelects() throws InterruptedException, TimeoutException {
+ longPressNode("intelligence");
+ assertEquals("Intelligence", getSelectedText());
+ fakeResponse(false, 200, "Intelligence", "Intelligence", "alternate-term", false);
+ assertContainsParameters("Intelligence", "alternate-term");
+ waitForPanelToPeekAndAssert();
+ assertLoadedNoUrl(); // No load after long-press until opening panel.
+ clickNode("question-mark");
+ waitForGestureProcessingAndAssert();
+ assertNull(getSelectedText());
+ assertPanelClosedOrUndefined();
+ assertLoadedNoUrl();
+ }
+
+ /**
+ * Tests that a Tap gesture selects the expected text.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGestureSelects() throws InterruptedException, TimeoutException {
+ clickWordNode("intelligence");
+ assertEquals("Intelligence", getSelectedText());
+ fakeResponse(false, 200, "Intelligence", "Intelligence", "alternate-term", false);
+ assertContainsParameters("Intelligence", "alternate-term");
+ waitForPanelToPeekAndAssert();
+ assertLoadedLowPriorityUrl();
+ clickNode("question-mark");
+ waitForGestureProcessingAndAssert();
+ assertNull(getSelectedText());
+ }
+
+ /**
+ * Tests that a Tap gesture on a special character does not select or show the panel.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGestureOnSpecialCharacterDoesntSelect()
+ throws InterruptedException, TimeoutException {
+ clickNode("question-mark");
+ waitForGestureProcessingAndAssert();
+ assertNull(getSelectedText());
+ assertPanelClosedOrUndefined();
+ assertLoadedNoUrl();
+ }
+
+ /**
+ * Tests that a Tap gesture followed by scrolling clears the selection.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGestureFollowedByScrollClearsSelection()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("intelligence");
+ fakeResponse(false, 200, "Intelligence", "Intelligence", "alternate-term", false);
+ assertContainsParameters("Intelligence", "alternate-term");
+ waitForPanelToPeekAndAssert();
+ assertLoadedLowPriorityUrl();
+ scrollBasePage();
+ assertPanelClosedOrUndefined();
+ assertNull(mSelectionController.getSelectedText());
+ }
+
+ /**
+ * Tests that a Tap gesture followed by tapping an invalid character doesn't select.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGestureFollowedByInvalidTextTapCloses()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("states-far");
+ waitForPanelToPeekAndAssert();
+ clickNode("question-mark");
+ waitForGestureProcessingAndAssert();
+ assertPanelClosedOrUndefined();
+ assertNull(mSelectionController.getSelectedText());
+ }
+
+ /**
+ * Tests that a Tap gesture followed by tapping a non-text character doesn't select.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGestureFollowedByNonTextTap()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("states-far");
+ waitForPanelToPeekAndAssert();
+ clickNode("button");
+ waitForGestureProcessingAndAssert();
+ assertPanelClosedOrUndefined();
+ assertNull(mSelectionController.getSelectedText());
+ }
+
+ /**
+ * Tests that a Tap gesture far away toggles selecting text.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGestureFarAwayTogglesSelecting()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ assertEquals("States", getSelectedText());
+ waitForPanelToPeekAndAssert();
+ clickNode("states-far");
+ waitForGestureProcessingAndAssert();
+ assertNull(getSelectedText());
+ assertPanelClosedOrUndefined();
+ clickNode("states-far");
+ waitForGestureProcessingAndAssert();
+ waitForPanelToPeekAndAssert();
+ assertEquals("States", getSelectedText());
+ }
+
+ /**
+ * Tests that sequential Tap gestures nearby keep selecting.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapGesturesNearbyKeepSelecting()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ assertEquals("States", getSelectedText());
+ waitForPanelToPeekAndAssert();
+ // Because sequential taps never hide the bar, we we can't wait for it to peek.
+ // Instead we use clickNode (which doesn't wait) instead of clickWordNode and wait
+ // for the selection to change.
+ clickNode("states-near");
+ waitForSelectionToBe("StatesNear");
+ clickNode("states");
+ waitForSelectionToBe("States");
+ }
+
+ /**
+ * Tests that a long-press gesture followed by scrolling does not clear the selection.
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testLongPressGestureFollowedByScrollMaintainsSelection()
+ throws InterruptedException, TimeoutException {
+ longPressNode("intelligence");
+ waitForPanelToPeekAndAssert();
+ scrollBasePage();
+ assertPanelClosedOrUndefined();
+ assertEquals("Intelligence", getSelectedText());
+ assertLoadedNoUrl();
+ }
+
+ /**
+ * Tests that a long-press gesture followed by a tap does not select.
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testLongPressGestureFollowedByTapDoesntSelect()
+ throws InterruptedException, TimeoutException {
+ longPressNode("intelligence");
+ waitForPanelToPeekAndAssert();
+ clickWordNode("states-far");
+ waitForGestureToClosePanelAndAssertNoSelection();
+ assertLoadedNoUrl();
+ }
+
+ /**
+ * Tests that the panel closes when its base page crashes.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testContextualSearchDismissedOnForegroundTabCrash()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ assertEquals("States", getSelectedText());
+ waitForPanelToPeekAndAssert();
+
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().getActivityTab().simulateRendererKilledForTesting(true);
+ }
+ });
+
+ // Give the panelState time to change
+ CriteriaHelper.pollForCriteria(new Criteria(){
+ @Override
+ public boolean isSatisfied() {
+ PanelState panelState = mPanelDelegate.getPanelState();
+ return panelState != PanelState.PEEKED;
+ }
+ });
+
+ assertPanelClosedOrUndefined();
+ }
+
+ /**
+ * Test the the panel does not close when some background tab crashes.
+ */
+ @CommandLineFlags.Add(ChromeSwitches.DISABLE_DOCUMENT_MODE)
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testContextualSearchNotDismissedOnBackgroundTabCrash()
+ throws InterruptedException, TimeoutException {
+ ChromeTabUtils.newTabFromMenu(getInstrumentation(),
+ (ChromeTabbedActivity) getActivity());
+ final Tab tab2 = TabModelUtils.getCurrentTab(getActivity().getCurrentTabModel());
+
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TabModelUtils.setIndex(getActivity().getCurrentTabModel(), 0);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ clickWordNode("states");
+ assertEquals("States", getSelectedText());
+ waitForPanelToPeekAndAssert();
+
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ tab2.simulateRendererKilledForTesting(false);
+ }
+ });
+
+ // Give the panelState time to change
+ CriteriaHelper.pollForCriteria(new Criteria(){
+ @Override
+ public boolean isSatisfied() {
+ PanelState panelState = mPanelDelegate.getPanelState();
+ return panelState != PanelState.PEEKED;
+ }
+ });
+
+ waitForPanelToPeekAndAssert();
+ }
+
+ /*
+ * Test that tapping on the Search Bar before having a resolved search term does not
+ * promote to a tab, and that after the resolution it does promote to a tab.
+ *
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ */
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ @CommandLineFlags.Add(ChromeSwitches.DISABLE_DOCUMENT_MODE)
+ @FlakyTest
+ public void testTapSearchBarPromotesToTab() throws InterruptedException, TimeoutException {
+ // Tap on a word.
+ clickWordNode("intelligence");
+ assertSearchTermRequested();
+
+ // Wait for the panel to peek.
+ waitForPanelToPeekAndAssert();
+
+ // Swipe Panel up and wait for it to maximize.
+ swipePanelUpToTop();
+ waitForPanelToMaximizeAndAssert();
+
+ // Create an observer to track that a new tab is created.
+ final CallbackHelper tabCreatedHelper = new CallbackHelper();
+ int tabCreatedHelperCallCount = tabCreatedHelper.getCallCount();
+ TabModelSelectorObserver observer = new EmptyTabModelSelectorObserver() {
+ @Override
+ public void onNewTabCreated(Tab tab) {
+ tabCreatedHelper.notifyCalled();
+ }
+ };
+ getActivity().getTabModelSelector().addObserver(observer);
+
+ // Tap the Search Bar.
+ clickPanelBar(0.05f);
+
+ // The Search Term Resolution response hasn't arrived yet, so the Panel should not
+ // be promoted. Therefore, we are asserting that the Panel is still maximized.
+ waitForPanelToMaximizeAndAssert();
+
+ // Get a Search Term Resolution response.
+ fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false);
+ assertContainsParameters("Intelligence", "alternate-term");
+
+ // Tap the Search Bar again.
+ clickPanelBar(0.05f);
+
+ // Now that the response has arrived, tapping on the Search Panel should promote it
+ // to a Tab. Therefore, we are asserting that the Panel got closed.
+ waitForPanelToCloseAndAssert();
+
+ // Finally, make sure a tab was created.
+ if (!FeatureUtilities.isDocumentMode(getInstrumentation().getContext())) {
+ // TODO(donnd): figure out how to check for tab creation in Document mode.
+ tabCreatedHelper.waitForCallback(tabCreatedHelperCallCount);
+ }
+ getActivity().getTabModelSelector().removeObserver(observer);
+ }
+
+ /**
+ * Tests that a Tap gesture on an element with an ARIA role does not trigger.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapOnRoleIgnored() throws InterruptedException, TimeoutException {
+ clickNode("role");
+ waitForGestureToClosePanelAndAssertNoSelection();
+ }
+
+ /**
+ * Tests that a Tap gesture on an element with an ARIA attribute does not trigger.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapOnARIAIgnored() throws InterruptedException, TimeoutException {
+ clickNode("aria");
+ waitForGestureToClosePanelAndAssertNoSelection();
+ }
+
+ /**
+ * Tests that a Tap gesture on an element that is focusable does not trigger.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testTapOnFocusableIgnored() throws InterruptedException, TimeoutException {
+ clickNode("focusable");
+ waitForGestureToClosePanelAndAssertNoSelection();
+ }
+
+ /**
+ * Tests that taps can be resolve-limited for decided users.
+ * @CommandLineFlags.Add(
+ * ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_TAP_RESOLVE_LIMIT_FOR_DECIDED + "=2")
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ * crbug.com/487759
+ */
+ @FlakyTest
+ public void testTapResolveLimitForDecided() throws InterruptedException, TimeoutException {
+ clickToTriggerSearchTermResolution();
+ assertSearchTermRequested();
+ clickToTriggerSearchTermResolution();
+ assertSearchTermRequested();
+ // 3rd click should not resolve.
+ clickToTriggerSearchTermResolution();
+ assertSearchTermNotRequested();
+
+ // Expanding the panel should reset the limit.
+ clickToExpandAndClosePanel();
+
+ // Click should resolve again.
+ clickToTriggerSearchTermResolution();
+ assertSearchTermRequested();
+ }
+
+ /**
+ * Tests that taps can be resolve-limited for undecided users.
+ * @CommandLineFlags.Add({
+ * ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_TAP_RESOLVE_LIMIT_FOR_UNDECIDED + "=2"})
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ * crbug.com/487759
+ */
+ @FlakyTest
+ public void testTapResolveLimitForUndecided() throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(false);
+
+ clickToTriggerSearchTermResolution();
+ assertSearchTermRequested();
+ clickToTriggerSearchTermResolution();
+ assertSearchTermRequested();
+ // 3rd click should not resolve.
+ clickToTriggerSearchTermResolution();
+ assertSearchTermNotRequested();
+
+ // Expanding the panel should reset the limit.
+ clickToExpandAndClosePanel();
+
+ // Click should resolve again.
+ clickToTriggerSearchTermResolution();
+ assertSearchTermRequested();
+ }
+
+ /**
+ * Tests that taps can be preload-limited for decided users.
+ * @CommandLineFlags.Add(
+ * ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_TAP_PREFETCH_LIMIT_FOR_DECIDED + "=2")
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ * crbug.com/487759
+ */
+ @FlakyTest
+ public void testTapPrefetchLimitForDecided() throws InterruptedException, TimeoutException {
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ // 3rd click should not preload.
+ clickToTriggerPrefetch();
+ assertLoadedNoUrl();
+
+ // Expanding the panel should reset the limit.
+ clickToExpandAndClosePanel();
+
+ // Click should preload again.
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ }
+
+ /**
+ * Tests that taps can be preload-limited for undecided users.
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ * @CommandLineFlags.Add(
+ * ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_TAP_PREFETCH_LIMIT_FOR_UNDECIDED + "=2")
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * crbug.com/487759
+ */
+ @FlakyTest
+ public void testTapPrefetchLimitForUndecided() throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(false);
+
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ // 3rd click should not preload.
+ clickToTriggerPrefetch();
+ assertLoadedNoUrl();
+
+ // Expanding the panel should reset the limit.
+ clickToExpandAndClosePanel();
+
+ // Click should preload again.
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ }
+
+ /**
+ * Tests the tap triggered promo limit for opt-out.
+ * @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ * @CommandLineFlags.Add({
+ * ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_PROMO_ON_LIMITED_TAPS + "=true",
+ * ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_LIMIT + "=2"})
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ * crbug.com/487759
+ */
+ @FlakyTest
+ public void testTapTriggeredPromoLimitForOptOut()
+ throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(false);
+
+ clickWordNode("states");
+ clickNode("states-far");
+ waitForPanelToCloseAndAssert();
+ clickWordNode("states");
+ clickNode("states-far");
+ waitForPanelToCloseAndAssert();
+
+ // 3rd click won't peek the panel.
+ clickNode("states");
+ assertPanelClosedOrUndefined();
+ // The Tap should not select any text either!
+ assertNull(getSelectedText());
+
+ // A long-press should still show the promo bar.
+ longPressNode("states");
+ waitForPanelToPeekAndAssert();
+
+ // Expanding the panel should deactivate the limit.
+ clickToExpandAndClosePanel();
+
+ // Three taps should work now.
+ clickWordNode("states");
+ clickNode("states-far");
+ waitForPanelToCloseAndAssert();
+ clickWordNode("states");
+ clickNode("states-far");
+ waitForPanelToCloseAndAssert();
+ clickWordNode("states");
+ clickNode("states-far");
+ waitForPanelToCloseAndAssert();
+ }
+
+ /**
+ * This is a test that happens to create a separate bar without any content area!
+ *
+ * @SmallTest
+ * @Feature({"ContextualSearch"})
+ */
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ @FlakyTest
+ @CommandLineFlags.Add(
+ ContextualSearchFieldTrial.CONTEXTUAL_SEARCH_TAP_PREFETCH_LIMIT_FOR_DECIDED + "=2")
+ public void testDisembodiedBar() throws InterruptedException, TimeoutException {
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ // 3rd click should not preload.
+ clickToTriggerPrefetch();
+ assertLoadedNoUrl();
+
+ // Expanding the panel should reset the limit.
+ swipePanelUp();
+ singleClick(0.5f, 0.5f);
+ waitForPanelToCloseAndAssert();
+
+ // Click should preload again.
+ clickToTriggerPrefetch();
+ assertLoadedLowPriorityUrl();
+ }
+
+ /**
+ * Tests expanding the panel before the search term has resolved, verifies that nothing
+ * loads until the resolve completes and that it's now a normal priority URL.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testExpandBeforeSearchTermResolution()
+ throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ assertNoContentViewCore();
+
+ // Expanding before the search term resolves should not load anything.
+ tapPeekingBarToExpandAndAssert();
+ assertLoadedNoUrl();
+
+ // Once the response comes in, it should load.
+ fakeResponse(false, 200, "states", "United States Intelligence", "alternate-term", false);
+ assertContainsParameters("states", "alternate-term");
+ assertLoadedNormalPriorityUrl();
+ assertContentViewCoreCreated();
+ }
+
+ /**
+ * Tests that an error from the Search Term Resolution request causes a fallback to a
+ * search request for the literal selection.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testSearchTermResolutionError() throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ assertSearchTermRequested();
+ fakeResponse(false, 403, "", "", "", false);
+ assertLoadedNoUrl();
+ tapPeekingBarToExpandAndAssert();
+ assertLoadedNormalPriorityUrl();
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // HTTP/HTTPS for Undecided/Decided users.
+ // --------------------------------------------------------------------------------------------
+
+ /**
+ * Tests that HTTPS does not resolve in the opt-out model before the user accepts.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testHttpsBeforeAcceptForOptOut() throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(false);
+ mFakeServer.setShouldUseHttps(true);
+
+ clickWordNode("states");
+ assertLoadedLowPriorityUrl();
+ assertSearchTermNotRequested();
+ }
+
+ /**
+ * Tests that HTTPS does resolve in the opt-out model after the user accepts.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testHttpsAfterAcceptForOptOut() throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(true);
+ mFakeServer.setShouldUseHttps(true);
+
+ clickToResolveAndAssertPrefetch();
+ }
+
+ /**
+ * Tests that HTTP does resolve in the opt-out model before the user accepts.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testHttpBeforeAcceptForOptOut() throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(false);
+
+ clickToResolveAndAssertPrefetch();
+ }
+
+ /**
+ * Tests that HTTP does resolve in the opt-out model after the user accepts.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testHttpAfterAcceptForOptOut() throws InterruptedException, TimeoutException {
+ mPolicy.overrideDecidedStateForTesting(true);
+
+ clickToResolveAndAssertPrefetch();
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // App Menu Suppression
+ // --------------------------------------------------------------------------------------------
+
+ /**
+ * Simulates pressing the App Menu button.
+ */
+ private void pressAppMenuKey() {
+ pressKey(KeyEvent.KEYCODE_MENU);
+ }
+
+ /**
+ * Asserts whether the App Menu is visible.
+ */
+ private void assertAppMenuVisibility(final boolean isVisible) throws InterruptedException {
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ if (((CompositorChromeActivity) getActivity())
+ .getAppMenuHandler().isAppMenuShowing() == isVisible) return true;
+ return false;
+ }
+ }));
+ }
+
+ /**
+ * Tests that the App Menu gets suppressed when Search Panel is expanded.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testAppMenuSuppressedWhenExpanded() throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ tapPeekingBarToExpandAndAssert();
+
+ pressAppMenuKey();
+ assertAppMenuVisibility(false);
+
+ tapBasePage();
+ waitForPanelToCloseAndAssert();
+
+ pressAppMenuKey();
+ assertAppMenuVisibility(true);
+ }
+
+ /**
+ * Tests that the App Menu gets suppressed when Search Panel is maximized.
+ */
+ @SmallTest
+ @Feature({"ContextualSearch"})
+ @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+ public void testAppMenuSuppressedWhenMaximized() throws InterruptedException, TimeoutException {
+ clickWordNode("states");
+ swipePanelUpToTop();
+ waitForPanelToMaximizeAndAssert();
+
+ pressAppMenuKey();
+ assertAppMenuVisibility(false);
+
+ pressBackButton();
+ waitForPanelToCloseAndAssert();
+
+ pressAppMenuKey();
+ assertAppMenuVisibility(true);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698