401 lines
11 KiB
JavaScript
401 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;
|
|
// Add some user interaction to entry 0
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"body",
|
|
0,
|
|
0,
|
|
{},
|
|
browser.browsingContext,
|
|
true
|
|
);
|
|
|
|
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;
|
|
// Add some user interaction to entry 0
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"body",
|
|
0,
|
|
0,
|
|
{},
|
|
browser.browsingContext,
|
|
true
|
|
);
|
|
|
|
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;
|
|
// Add some user interaction to entry 0
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"body",
|
|
0,
|
|
0,
|
|
{},
|
|
browser.browsingContext,
|
|
true
|
|
);
|
|
|
|
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);
|
|
});
|