Index: chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..41be0588e4a86bfc385c05f2da172fa0187e8a6f |
--- /dev/null |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java |
@@ -0,0 +1,319 @@ |
+// 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; |
+ |
+import android.app.Dialog; |
+import android.support.v7.app.AlertDialog; |
+import android.test.FlakyTest; |
+import android.util.JsonReader; |
+import android.widget.Button; |
+ |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.base.test.util.DisabledTest; |
+import org.chromium.chrome.browser.preferences.Preferences; |
+import org.chromium.chrome.browser.preferences.PreferencesStaging; |
+import org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataDialogFragment; |
+import org.chromium.chrome.test.ChromeActivityTestCaseBase; |
+import org.chromium.chrome.test.util.ActivityUtils; |
+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.JavaScriptUtils; |
+import org.chromium.content.browser.test.util.TestTouchUtils; |
+import org.chromium.content.browser.test.util.UiUtils; |
+ |
+import java.io.IOException; |
+import java.io.StringReader; |
+import java.util.Vector; |
+import java.util.concurrent.Callable; |
+import java.util.concurrent.TimeoutException; |
+ |
+public class HistoryUITest extends ChromeActivityTestCaseBase<ChromeActivity> { |
+ |
+ private static final String HISTORY_URL = "chrome://history-frame/"; |
+ |
+ public HistoryUITest() { |
+ super(ChromeActivity.class); |
+ } |
+ |
+ @Override |
+ public void startMainActivity() throws InterruptedException { |
+ startMainActivityOnBlankPage(); |
+ } |
+ |
+ private static class HistoryItem { |
+ public final String url; |
+ public final String title; |
+ |
+ HistoryItem(String url, String title) { |
+ this.url = url; |
+ this.title = title; |
+ } |
+ } |
+ |
+ private HistoryItem[] getHistoryContents() throws InterruptedException, TimeoutException { |
+ getInstrumentation().waitForIdleSync(); |
+ String jsResults = runJavaScriptCodeInCurrentTab(new StringBuilder() |
+ .append("var rawResults = document.querySelectorAll('.title');\n") |
+ .append("var results = [];\n") |
+ .append("for (i = 0; i < rawResults.length; ++i) {\n") |
+ .append(" results.push([rawResults[i].childNodes[0].href,\n") |
+ .append(" rawResults[i].childNodes[0].childNodes[0].textContent]);\n") |
+ .append("}\n") |
+ .append("results").toString()); |
+ |
+ JsonReader jsonReader = new JsonReader(new StringReader(jsResults)); |
+ Vector<HistoryItem> results = new Vector<HistoryItem>(); |
+ try { |
+ jsonReader.beginArray(); |
+ while (jsonReader.hasNext()) { |
+ jsonReader.beginArray(); |
+ assertTrue(jsonReader.hasNext()); |
+ String url = jsonReader.nextString(); |
+ assertTrue(jsonReader.hasNext()); |
+ String title = jsonReader.nextString(); |
+ assertFalse(jsonReader.hasNext()); |
+ jsonReader.endArray(); |
+ results.add(new HistoryItem(url, title)); |
+ } |
+ jsonReader.endArray(); |
+ } catch (IOException ioe) { |
+ fail("Failed to evaluate JavaScript: " + jsResults + "\n" + ioe); |
+ } |
+ |
+ HistoryItem[] history = new HistoryItem[results.size()]; |
+ results.toArray(history); |
+ return history; |
+ } |
+ |
+ private void removeSelectedEntries(int[] indices) |
+ throws InterruptedException, TimeoutException { |
+ // Build the query with the indices of the history elements to delete. |
+ StringBuilder jsQuery = new StringBuilder("var toCheck = ["); |
+ for (int i = 0; i < indices.length; ++i) { |
+ if (i != 0) { |
+ jsQuery.append(", "); |
+ } |
+ jsQuery.append(Integer.toString(indices[i])); |
+ } |
+ |
+ // Remove the specified indices from history. |
+ runJavaScriptCodeInCurrentTab(jsQuery.append("];\n") |
+ .append("var checkboxes = Array.prototype.slice.call(") |
+ .append(" document.getElementsByTagName('input')).") |
+ .append(" filter(function(elem, index, array) {") |
+ .append(" return elem.type == 'checkbox'; })\n") |
+ .append("for (i = 0; i < checkboxes.length; ++i) {\n") |
+ .append(" checkboxes[i].checked = false;\n") |
+ .append("}\n") |
+ .append("for (i = 0; i < toCheck.length; ++i) {\n") |
+ .append(" checkboxes[toCheck[i]].checked = true;\n") |
+ .append("}\n") |
+ .append("window.confirm = function() { return true; };\n") |
+ .append("removeItems();\n").toString()); |
+ |
+ // The deleteComplete() JavaScript method is called when the operation finishes. |
+ // Since we cannot synchronously wait for a JS callback, keep checking until the delete |
+ // queue becomes empty. |
+ Boolean pending; |
+ do { |
+ pending = Boolean.parseBoolean(runJavaScriptCodeInCurrentTab("deleteQueue.length > 0")); |
+ } while (pending); |
+ } |
+ |
+ private int getHistoryLength(ContentViewCore cvc) |
+ throws InterruptedException, TimeoutException { |
+ getInstrumentation().waitForIdleSync(); |
+ |
+ String numResultsString = JavaScriptUtils.executeJavaScriptAndWaitForResult( |
+ cvc.getWebContents(), "document.querySelectorAll('.entry').length"); |
+ int numResults = Integer.parseInt(numResultsString); |
+ return numResults; |
+ } |
+ |
+ /** |
+ * Wait for the UI to show the expected number of results. |
+ * @param expected The number of results that should be loaded. |
+ * @throws InterruptedException |
+ */ |
+ private void assertResultCountReaches(final ContentViewCore cvc, final int expected) |
+ throws InterruptedException { |
+ assertTrue(CriteriaHelper.pollForCriteria( |
+ new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ try { |
+ return expected == getHistoryLength(cvc); |
+ } catch (InterruptedException e) { |
+ e.printStackTrace(); |
+ return false; |
+ } catch (TimeoutException e) { |
+ e.printStackTrace(); |
+ return false; |
+ } |
+ } |
+ })); |
+ } |
+ |
+ /* |
+ * @MediumTest |
+ * @Feature({"History"}) |
+ * Bug 5969084 |
+ */ |
+ @DisabledTest |
+ public void testSearchHistory() throws InterruptedException, TimeoutException { |
+ // Introduce some entries in the history page. |
+ loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/about.html")); |
+ loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/get_title_test.html")); |
+ loadUrl(HISTORY_URL); |
+ UiUtils.settleDownUI(getInstrumentation()); |
+ assertResultCountReaches(getActivity().getCurrentContentViewCore(), 2); |
+ |
+ // Search for one of them. |
+ Tab tab = getActivity().getActivityTab(); |
+ final CallbackHelper loadCallback = new CallbackHelper(); |
+ TabObserver observer = new EmptyTabObserver() { |
+ @Override |
+ public void onLoadStopped(Tab tab) { |
+ if (tab.getUrl().startsWith(HISTORY_URL)) { |
+ loadCallback.notifyCalled(); |
+ } |
+ } |
+ }; |
+ tab.addObserver(observer); |
+ runJavaScriptCodeInCurrentTab("historyView.setSearch('about')"); |
+ loadCallback.waitForCallback(0); |
+ assertResultCountReaches(getActivity().getCurrentContentViewCore(), 1); |
+ |
+ // Delete the search term. |
+ runJavaScriptCodeInCurrentTab("historyView.setSearch('')"); |
+ loadCallback.waitForCallback(1); |
+ assertResultCountReaches(getActivity().getCurrentContentViewCore(), 2); |
+ tab.removeObserver(observer); |
+ } |
+ |
+ /* |
+ * @LargeTest |
+ * @Feature({"History"}) |
+ * Bug 6164471 |
+ */ |
+ @FlakyTest |
+ public void testRemovingEntries() throws InterruptedException, TimeoutException { |
+ // Urls will be visited in reverse order to preserve the array ordering |
+ // in the history results. |
+ String[] testUrls = new String[] { |
+ TestHttpServerClient.getUrl("chrome/test/data/android/google.html"), |
+ TestHttpServerClient.getUrl("chrome/test/data/android/about.html"), |
+ }; |
+ |
+ String[] testTitles = new String[testUrls.length]; |
+ for (int i = testUrls.length - 1; i >= 0; --i) { |
+ loadUrl(testUrls[i]); |
+ testTitles[i] = getActivity().getActivityTab().getTitle(); |
+ } |
+ |
+ // Check that the history page contains the visited pages. |
+ loadUrl(HISTORY_URL); |
+ UiUtils.settleDownUI(getInstrumentation()); |
+ HistoryItem[] history = getHistoryContents(); |
+ assertEquals(testUrls.length, history.length); |
+ for (int i = 0; i < testUrls.length; ++i) { |
+ assertEquals(testUrls[i], history[i].url); |
+ assertEquals(testTitles[i], history[i].title); |
+ } |
+ |
+ // Remove the first entry from history. |
+ assertTrue(history.length >= 1); |
+ removeSelectedEntries(new int[]{ 0 }); |
+ |
+ // Check that now the first result is the second visited page. |
+ history = getHistoryContents(); |
+ assertEquals(testUrls.length - 1, history.length); |
+ assertEquals(testUrls[1], history[0].url); |
+ assertEquals(testTitles[1], history[0].title); |
+ } |
+ |
+ /* |
+ * @LargeTest |
+ * @Feature({"History"}) |
+ * Bug 5971989 |
+ */ |
+ @FlakyTest |
+ public void testClearBrowsingData() throws InterruptedException, TimeoutException { |
+ // Introduce some entries in the history page. |
+ loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html")); |
+ loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/about.html")); |
+ loadUrl(HISTORY_URL); |
+ UiUtils.settleDownUI(getInstrumentation()); |
+ assertResultCountReaches(getActivity().getCurrentContentViewCore(), 2); |
+ |
+ // Trigger cleaning up all the browsing data. JS finishing events will make it synchronous |
+ // to us. |
+ final Preferences prefActivity = ActivityUtils.waitForActivity( |
+ getInstrumentation(), PreferencesStaging.class, new Runnable() { |
+ @Override |
+ public void run() { |
+ try { |
+ runJavaScriptCodeInCurrentTab("openClearBrowsingData()"); |
+ } catch (InterruptedException e) { |
+ fail("Exception occurred while attempting to open clear browing data"); |
+ } catch (TimeoutException e) { |
+ fail("Exception occurred while attempting to open clear browing data"); |
+ } |
+ } |
+ }); |
+ assertNotNull("Could not find the preferences activity", prefActivity); |
+ |
+ final ClearBrowsingDataDialogFragment clearBrowsingFragment = |
+ ActivityUtils.waitForFragment( |
+ prefActivity, ClearBrowsingDataDialogFragment.FRAGMENT_TAG); |
+ assertNotNull("Could not find clear browsing data fragment", clearBrowsingFragment); |
+ |
+ Dialog dialog = clearBrowsingFragment.getDialog(); |
+ final Button clearButton = ((AlertDialog) dialog).getButton( |
+ AlertDialog.BUTTON_POSITIVE); |
+ assertNotNull("Could not find Clear button.", clearButton); |
+ |
+ TestTouchUtils.performClickOnMainSync(getInstrumentation(), clearButton); |
+ assertTrue("Clear browsing dialog never hidden", |
+ CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return !clearBrowsingFragment.isVisible(); |
+ } |
+ })); |
+ |
+ final ChromeActivity mainActivity = ActivityUtils.waitForActivity( |
+ getInstrumentation(), getActivity().getClass(), new Runnable() { |
+ @Override |
+ public void run() { |
+ ThreadUtils.runOnUiThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ prefActivity.finish(); |
+ } |
+ }); |
+ } |
+ }); |
+ assertNotNull("Main never resumed", mainActivity); |
+ assertTrue("Main tab never restored", CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { |
+ @Override |
+ public Boolean call() throws Exception { |
+ return mainActivity.getActivityTab() != null |
+ && !mainActivity.getActivityTab().isFrozen(); |
+ } |
+ }); |
+ } |
+ })); |
+ JavaScriptUtils.executeJavaScriptAndWaitForResult( |
+ mainActivity.getCurrentContentViewCore().getWebContents(), "reloadHistory()"); |
+ assertResultCountReaches(getActivity().getCurrentContentViewCore(), 0); |
+ } |
+} |