diff --git a/browser/components/extensions/parent/ext-tabs.js b/browser/components/extensions/parent/ext-tabs.js index 0623d5683f72..48d69bc8131f 100644 --- a/browser/components/extensions/parent/ext-tabs.js +++ b/browser/components/extensions/parent/ext-tabs.js @@ -1638,12 +1638,12 @@ this.tabs = class extends ExtensionAPIPersistent { goForward(tabId) { let nativeTab = getTabOrActive(tabId); - nativeTab.linkedBrowser.goForward(); + nativeTab.linkedBrowser.goForward(false); }, goBack(tabId) { let nativeTab = getTabOrActive(tabId); - nativeTab.linkedBrowser.goBack(); + nativeTab.linkedBrowser.goBack(false); }, }, }; diff --git a/browser/components/extensions/test/browser/browser_ext_tabs_goBack_goForward.js b/browser/components/extensions/test/browser/browser_ext_tabs_goBack_goForward.js index 2ab960699d60..7c9f192341cc 100644 --- a/browser/components/extensions/test/browser/browser_ext_tabs_goBack_goForward.js +++ b/browser/components/extensions/test/browser/browser_ext_tabs_goBack_goForward.js @@ -3,10 +3,6 @@ "use strict"; add_task(async function test_tabs_goBack_goForward() { - await SpecialPowers.pushPrefEnv({ - set: [["browser.navigation.requireUserInteraction", false]], - }); - let extension = ExtensionTestUtils.loadExtension({ manifest: { permissions: ["tabs"], diff --git a/docshell/test/browser/browser.toml b/docshell/test/browser/browser.toml index 3b2592a5a40e..ff8288575615 100644 --- a/docshell/test/browser/browser.toml +++ b/docshell/test/browser/browser.toml @@ -260,6 +260,8 @@ support-files = [ "file_csp_uir_dummy.html", ] +["browser_current_entry_always_in_history_menu.js"] + ["browser_dataURI_unique_opaque_origin.js"] https_first_disabled = true @@ -305,6 +307,9 @@ support-files = ["overlink_test.html"] ["browser_platform_emulation.js"] +["browser_replace_state_during_navigation.js"] +support-files = ["file_replace_state_during_navigation.html"] + ["browser_search_notification.js"] ["browser_tab_replace_while_loading.js"] diff --git a/docshell/test/browser/browser_current_entry_always_in_history_menu.js b/docshell/test/browser/browser_current_entry_always_in_history_menu.js new file mode 100644 index 000000000000..1ffb891a3463 --- /dev/null +++ b/docshell/test/browser/browser_current_entry_always_in_history_menu.js @@ -0,0 +1,37 @@ +"use strict"; + +const TEST_URI = "https://example.com/"; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["browser.navigation.requireUserInteraction", true]], + }); +}); + +add_task(async () => { + await BrowserTestUtils.withNewTab(TEST_URI, async browser => { + // Navigate away, after causing a user interaction. + SpecialPowers.wrap(document).notifyUserGestureActivation(); + await followLink(TEST_URI + "2.html"); + + // Navigate again, without causing a user interaction. + await SpecialPowers.spawn(browser, [], async function () { + content.history.pushState({}, "", "https://example.com/3.html"); + }); + + // Wait for the session data to be flushed before continuing the test + await new Promise(resolve => + SessionStore.getSessionHistory(gBrowser.selectedTab, resolve) + ); + // The entry with no interaction shouldn't appear. + await assertMenulist([TEST_URI + "3.html", TEST_URI]); + + // Go back using history.back, which does not check for user interaction. + await SpecialPowers.spawn(browser, [], async function () { + content.history.back(); + }); + + // We are back on entry 2, so it should appear in the list. + await assertMenulist([TEST_URI + "3.html", TEST_URI + "2.html", TEST_URI]); + }); +}); diff --git a/docshell/test/browser/browser_replace_state_during_navigation.js b/docshell/test/browser/browser_replace_state_during_navigation.js new file mode 100644 index 000000000000..0554e53a7e55 --- /dev/null +++ b/docshell/test/browser/browser_replace_state_during_navigation.js @@ -0,0 +1,38 @@ +"use strict"; + +const TEST_URI = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" + ) + "dummy_page.html"; +const TEST_URI_2 = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" + ) + "file_replace_state_during_navigation.html"; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["browser.navigation.requireUserInteraction", true]], + }); +}); + +add_task(async () => { + await BrowserTestUtils.withNewTab(TEST_URI, async browser => { + // Add user interaction to the first page. + await BrowserTestUtils.synthesizeMouseAtCenter("body", {}, browser); + + // Follow link to the next page. + await followLink(TEST_URI_2); + + // Navigate, causing a hashchange event to fire and call history.replaceState + await BrowserTestUtils.synthesizeMouseAtCenter("#link", {}, browser); + + await assertMenulist([ + TEST_URI_2 + "#1", + TEST_URI_2 + "#inject", + TEST_URI_2, + TEST_URI, + ]); + }); +}); diff --git a/docshell/test/browser/file_replace_state_during_navigation.html b/docshell/test/browser/file_replace_state_during_navigation.html new file mode 100644 index 000000000000..09b0de9e05ae --- /dev/null +++ b/docshell/test/browser/file_replace_state_during_navigation.html @@ -0,0 +1,8 @@ + + +link diff --git a/docshell/test/browser/head.js b/docshell/test/browser/head.js index 00b17d89a9b0..a2158586789a 100644 --- a/docshell/test/browser/head.js +++ b/docshell/test/browser/head.js @@ -195,3 +195,51 @@ class SHListener { }); } } + +async function assertMenulist(entries) { + // 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; + + info("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"), + entries[i], + "contextMenu node has the correct uri" + ); + } + + let popupHiddenPromise = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await popupHiddenPromise; +} diff --git a/mobile/shared/components/extensions/ext-tabs.js b/mobile/shared/components/extensions/ext-tabs.js index c4d8010e7937..70c1cff8a04d 100644 --- a/mobile/shared/components/extensions/ext-tabs.js +++ b/mobile/shared/components/extensions/ext-tabs.js @@ -580,12 +580,12 @@ this.tabs = class extends ExtensionAPIPersistent { goForward(tabId) { const { browser } = getTabOrActive(tabId); - browser.goForward(); + browser.goForward(false); }, goBack(tabId) { const { browser } = getTabOrActive(tabId); - browser.goBack(); + browser.goBack(false); }, }, };