mobile/android/tests/browser/chrome/test_session_scroll_position.html
author Jan Henning <jh+bugzilla@buttercookie.de>
Fri, 11 Jan 2019 19:50:09 +0000
changeset 453553 39207d39e5c2
parent 453547 bf744ce7867a
child 455795 6b56696d713a
permissions -rw-r--r--
Bug 1498812 - Part 9: Switch session store/session history to use visual viewport for scroll position tracking. r=mikedeboer,snorp For simplicity's sake, for now we keep storing only one scroll position per history entry (bug 1499210), so if we have to choose between the layout and the visual viewport, the latter is a vastly better choice, as it more accurately represents the scroll position as perceived by the user, especially when the page has been pinch-zoomed. This also means that instead of the normal scroll events, the session store now has to listen for the corresponding events specific to the visual viewport. We also extend the scroll position test to check that the scroll position isn't just properly saved, but also actually properly restored in practice as well. We only add this test now instead of already adding it beforehand like we did with the rest of the test - to avoid having to temporarily extend the checkScroll() helper function to deal with todo()/todo_is etc. - because getting that part of the test to complete without timing out (which would be one of its natural failure modes, because the expected events would be missing) would require faking even more scroll events - because we already have the todo() tests that are telling us the we didn't *store* any scroll position in the first place, so there's no point in trying to actually restore anything For the GeckoView saveAndRestoreState test, we now spin the event loop once before setting the scroll position in order to give APZ opportunity to settle down after the initial page load. Differential Revision: https://phabricator.services.mozilla.com/D15690

<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=810981
https://bugzilla.mozilla.org/show_bug.cgi?id=1282902
https://bugzilla.mozilla.org/show_bug.cgi?id=1301016
https://bugzilla.mozilla.org/show_bug.cgi?id=1265818
https://bugzilla.mozilla.org/show_bug.cgi?id=1498892
-->
<head>
  <meta charset="utf-8">
  <title>Various scroll position/zoom level tests for the mobile session store</title>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/AddTask.js"></script>
  <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
  <script type="application/javascript" src="head.js"></script>
  <script type="application/javascript" src="head_scroll.js"></script>
  <script type="application/javascript">

  /** Tests for Bug 810981, 1282902, 1301016, 1265818, 1498892 **/

  "use strict";

  ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
  ChromeUtils.import("resource://gre/modules/Services.jsm");
  ChromeUtils.import("resource://gre/modules/Messaging.jsm");
  ChromeUtils.import("resource://testing-common/Task.jsm");

  // The chrome window and friends.
  let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
  let BrowserApp = chromeWin.BrowserApp;

  const BASE = "http://example.org/chrome/mobile/android/tests/browser/chrome/";
  // Use something with ample space for scrolling and zooming.
  const URL = BASE + "browser_scrollPositions_sample.html";
  // Same content but under a different URL, so we have something to navigate to and from.
  const URL2 = BASE + "browser_scrollPositions_sample2.html";
  // Test nested scrolling with frames.
  const URL_FRAMESET = BASE + "browser_scrollPositions_sample_frameset.html";
  // Reader mode URL
  const URL_reader = "about:reader?url=http%3A%2F%2Fexample.org%2Fchrome%2Fmobile%2Fandroid%2Ftests%2Fbrowser%2Fchrome%2Fbasic_article_mobile.html";

  // Randomized set of scroll positions and zoom factors we will use in this test.
  const SCROLL_X = Math.round(100 * (1 + Math.random()));
  const SCROLL_Y = Math.round(200 * (1 + Math.random()));
  const ZOOM = 1 + 0.5 * Math.random();

  const SCROLL2_X = Math.round(300 * (1 + Math.random()));
  const SCROLL2_Y = Math.round(400 * (1 + Math.random()));
  const ZOOM2 = 1.5 + 0.5 * Math.random();

  // Track the tabs where the tests are happening.
  let tabScroll;

  function cleanupTabs() {
    if (tabScroll) {
      BrowserApp.closeTab(tabScroll);
      tabScroll = null;
    }
  }

  SimpleTest.registerCleanupFunction(function() {
    cleanupTabs();
  });

  let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);

  add_task(async function test_sessionStoreScrollPositionReaderMode() {
    let testData = {x: 0, y: SCROLL_Y};
    // Creates a tab, sets a scroll position and closes the tab.
    function createAndRemoveReaderTab() {
      return Task.spawn(function* () {
        // Create a new tab.
        tabScroll = BrowserApp.addTab(URL_reader);
        let browser = tabScroll.browser;
        yield promiseBrowserEvent(browser, "AboutReaderContentReady");

        // Modify scroll position.
        setScrollPosition(browser, testData);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");

        // Check that we've actually scrolled.
        checkScroll(browser, testData);

        // Remove the tab.
        BrowserApp.closeTab(tabScroll);
        yield promiseTabEvent(browser, "SSTabCloseProcessed");
      });
    }

    await createAndRemoveReaderTab();
    let state = ss.getClosedTabs(chromeWin);
    let [{scrolldata}] = state;
    is(scrolldata.scroll, getScrollString(testData), "stored scroll position is correct");

    // Restore the closed tab.
    let closedTabData = ss.getClosedTabs(chromeWin)[0];
    let browser = ss.undoCloseTab(chromeWin, closedTabData);
    await promiseBrowserEvent(browser, "AboutReaderContentReady");

    // Check the scroll position.
    checkScroll(browser, testData);

    // Remove the tab.
    BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
  });

  add_task(async function test_sessionStoreScrollPositionAndZoomLevel() {
    let testData1 = {x: SCROLL_X, y: SCROLL_Y, zoom: ZOOM};
    let testData2 = {x: SCROLL2_X, y: SCROLL2_Y, zoom: ZOOM2};
    // Creates a tab, sets a scroll position and zoom level and closes the tab.
    function createAndRemoveTab() {
      return Task.spawn(function* () {
        // Create a new tab.
        tabScroll = BrowserApp.addTab(URL);
        let browser = tabScroll.browser;
        yield promiseBrowserEvent(browser, "pageshow");

        // Modify scroll position and zoom level.
        setScrollPosition(browser, testData1);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");

        // Check that we've actually scrolled and zoomed.
        checkScroll(browser, testData1);

        // Navigate to a different page and scroll/zoom there as well.
        browser.loadURI(URL2);
        yield promiseBrowserEvent(browser, "pageshow");

        setScrollPosition(browser, testData2);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");

        checkScroll(browser, testData2);

        // Remove the tab.
        BrowserApp.closeTab(tabScroll);
        yield promiseTabEvent(browser, "SSTabCloseProcessed");
      });
    }

    await createAndRemoveTab();
    let state = ss.getClosedTabs(chromeWin);
    let [{scrolldata}] = state;
    is(scrolldata.scroll, getScrollString(testData2), "stored scroll position is correct");
    ok(fuzzyEquals(scrolldata.zoom.resolution, ZOOM2), "stored zoom level is correct");

    // Restore the closed tab.
    let closedTabData = ss.getClosedTabs(chromeWin)[0];
    let browser = ss.undoCloseTab(chromeWin, closedTabData);
    let pageshow = promiseBrowserEvent(browser, "pageshow");
    let scroll = promiseBrowserEvent(browser, "mozvisualscroll",
                                     { mozSystemGroup: true });
    await pageshow;
    await scroll;

    // Check the scroll position and zoom level.
    checkScroll(browser, testData2);

    // Now go back in history and check that the scroll position
    // is restored there as well.
    is(browser.canGoBack, true, "can go back");
    pageshow = promiseBrowserEvent(browser, "pageshow");
    scroll = promiseBrowserEvent(browser, "mozvisualscroll",
                                 { mozSystemGroup: true });
    browser.goBack();
    await pageshow;
    await scroll;

    checkScroll(browser, testData1);

    // Remove the tab.
    BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
  });

  add_task(async function test_sessionStoreZoomLevelRecalc() {
    let testData = {x: SCROLL_X, y: SCROLL_Y, zoom: ZOOM};
    // Creates a tab, sets a scroll position and zoom level and closes the tab.
    function createAndRemoveTab() {
      return Task.spawn(function* () {
        // Create a new tab.
        tabScroll = BrowserApp.addTab(URL);
        let browser = tabScroll.browser;
        yield promiseBrowserEvent(browser, "pageshow");

        // Modify scroll position and zoom level.
        setScrollPosition(browser, testData);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");

        // Check that we've actually scrolled and zoomed.
        checkScroll(browser, testData);

        // Remove the tab.
        BrowserApp.closeTab(tabScroll);
        yield promiseTabEvent(browser, "SSTabCloseProcessed");
      });
    }

    await createAndRemoveTab();
    let state = ss.getClosedTabs(chromeWin);
    let [{scrolldata}] = state;
    is(scrolldata.scroll, getScrollString(testData), "stored scroll position is correct");
    ok(fuzzyEquals(scrolldata.zoom.resolution, ZOOM), "stored zoom level is correct");

    // Pretend the zoom level was originally saved on a rotated device.
    let closedTabData = ss.getClosedTabs(chromeWin)[0];
    let displayWidth = scrolldata.zoom.displaySize.width;
    let displayHeight = scrolldata.zoom.displaySize.height;
    closedTabData.scrolldata.zoom.displaySize.width = displayHeight;
    closedTabData.scrolldata.zoom.displaySize.height = displayWidth;

    // Restore the closed tab.
    let browser = ss.undoCloseTab(chromeWin, closedTabData);
    await promiseBrowserEvent(browser, "pageshow");

    // Check the scroll position and zoom level.
    testData.zoom = ZOOM * displayWidth / displayHeight;
    checkScroll(browser, testData);

    // Remove the tab.
    BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
  });

  add_task(async function test_sessionStoreScrollPositionForFrames() {
    let testDataParent = {x: 0, y: Math.round(SCROLL_Y / 2), zoom: 2.0};
    let testData1 = {x: SCROLL_X, y: SCROLL_Y, frame: 0};
    let testData2 = {x: SCROLL2_X, y: SCROLL2_Y, frame: 1};
    // Creates a tab, sets a scroll position and zoom level and closes the tab.
    function createAndRemoveTab() {
      return Task.spawn(function* () {
        // Create a new tab.
        tabScroll = BrowserApp.addTab(URL_FRAMESET);
        let browser = tabScroll.browser;
        yield promiseBrowserEvent(browser, "pageshow");

        // Move the frameset itself.
        setScrollPosition(browser, testDataParent);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");
        checkScroll(browser, testDataParent);

        // Modify scroll position and zoom level for one frame...
        setScrollPosition(browser, testData1);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");
        checkScroll(browser, testData1);

        // ... and the other.
        setScrollPosition(browser, testData2);
        yield promiseTabEvent(browser, "SSTabScrollCaptured");
        checkScroll(browser, testData2);

        // Remove the tab.
        BrowserApp.closeTab(tabScroll);
        yield promiseTabEvent(browser, "SSTabCloseProcessed");
      });
    }

    await createAndRemoveTab();
    let state = ss.getClosedTabs(chromeWin);
    let [{scrolldata}] = state;
    is(scrolldata.scroll, getScrollString(testDataParent), "stored scroll position for frameset is correct");
    is(scrolldata.children[0].scroll, getScrollString(testData1), "stored scroll position for frame 1 is correct");
    is(scrolldata.children[1].scroll, getScrollString(testData2), "stored scroll position for frame 2 is correct");

    // Restore the closed tab.
    let closedTabData = ss.getClosedTabs(chromeWin)[0];
    let browser = ss.undoCloseTab(chromeWin, closedTabData);
    let pageshow = promiseBrowserEvent(browser, "pageshow");
    // We can't add event listeners for the frames until we're sure that they've actually loaded.
    let load = promiseBrowserEvent(browser, "load");
    await load;
    let scrollParent = promiseBrowserEvent(getFrame(browser, testDataParent),
                                           "mozvisualscroll",
                                           { mozSystemGroup: true });
    let scroll1 = promiseBrowserEvent(getFrame(browser, testData1),
                                      "mozvisualscroll",
                                      { mozSystemGroup: true });
    let scroll2 = promiseBrowserEvent(getFrame(browser, testData2),
                                      "mozvisualscroll",
                                      { mozSystemGroup: true });
    await pageshow;
    await scrollParent;
    await scroll1;
    await scroll2;

    // Check the scroll position and zoom level.
    checkScroll(browser, testDataParent);
    checkScroll(browser, testData1);
    checkScroll(browser, testData2);

    // Remove the tab.
    BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
  });

  </script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=810981">Mozilla Bug 810981</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1282902">Mozilla Bug 1282902</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1301016">Mozilla Bug 1301016</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1265818">Mozilla Bug 1265818</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1498892">Mozilla Bug 1498892</a>
<p id="display"></p>
<div id="content" style="display: none">

</div>
<pre id="test">
</pre>
</body>
</html>