forked from mirrors/gecko-dev
		
	When re-enabling the test case blocked by bug 1670933 it became apparent that we were not allowing session history entries to be marked with user interaction when the SH entry was created by navigation through a sub-frame. The code that we had for this only covered updating SH entries after pushState etc., not adding new entries for document loads. When SH lives in the child this is easier to manage in nsDocShell, but with Fission it probably makes sense to move this code to the parent. Differential Revision: https://phabricator.services.mozilla.com/D97421
		
			
				
	
	
		
			380 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			380 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Any copyright is dedicated to the Public Domain.
 | 
						|
   http://creativecommons.org/publicdomain/zero/1.0/ */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const TEST_PAGE =
 | 
						|
  getRootDirectory(gTestPath).replace(
 | 
						|
    "chrome://mochitests/content",
 | 
						|
    "https://example.com"
 | 
						|
  ) + "dummy_page.html";
 | 
						|
const IFRAME_PAGE =
 | 
						|
  getRootDirectory(gTestPath).replace(
 | 
						|
    "chrome://mochitests/content",
 | 
						|
    "https://example.com"
 | 
						|
  ) + "dummy_iframe_page.html";
 | 
						|
 | 
						|
async function assertMenulist(entries, baseURL = TEST_PAGE) {
 | 
						|
  // Wait for the session data to be flushed before continuing the test
 | 
						|
  await new Promise(resolve =>
 | 
						|
    SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
 | 
						|
  );
 | 
						|
 | 
						|
  let backButton = document.getElementById("back-button");
 | 
						|
  let contextMenu = document.getElementById("backForwardMenu");
 | 
						|
 | 
						|
  info("waiting for the history menu to open");
 | 
						|
 | 
						|
  let popupShownPromise = BrowserTestUtils.waitForEvent(
 | 
						|
    contextMenu,
 | 
						|
    "popupshown"
 | 
						|
  );
 | 
						|
  EventUtils.synthesizeMouseAtCenter(backButton, {
 | 
						|
    type: "contextmenu",
 | 
						|
    button: 2,
 | 
						|
  });
 | 
						|
  await popupShownPromise;
 | 
						|
 | 
						|
  ok(true, "history menu opened");
 | 
						|
 | 
						|
  let nodes = contextMenu.childNodes;
 | 
						|
 | 
						|
  is(
 | 
						|
    nodes.length,
 | 
						|
    entries.length,
 | 
						|
    "Has the expected number of contextMenu entries"
 | 
						|
  );
 | 
						|
 | 
						|
  for (let i = 0; i < entries.length; i++) {
 | 
						|
    let node = nodes[i];
 | 
						|
    is(
 | 
						|
      node.getAttribute("uri").replace(/[?|#]/, "!"),
 | 
						|
      baseURL + "!entry=" + entries[i],
 | 
						|
      "contextMenu node has the correct uri"
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  let popupHiddenPromise = BrowserTestUtils.waitForEvent(
 | 
						|
    contextMenu,
 | 
						|
    "popuphidden"
 | 
						|
  );
 | 
						|
  contextMenu.hidePopup();
 | 
						|
  await popupHiddenPromise;
 | 
						|
}
 | 
						|
 | 
						|
// There are different ways of loading a page, but they should exhibit roughly the same
 | 
						|
// back-forward behavior for the purpose of requiring user interaction. Thus, we
 | 
						|
// have a utility function that runs the same test with a parameterized method of loading
 | 
						|
// new URLs.
 | 
						|
async function runTopLevelTest(loadMethod, useHashes = false) {
 | 
						|
  let p = useHashes ? "#" : "?";
 | 
						|
 | 
						|
  // Test with both pref on and off
 | 
						|
  for (let requireUserInteraction of [true, false]) {
 | 
						|
    Services.prefs.setBoolPref(
 | 
						|
      "browser.navigation.requireUserInteraction",
 | 
						|
      requireUserInteraction
 | 
						|
    );
 | 
						|
 | 
						|
    let tab = await BrowserTestUtils.openNewForegroundTab(
 | 
						|
      gBrowser,
 | 
						|
      TEST_PAGE + p + "entry=0"
 | 
						|
    );
 | 
						|
    let browser = tab.linkedBrowser;
 | 
						|
 | 
						|
    assertBackForwardState(false, false);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + p + "entry=1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist([1, 0]);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + p + "entry=2");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(requireUserInteraction ? [2, 0] : [2, 1, 0]);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + p + "entry=3");
 | 
						|
 | 
						|
    info("Adding user interaction for entry=3");
 | 
						|
    // Add some user interaction to entry 3
 | 
						|
    await BrowserTestUtils.synthesizeMouse(
 | 
						|
      "body",
 | 
						|
      0,
 | 
						|
      0,
 | 
						|
      {},
 | 
						|
      browser.browsingContext,
 | 
						|
      true
 | 
						|
    );
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(requireUserInteraction ? [3, 0] : [3, 2, 1, 0]);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + p + "entry=4");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(requireUserInteraction ? [4, 3, 0] : [4, 3, 2, 1, 0]);
 | 
						|
 | 
						|
    info("Adding user interaction for entry=4");
 | 
						|
    // Add some user interaction to entry 4
 | 
						|
    await BrowserTestUtils.synthesizeMouse(
 | 
						|
      "body",
 | 
						|
      0,
 | 
						|
      0,
 | 
						|
      {},
 | 
						|
      browser.browsingContext,
 | 
						|
      true
 | 
						|
    );
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + p + "entry=5");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
 | 
						|
    );
 | 
						|
 | 
						|
    await goBack(TEST_PAGE + p + "entry=4");
 | 
						|
    await goBack(TEST_PAGE + p + "entry=3");
 | 
						|
 | 
						|
    if (!requireUserInteraction) {
 | 
						|
      await goBack(TEST_PAGE + p + "entry=2");
 | 
						|
      await goBack(TEST_PAGE + p + "entry=1");
 | 
						|
    }
 | 
						|
 | 
						|
    assertBackForwardState(true, true);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
 | 
						|
    );
 | 
						|
 | 
						|
    await goBack(TEST_PAGE + p + "entry=0");
 | 
						|
 | 
						|
    assertBackForwardState(false, true);
 | 
						|
 | 
						|
    if (!requireUserInteraction) {
 | 
						|
      await goForward(TEST_PAGE + p + "entry=1");
 | 
						|
      await goForward(TEST_PAGE + p + "entry=2");
 | 
						|
    }
 | 
						|
 | 
						|
    await goForward(TEST_PAGE + p + "entry=3");
 | 
						|
 | 
						|
    assertBackForwardState(true, true);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
 | 
						|
    );
 | 
						|
 | 
						|
    await goForward(TEST_PAGE + p + "entry=4");
 | 
						|
 | 
						|
    assertBackForwardState(true, true);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
 | 
						|
    );
 | 
						|
 | 
						|
    await goForward(TEST_PAGE + p + "entry=5");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
 | 
						|
    );
 | 
						|
 | 
						|
    BrowserTestUtils.removeTab(tab);
 | 
						|
  }
 | 
						|
 | 
						|
  Services.prefs.clearUserPref("browser.navigation.requireUserInteraction");
 | 
						|
}
 | 
						|
 | 
						|
async function runIframeTest(loadMethod) {
 | 
						|
  // Test with both pref on and off
 | 
						|
  for (let requireUserInteraction of [true, false]) {
 | 
						|
    Services.prefs.setBoolPref(
 | 
						|
      "browser.navigation.requireUserInteraction",
 | 
						|
      requireUserInteraction
 | 
						|
    );
 | 
						|
 | 
						|
    // First test the boring case where we only have one iframe.
 | 
						|
    let tab = await BrowserTestUtils.openNewForegroundTab(
 | 
						|
      gBrowser,
 | 
						|
      IFRAME_PAGE + "?entry=0"
 | 
						|
    );
 | 
						|
    let browser = tab.linkedBrowser;
 | 
						|
 | 
						|
    assertBackForwardState(false, false);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + "?sub_entry=1", "frame1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist([0, 0], IFRAME_PAGE);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + "?sub_entry=2", "frame1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [0, 0] : [0, 0, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    let bc = await SpecialPowers.spawn(browser, [], function() {
 | 
						|
      return content.document.getElementById("frame1").browsingContext;
 | 
						|
    });
 | 
						|
 | 
						|
    // Add some user interaction to sub entry 2
 | 
						|
    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + "?sub_entry=3", "frame1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    await loadMethod(TEST_PAGE + "?sub_entry=4", "frame1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    if (!requireUserInteraction) {
 | 
						|
      await goBack(TEST_PAGE + "?sub_entry=3", true);
 | 
						|
    }
 | 
						|
 | 
						|
    await goBack(TEST_PAGE + "?sub_entry=2", true);
 | 
						|
 | 
						|
    assertBackForwardState(true, true);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    await loadMethod(IFRAME_PAGE + "?entry=1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [1, 0, 0] : [1, 0, 0, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    BrowserTestUtils.removeTab(tab);
 | 
						|
 | 
						|
    // Two iframes, now we're talking.
 | 
						|
    tab = await BrowserTestUtils.openNewForegroundTab(
 | 
						|
      gBrowser,
 | 
						|
      IFRAME_PAGE + "?entry=0"
 | 
						|
    );
 | 
						|
    browser = tab.linkedBrowser;
 | 
						|
 | 
						|
    await loadMethod(IFRAME_PAGE + "?entry=1");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(requireUserInteraction ? [1, 0] : [1, 0], IFRAME_PAGE);
 | 
						|
 | 
						|
    // Add some user interaction to frame 1.
 | 
						|
    bc = await SpecialPowers.spawn(browser, [], function() {
 | 
						|
      return content.document.getElementById("frame1").browsingContext;
 | 
						|
    });
 | 
						|
    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
 | 
						|
 | 
						|
    // Add some user interaction to frame 2.
 | 
						|
    bc = await SpecialPowers.spawn(browser, [], function() {
 | 
						|
      return content.document.getElementById("frame2").browsingContext;
 | 
						|
    });
 | 
						|
    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
 | 
						|
 | 
						|
    // Navigate frame 2.
 | 
						|
    await loadMethod(TEST_PAGE + "?sub_entry=1", "frame2");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [1, 1, 0] : [1, 1, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    // Add some user interaction to frame 1, again.
 | 
						|
    bc = await SpecialPowers.spawn(browser, [], function() {
 | 
						|
      return content.document.getElementById("frame1").browsingContext;
 | 
						|
    });
 | 
						|
    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
 | 
						|
 | 
						|
    // Navigate frame 2, again.
 | 
						|
    await loadMethod(TEST_PAGE + "?sub_entry=2", "frame2");
 | 
						|
 | 
						|
    assertBackForwardState(true, false);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    await goBack(TEST_PAGE + "?sub_entry=1", true);
 | 
						|
 | 
						|
    assertBackForwardState(true, true);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    await goBack(TEST_PAGE + "?sub_entry=0", true);
 | 
						|
 | 
						|
    assertBackForwardState(true, true);
 | 
						|
    await assertMenulist(
 | 
						|
      requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0],
 | 
						|
      IFRAME_PAGE
 | 
						|
    );
 | 
						|
 | 
						|
    BrowserTestUtils.removeTab(tab);
 | 
						|
  }
 | 
						|
 | 
						|
  Services.prefs.clearUserPref("browser.navigation.requireUserInteraction");
 | 
						|
}
 | 
						|
 | 
						|
// Test that when the pref is flipped, we are skipping history
 | 
						|
// entries without user interaction when following links with hash URIs.
 | 
						|
add_task(async function test_hashURI() {
 | 
						|
  async function followLinkHash(url) {
 | 
						|
    info(`Creating and following a link to ${url}`);
 | 
						|
    let browser = gBrowser.selectedBrowser;
 | 
						|
    let loaded = BrowserTestUtils.waitForLocationChange(gBrowser, url);
 | 
						|
    await SpecialPowers.spawn(browser, [url], function(url) {
 | 
						|
      let a = content.document.createElement("a");
 | 
						|
      a.href = url;
 | 
						|
      content.document.body.appendChild(a);
 | 
						|
      a.click();
 | 
						|
    });
 | 
						|
    await loaded;
 | 
						|
    info(`Loaded ${url}`);
 | 
						|
  }
 | 
						|
 | 
						|
  await runTopLevelTest(followLinkHash, true);
 | 
						|
});
 | 
						|
 | 
						|
// Test that when the pref is flipped, we are skipping history
 | 
						|
// entries without user interaction when using history.pushState.
 | 
						|
add_task(async function test_pushState() {
 | 
						|
  await runTopLevelTest(pushState);
 | 
						|
});
 | 
						|
 | 
						|
// Test that when the pref is flipped, we are skipping history
 | 
						|
// entries without user interaction when using loadURI.
 | 
						|
add_task(async function test_loadURI() {
 | 
						|
  await runTopLevelTest(loadURI);
 | 
						|
});
 | 
						|
 | 
						|
// Test that when the pref is flipped, we are skipping history
 | 
						|
// entries without user interaction when following a link.
 | 
						|
add_task(async function test_followLink() {
 | 
						|
  await runTopLevelTest(followLink);
 | 
						|
});
 | 
						|
 | 
						|
// Test that when the pref is flipped, we are skipping history
 | 
						|
// entries without user interaction when navigating inside an iframe
 | 
						|
// using history.pushState.
 | 
						|
add_task(async function test_iframe_pushState() {
 | 
						|
  await runIframeTest(pushState);
 | 
						|
});
 | 
						|
 | 
						|
// Test that when the pref is flipped, we are skipping history
 | 
						|
// entries without user interaction when navigating inside an iframe
 | 
						|
// by following links.
 | 
						|
add_task(async function test_iframe_followLink() {
 | 
						|
  await runIframeTest(followLink);
 | 
						|
});
 |