forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			374 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			374 lines
		
	
	
	
		
			10 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 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);
 | |
| });
 | 
