root/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. setUp
  2. tearDown
  3. getNavigationHistory
  4. checkHistoryItem
  5. addPage1ToServer
  6. addPage2ToServer
  7. addPageWithHashTagRedirectToServer
  8. testNavigateOneUrl
  9. testNavigateTwoUrls
  10. testNavigateTwoUrlsAndBack
  11. testFavicon
  12. addNoncacheableLoginPageToServer
  13. addNoncacheableLoginResponsePageToServer
  14. testNavigateBackToNoncacheableLoginPage

// Copyright 2012 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.android_webview.test;

import android.test.suitebuilder.annotation.SmallTest;

import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.content.browser.NavigationEntry;
import org.chromium.content.browser.NavigationHistory;
import org.chromium.content.browser.test.util.HistoryUtils;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
import org.chromium.net.test.util.TestWebServer;

import java.util.concurrent.Callable;

/**
 * Navigation history tests.
 */
public class NavigationHistoryTest extends AwTestBase {

    private static final String PAGE_1_PATH = "/page1.html";
    private static final String PAGE_1_TITLE = "Page 1 Title";
    private static final String PAGE_2_PATH = "/page2.html";
    private static final String PAGE_2_TITLE = "Page 2 Title";
    private static final String PAGE_WITH_HASHTAG_REDIRECT_TITLE = "Page with hashtag";
    private static final String LOGIN_PAGE_PATH = "/login.html";
    private static final String LOGIN_PAGE_TITLE = "Login page";
    private static final String LOGIN_RESPONSE_PAGE_PATH = "/login-response.html";
    private static final String LOGIN_RESPONSE_PAGE_TITLE = "Login response";
    private static final String LOGIN_RESPONSE_PAGE_HELP_LINK_ID = "help";

    private TestWebServer mWebServer;
    private TestAwContentsClient mContentsClient;
    private AwContents mAwContents;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        AwContents.setShouldDownloadFavicons();
        mContentsClient = new TestAwContentsClient();
        final AwTestContainerView testContainerView =
            createAwTestContainerViewOnMainSync(mContentsClient);
        mAwContents = testContainerView.getAwContents();
        mWebServer = new TestWebServer(false);
    }

    @Override
    public void tearDown() throws Exception {
        mWebServer.shutdown();
        super.tearDown();
    }

    private NavigationHistory getNavigationHistory(final AwContents awContents)
            throws Exception {
        return ThreadUtils.runOnUiThreadBlocking(new Callable<NavigationHistory>() {
            @Override
            public NavigationHistory call() {
                return awContents.getContentViewCore().getNavigationHistory();
            }
        });
    }

    private void checkHistoryItem(NavigationEntry item, String url, String originalUrl,
            String title, boolean faviconNull) {
        assertEquals(url, item.getUrl());
        assertEquals(originalUrl, item.getOriginalUrl());
        assertEquals(title, item.getTitle());
        if (faviconNull) {
            assertNull(item.getFavicon());
        } else {
            assertNotNull(item.getFavicon());
        }
    }

    private String addPage1ToServer(TestWebServer webServer) {
        return mWebServer.setResponse(PAGE_1_PATH,
                CommonResources.makeHtmlPageFrom(
                        "<title>" + PAGE_1_TITLE + "</title>",
                        "<div>This is test page 1.</div>"),
                CommonResources.getTextHtmlHeaders(false));
    }

    private String addPage2ToServer(TestWebServer webServer) {
        return mWebServer.setResponse(PAGE_2_PATH,
                CommonResources.makeHtmlPageFrom(
                        "<title>" + PAGE_2_TITLE + "</title>",
                        "<div>This is test page 2.</div>"),
                CommonResources.getTextHtmlHeaders(false));
    }

    private String addPageWithHashTagRedirectToServer(TestWebServer webServer) {
        return mWebServer.setResponse(PAGE_2_PATH,
                CommonResources.makeHtmlPageFrom(
                        "<title>" + PAGE_WITH_HASHTAG_REDIRECT_TITLE + "</title>",
                        "<iframe onLoad=\"location.replace(location.href + '#tag');\" />"),
                CommonResources.getTextHtmlHeaders(false));
    }

    @SmallTest
    public void testNavigateOneUrl() throws Throwable {
        NavigationHistory history = getNavigationHistory(mAwContents);
        assertEquals(0, history.getEntryCount());

        final String pageWithHashTagRedirectUrl = addPageWithHashTagRedirectToServer(mWebServer);
        enableJavaScriptOnUiThread(mAwContents);

        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
                pageWithHashTagRedirectUrl);

        history = getNavigationHistory(mAwContents);
        checkHistoryItem(history.getEntryAtIndex(0),
                pageWithHashTagRedirectUrl + "#tag",
                pageWithHashTagRedirectUrl,
                PAGE_WITH_HASHTAG_REDIRECT_TITLE,
                true);

        assertEquals(0, history.getCurrentEntryIndex());
    }

    @SmallTest
    public void testNavigateTwoUrls() throws Throwable {
        NavigationHistory list = getNavigationHistory(mAwContents);
        assertEquals(0, list.getEntryCount());

        final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
                mContentsClient.getOnPageFinishedHelper();
        final String page1Url = addPage1ToServer(mWebServer);
        final String page2Url = addPage2ToServer(mWebServer);

        loadUrlSync(mAwContents, onPageFinishedHelper, page1Url);
        loadUrlSync(mAwContents, onPageFinishedHelper, page2Url);

        list = getNavigationHistory(mAwContents);

        // Make sure there is a new entry entry the list
        assertEquals(2, list.getEntryCount());

        // Make sure the first entry is still okay
        checkHistoryItem(list.getEntryAtIndex(0),
                page1Url,
                page1Url,
                PAGE_1_TITLE,
                true);

        // Make sure the second entry was added properly
        checkHistoryItem(list.getEntryAtIndex(1),
                page2Url,
                page2Url,
                PAGE_2_TITLE,
                true);

        assertEquals(1, list.getCurrentEntryIndex());

    }

    @SmallTest
    public void testNavigateTwoUrlsAndBack() throws Throwable {
        final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
                mContentsClient.getOnPageFinishedHelper();
        NavigationHistory list = getNavigationHistory(mAwContents);
        assertEquals(0, list.getEntryCount());

        final String page1Url = addPage1ToServer(mWebServer);
        final String page2Url = addPage2ToServer(mWebServer);

        loadUrlSync(mAwContents, onPageFinishedHelper, page1Url);
        loadUrlSync(mAwContents, onPageFinishedHelper, page2Url);

        HistoryUtils.goBackSync(getInstrumentation(), mAwContents.getContentViewCore(),
                onPageFinishedHelper);
        list = getNavigationHistory(mAwContents);

        // Make sure the first entry is still okay
        checkHistoryItem(list.getEntryAtIndex(0),
                page1Url,
                page1Url,
                PAGE_1_TITLE,
                true);

        // Make sure the second entry is still okay
        checkHistoryItem(list.getEntryAtIndex(1),
                page2Url,
                page2Url,
                PAGE_2_TITLE,
                true);

        // Make sure the current index is back to 0
        assertEquals(0, list.getCurrentEntryIndex());
    }

    /**
     * Disabled until favicons are getting fetched when using ContentView.
     *
     * @SmallTest
     * @throws Throwable
     */
    @DisabledTest
    public void testFavicon() throws Throwable {
        NavigationHistory list = getNavigationHistory(mAwContents);

        mWebServer.setResponseBase64("/" + CommonResources.FAVICON_FILENAME,
                CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(false));
        final String url = mWebServer.setResponse("/favicon.html",
                CommonResources.FAVICON_STATIC_HTML, null);

        assertEquals(0, list.getEntryCount());
        getAwSettingsOnUiThread(mAwContents).setImagesEnabled(true);
        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);

        list = getNavigationHistory(mAwContents);

        // Make sure the first entry is still okay.
        checkHistoryItem(list.getEntryAtIndex(0), url, url, "", false);
    }

    private String addNoncacheableLoginPageToServer(TestWebServer webServer) {
        final String submitButtonId = "submit";
        final String loginPageHtml =
                "<html>" +
                "  <head>" +
                "    <title>" + LOGIN_PAGE_TITLE + "</title>" +
                "    <script>" +
                "      function startAction() {" +
                "        button = document.getElementById('" + submitButtonId + "');" +
                "        button.click();" +
                "      }" +
                "    </script>" +
                "  </head>" +
                "  <body onload='setTimeout(startAction, 0)'>" +
                "    <form action='" + LOGIN_RESPONSE_PAGE_PATH.substring(1) + "' method='post'>" +
                "      <input type='text' name='login'>" +
                "      <input id='" + submitButtonId + "' type='submit' value='Submit'>" +
                "    </form>" +
                "  </body>" +
                "</html>";
        return mWebServer.setResponse(LOGIN_PAGE_PATH,
                loginPageHtml,
                CommonResources.getTextHtmlHeaders(true));
    }

    private String addNoncacheableLoginResponsePageToServer(TestWebServer webServer) {
        final String loginResponsePageHtml =
                "<html>" +
                "  <head>" +
                "    <title>" + LOGIN_RESPONSE_PAGE_TITLE + "</title>" +
                "  </head>" +
                "  <body>" +
                "    Login incorrect" +
                "    <div><a id='" + LOGIN_RESPONSE_PAGE_HELP_LINK_ID + "' href='" +
                PAGE_1_PATH.substring(1) + "'>Help</a></div>'" +
                "  </body>" +
                "</html>";
        return mWebServer.setResponse(LOGIN_RESPONSE_PAGE_PATH,
                loginResponsePageHtml,
                CommonResources.getTextHtmlHeaders(true));
    }

    // This test simulates Google login page behavior. The page is non-cacheable
    // and uses POST method for submission. It also contains a help link, leading
    // to another page. We are verifying that it is possible to go back to the
    // submitted login page after visiting the help page.
    /**
     * Temporarily disabled. It is blocking a patch that fixes chromium's form
     * resubmission defenses. This test should probably expect a modal dialog
     * asking permission to re-post rather than expecting to just be able to navigate
     * back to a page that specified Cache-Control: no-store.
     *
     * @MediumTest
     * @Feature({"AndroidWebView"})
     */
    @DisabledTest
    public void testNavigateBackToNoncacheableLoginPage() throws Throwable {
        final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
                mContentsClient.getOnPageFinishedHelper();

        final String loginPageUrl = addNoncacheableLoginPageToServer(mWebServer);
        final String loginResponsePageUrl = addNoncacheableLoginResponsePageToServer(mWebServer);
        final String page1Url = addPage1ToServer(mWebServer);

        getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
        loadUrlSync(mAwContents, onPageFinishedHelper, loginPageUrl);
        // Since the page performs an async action, we can't rely on callbacks.
        pollOnUiThread(new Callable<Boolean>() {
            @Override
            public Boolean call() {
                String title = mAwContents.getContentViewCore().getTitle();
                return LOGIN_RESPONSE_PAGE_TITLE.equals(title);
            }
        });
        executeJavaScriptAndWaitForResult(mAwContents,
                mContentsClient,
                "link = document.getElementById('" + LOGIN_RESPONSE_PAGE_HELP_LINK_ID + "');" +
                "link.click();");
        pollOnUiThread(new Callable<Boolean>() {
            @Override
            public Boolean call() {
                String title = mAwContents.getContentViewCore().getTitle();
                return PAGE_1_TITLE.equals(title);
            }
        });
        // Verify that we can still go back to the login response page despite that
        // it is non-cacheable.
        HistoryUtils.goBackSync(getInstrumentation(), mAwContents.getContentViewCore(),
                onPageFinishedHelper);
        pollOnUiThread(new Callable<Boolean>() {
            @Override
            public Boolean call() {
                String title = mAwContents.getContentViewCore().getTitle();
                return LOGIN_RESPONSE_PAGE_TITLE.equals(title);
            }
        });
    }
}

/* [<][>][^][v][top][bottom][index][help] */