Index: chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f686d672bb2b1547c17e47552020edb780a7356b |
--- /dev/null |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java |
@@ -0,0 +1,368 @@ |
+// 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.ntp; |
+ |
+import android.test.suitebuilder.annotation.LargeTest; |
+import android.test.suitebuilder.annotation.MediumTest; |
+import android.test.suitebuilder.annotation.SmallTest; |
+import android.view.KeyEvent; |
+import android.view.View; |
+import android.view.ViewGroup; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.chrome.browser.EmptyTabObserver; |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.UrlConstants; |
+import org.chromium.chrome.browser.omnibox.LocationBarLayout; |
+import org.chromium.chrome.browser.omnibox.UrlBar; |
+import org.chromium.chrome.test.ChromeTabbedActivityTestBase; |
+import org.chromium.chrome.test.util.ChromeTabUtils; |
+import org.chromium.chrome.test.util.NewTabPageTestUtils; |
+import org.chromium.chrome.test.util.OmniboxTestUtils; |
+import org.chromium.chrome.test.util.TestHttpServerClient; |
+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.KeyUtils; |
+import org.chromium.content.browser.test.util.TestTouchUtils; |
+import org.chromium.content_public.browser.LoadUrlParams; |
+import org.chromium.net.test.util.TestWebServer; |
+import org.chromium.ui.base.PageTransition; |
+ |
+import java.util.ArrayList; |
+import java.util.concurrent.Callable; |
+import java.util.concurrent.Semaphore; |
+import java.util.concurrent.TimeUnit; |
+ |
+/** |
+ * Tests for the native android New Tab Page. |
+ */ |
+public class NewTabPageTest extends ChromeTabbedActivityTestBase { |
+ |
+ private static final String TEST_PAGE = |
+ TestHttpServerClient.getUrl("chrome/test/data/android/navigate/simple.html"); |
+ |
+ private static final String[] FAKE_MOST_VISITED_TITLES = new String[] { "Simple" }; |
+ private static final String[] FAKE_MOST_VISITED_URLS = new String[] { TEST_PAGE }; |
+ |
+ private Tab mTab; |
+ private NewTabPage mNtp; |
+ private View mFakebox; |
+ private ViewGroup mMostVisitedLayout; |
+ private FakeMostVisitedSites mFakeMostVisitedSites; |
+ |
+ @Override |
+ public void startMainActivity() throws InterruptedException { |
+ startMainActivityOnBlankPage(); |
+ mTab = getActivity().getActivityTab(); |
+ |
+ try { |
+ runTestOnUiThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ // Create FakeMostVisitedSites after starting the activity, since it depends on |
+ // native code. |
+ mFakeMostVisitedSites = new FakeMostVisitedSites(mTab.getProfile(), |
+ FAKE_MOST_VISITED_TITLES, FAKE_MOST_VISITED_URLS); |
+ } |
+ }); |
+ } catch (Throwable t) { |
+ fail(t.getMessage()); |
+ } |
+ NewTabPage.setMostVisitedSitesForTests(mFakeMostVisitedSites); |
+ |
+ loadUrl(UrlConstants.NTP_URL); |
+ NewTabPageTestUtils.waitForNtpLoaded(mTab); |
+ |
+ assertTrue(mTab.getNativePage() instanceof NewTabPage); |
+ mNtp = (NewTabPage) mTab.getNativePage(); |
+ mFakebox = mNtp.getView().findViewById(R.id.search_box); |
+ mMostVisitedLayout = (ViewGroup) mNtp.getView().findViewById(R.id.most_visited_layout); |
+ assertEquals(FAKE_MOST_VISITED_URLS.length, mMostVisitedLayout.getChildCount()); |
+ } |
+ |
+ /** |
+ * Tests that clicking on the fakebox causes it to animate upwards and focus the omnibox, and |
+ * defocusing the omnibox causes the fakebox to animate back down. |
+ */ |
+ @SmallTest |
+ @Feature({"NewTabPage"}) |
+ public void testFocusFakebox() throws InterruptedException { |
+ int initialFakeboxTop = getFakeboxTop(mNtp); |
+ |
+ singleClickView(mFakebox); |
+ waitForFakeboxFocusAnimationComplete(mNtp); |
+ UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
+ assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true)); |
+ int afterFocusFakeboxTop = getFakeboxTop(mNtp); |
+ assertTrue(afterFocusFakeboxTop < initialFakeboxTop); |
+ |
+ OmniboxTestUtils.toggleUrlBarFocus(urlBar, false); |
+ waitForFakeboxTopPosition(mNtp, initialFakeboxTop); |
+ assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, false)); |
+ } |
+ |
+ /** |
+ * Tests that clicking on the fakebox causes it to focus the omnibox and allows typing and |
+ * navigating to a URL. |
+ */ |
+ @SmallTest |
+ @Feature({"NewTabPage"}) |
+ public void testSearchFromFakebox() throws InterruptedException { |
+ singleClickView(mFakebox); |
+ waitForFakeboxFocusAnimationComplete(mNtp); |
+ final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
+ assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true)); |
+ |
+ getInstrumentation().sendStringSync(TEST_PAGE); |
+ LocationBarLayout locationBar = |
+ (LocationBarLayout) getActivity().findViewById(R.id.location_bar); |
+ OmniboxTestUtils.waitForOmniboxSuggestions(locationBar); |
+ |
+ ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() { |
+ @Override |
+ public void run() { |
+ KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_ENTER); |
+ } |
+ }); |
+ } |
+ |
+ /** |
+ * Tests clicking on a most visited item. |
+ */ |
+ @SmallTest |
+ @Feature({"NewTabPage"}) |
+ public void testClickMostVisitedItem() throws InterruptedException { |
+ ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() { |
+ @Override |
+ public void run() { |
+ View mostVisitedItem = mMostVisitedLayout.getChildAt(0); |
+ singleClickView(mostVisitedItem); |
+ } |
+ }); |
+ assertEquals(FAKE_MOST_VISITED_URLS[0], mTab.getUrl()); |
+ } |
+ |
+ /** |
+ * Tests opening a most visited item in a new tab. |
+ */ |
+ @SmallTest |
+ @Feature({"NewTabPage"}) |
+ public void testOpenMostVisitedItemInNewTab() throws InterruptedException { |
+ invokeContextMenuAndOpenInANewTab(mMostVisitedLayout.getChildAt(0), |
+ NewTabPage.ID_OPEN_IN_NEW_TAB, false, FAKE_MOST_VISITED_URLS[0]); |
+ } |
+ |
+ /** |
+ * Tests opening a most visited item in a new incognito tab. |
+ */ |
+ @SmallTest |
+ @Feature({"NewTabPage"}) |
+ public void testOpenMostVisitedItemInIncognitoTab() throws InterruptedException { |
+ invokeContextMenuAndOpenInANewTab(mMostVisitedLayout.getChildAt(0), |
+ NewTabPage.ID_OPEN_IN_INCOGNITO_TAB, true, FAKE_MOST_VISITED_URLS[0]); |
+ } |
+ |
+ /** |
+ * Tests deleting a most visited item. |
+ */ |
+ @SmallTest |
+ @Feature({"NewTabPage"}) |
+ public void testRemoveMostVisitedItem() { |
+ View mostVisitedItem = mMostVisitedLayout.getChildAt(0); |
+ ArrayList<View> views = new ArrayList<View>(); |
+ mMostVisitedLayout.findViewsWithText(views, FAKE_MOST_VISITED_TITLES[0], |
+ View.FIND_VIEWS_WITH_TEXT); |
+ assertEquals(1, views.size()); |
+ |
+ TestTouchUtils.longClickView(getInstrumentation(), mostVisitedItem); |
+ assertTrue(getInstrumentation().invokeContextMenuAction(getActivity(), |
+ NewTabPage.ID_REMOVE, 0)); |
+ |
+ assertTrue(mFakeMostVisitedSites.isUrlBlacklisted(FAKE_MOST_VISITED_URLS[0])); |
+ } |
+ |
+ @MediumTest |
+ @Feature({"NewTabPage"}) |
+ public void testUrlFocusAnimationsDisabledOnLoad() throws InterruptedException { |
+ assertFalse(getUrlFocusAnimatonsDisabled()); |
+ ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() { |
+ @Override |
+ public void run() { |
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
+ @Override |
+ public void run() { |
+ int pageTransition = |
+ PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR; |
+ mTab.loadUrl(new LoadUrlParams(TEST_PAGE, pageTransition)); |
+ // It should be disabled as soon as a load URL is triggered. |
+ assertTrue(getUrlFocusAnimatonsDisabled()); |
+ } |
+ }); |
+ } |
+ }); |
+ // Ensure it is still marked as disabled once the new page is fully loaded. |
+ assertTrue(getUrlFocusAnimatonsDisabled()); |
+ } |
+ |
+ @LargeTest |
+ @Feature({"NewTagPage"}) |
+ public void testUrlFocusAnimationsEnabledOnFailedLoad() throws Exception { |
+ TestWebServer webServer = TestWebServer.start(); |
+ try { |
+ final Semaphore delaySemaphore = new Semaphore(0); |
+ Runnable delayAction = new Runnable() { |
+ @Override |
+ public void run() { |
+ try { |
+ assertTrue(delaySemaphore.tryAcquire(10, TimeUnit.SECONDS)); |
+ } catch (InterruptedException e) { |
+ e.printStackTrace(); |
+ } |
+ } |
+ }; |
+ final String testPageUrl = webServer.setResponseWithRunnableAction( |
+ "/ntp_test.html", |
+ "<html><body></body></html>", null, delayAction); |
+ |
+ assertFalse(getUrlFocusAnimatonsDisabled()); |
+ |
+ clickFakebox(); |
+ UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
+ OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true); |
+ typeInOmnibox(testPageUrl, false); |
+ LocationBarLayout locationBar = |
+ (LocationBarLayout) getActivity().findViewById(R.id.location_bar); |
+ OmniboxTestUtils.waitForOmniboxSuggestions(locationBar); |
+ |
+ final CallbackHelper loadedCallback = new CallbackHelper(); |
+ mTab.addObserver(new EmptyTabObserver() { |
+ @Override |
+ public void onPageLoadFinished(Tab tab) { |
+ loadedCallback.notifyCalled(); |
+ tab.removeObserver(this); |
+ } |
+ }); |
+ |
+ final View v = urlBar; |
+ KeyUtils.singleKeyEventView(getInstrumentation(), v, KeyEvent.KEYCODE_ENTER); |
+ |
+ assertTrue(waitForUrlFocusAnimationsDisabledState(true)); |
+ assertTrue(waitForTabLoading()); |
+ |
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
+ @Override |
+ public void run() { |
+ mTab.stopLoading(); |
+ } |
+ }); |
+ assertTrue(waitForUrlFocusAnimationsDisabledState(false)); |
+ delaySemaphore.release(); |
+ loadedCallback.waitForCallback(0); |
+ assertFalse(getUrlFocusAnimatonsDisabled()); |
+ } finally { |
+ webServer.shutdown(); |
+ } |
+ } |
+ |
+ private boolean getUrlFocusAnimatonsDisabled() { |
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { |
+ @Override |
+ public Boolean call() throws Exception { |
+ return mNtp.getNewTabPageView().urlFocusAnimationsDisabled(); |
+ } |
+ }); |
+ } |
+ |
+ private boolean waitForUrlFocusAnimationsDisabledState(final boolean disabled) |
+ throws InterruptedException { |
+ return CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return getUrlFocusAnimatonsDisabled() == disabled; |
+ } |
+ }); |
+ } |
+ |
+ private boolean waitForTabLoading() throws InterruptedException { |
+ return CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { |
+ @Override |
+ public Boolean call() throws Exception { |
+ return mTab.isLoading(); |
+ } |
+ }); |
+ } |
+ }); |
+ } |
+ |
+ private void waitForFakeboxFocusAnimationComplete(NewTabPage ntp) throws InterruptedException { |
+ waitForUrlFocusPercent(ntp, 1f); |
+ } |
+ |
+ private void waitForFakeboxUnfocusAnimationComplete(NewTabPage ntp) |
+ throws InterruptedException { |
+ waitForUrlFocusPercent(ntp, 0f); |
+ } |
+ |
+ private void waitForUrlFocusPercent(final NewTabPage ntp, final float percent) |
+ throws InterruptedException { |
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { |
+ @Override |
+ public Boolean call() throws Exception { |
+ return ntp.getNewTabPageView().getUrlFocusChangeAnimationPercent() |
+ == percent; |
+ } |
+ }); |
+ } |
+ })); |
+ } |
+ |
+ private void clickFakebox() { |
+ View fakebox = mNtp.getView().findViewById(R.id.search_box); |
+ singleClickView(fakebox); |
+ } |
+ |
+ /** |
+ * @return The position of the top of the fakebox relative to the window. |
+ */ |
+ private int getFakeboxTop(final NewTabPage ntp) { |
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer>() { |
+ @Override |
+ public Integer call() { |
+ final View fakebox = ntp.getView().findViewById(R.id.search_box); |
+ int[] location = new int[2]; |
+ fakebox.getLocationInWindow(location); |
+ return location[1]; |
+ } |
+ }); |
+ } |
+ |
+ /** |
+ * Waits until the top of the fakebox reaches the given position. |
+ */ |
+ private void waitForFakeboxTopPosition(final NewTabPage ntp, final int position) |
+ throws InterruptedException { |
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { |
+ @Override |
+ public Boolean call() throws Exception { |
+ return getFakeboxTop(ntp) == position; |
+ } |
+ }); |
+ } |
+ })); |
+ } |
+} |