From 69300a43c4bec5db7ad8761c3e45a735a2e7f0dd Mon Sep 17 00:00:00 2001 From: Julian Descottes Date: Wed, 7 Feb 2024 00:40:42 +0000 Subject: [PATCH] Bug 1877191 - Add removeTabOptions parameter to ContextualIdentityService.closeContainerTabs r=mconley Adds a removeTabOptions optional parameter to closeContainerTabs that will be forwarded to tabbrowser.removeTab This allows to set options such as skipPermitUnload. Browser mochitest added to check the new behavior. This should be a noop for current consumers of the API. Differential Revision: https://phabricator.services.mozilla.com/D200018 --- .../ContextualIdentityService.sys.mjs | 4 +- .../components/contextualidentity/moz.build | 1 + .../tests/browser/browser.toml | 3 + .../browser/browser_closeContainerTabs.js | 81 +++++++++++++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 toolkit/components/contextualidentity/tests/browser/browser.toml create mode 100644 toolkit/components/contextualidentity/tests/browser/browser_closeContainerTabs.js diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs b/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs index 50a201728c06..fefe162ea0b1 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs +++ b/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs @@ -567,7 +567,7 @@ _ContextualIdentityService.prototype = { return count; }, - closeContainerTabs(userContextId = 0) { + closeContainerTabs(userContextId = 0, removeTabOptions = {}) { return new Promise(resolve => { let remoteTabIds = new Set(); this._forEachContainerTab((tab, tabbrowser) => { @@ -578,7 +578,7 @@ _ContextualIdentityService.prototype = { remoteTabIds.add(frameLoader.remoteTab.tabId); } - tabbrowser.removeTab(tab); + tabbrowser.removeTab(tab, removeTabOptions); }, userContextId); if (remoteTabIds.size == 0) { diff --git a/toolkit/components/contextualidentity/moz.build b/toolkit/components/contextualidentity/moz.build index 2ced34710a0f..0ec0df4ece2e 100644 --- a/toolkit/components/contextualidentity/moz.build +++ b/toolkit/components/contextualidentity/moz.build @@ -11,4 +11,5 @@ EXTRA_JS_MODULES += [ "ContextualIdentityService.sys.mjs", ] +BROWSER_CHROME_MANIFESTS += ["tests/browser/browser.toml"] XPCSHELL_TESTS_MANIFESTS += ["tests/unit/xpcshell.toml"] diff --git a/toolkit/components/contextualidentity/tests/browser/browser.toml b/toolkit/components/contextualidentity/tests/browser/browser.toml new file mode 100644 index 000000000000..0678c38171ea --- /dev/null +++ b/toolkit/components/contextualidentity/tests/browser/browser.toml @@ -0,0 +1,3 @@ +[DEFAULT] + +["browser_closeContainerTabs.js"] diff --git a/toolkit/components/contextualidentity/tests/browser/browser_closeContainerTabs.js b/toolkit/components/contextualidentity/tests/browser/browser_closeContainerTabs.js new file mode 100644 index 000000000000..16fa28e30639 --- /dev/null +++ b/toolkit/components/contextualidentity/tests/browser/browser_closeContainerTabs.js @@ -0,0 +1,81 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PromptTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromptTestUtils.sys.mjs" +); + +const BUILDER_URL = "https://example.com/document-builder.sjs?html="; +const PAGE_MARKUP = ` + + + + +TEST PAGE + +`; +const TEST_URL = BUILDER_URL + encodeURI(PAGE_MARKUP); + +add_task(async function test_skipPermitUnload() { + await SpecialPowers.pushPrefEnv({ + set: [["dom.require_user_interaction_for_beforeunload", false]], + }); + + info("Create a test user context"); + const userContextId = ContextualIdentityService.create("test").userContextId; + + // Run tests in a new window to avoid affecting the main test window. + const win = await BrowserTestUtils.openNewBrowserWindow(); + registerCleanupFunction(async () => { + await BrowserTestUtils.closeWindow(win); + }); + + info("Create a tab owned by the test user context"); + const tab = await BrowserTestUtils.addTab(win.gBrowser, TEST_URL, { + userContextId, + }); + registerCleanupFunction(() => win.gBrowser.removeTab(tab)); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + info("Call closeContainerTabs without skipPermitUnload"); + const unloadDialogPromise = PromptTestUtils.handleNextPrompt( + tab.linkedBrowser, + { + modalType: Ci.nsIPrompt.MODAL_TYPE_CONTENT, + promptType: "confirmEx", + }, + // Click the cancel button. + { buttonNumClick: 1 } + ); + + const tabCountBeforeClose = win.gBrowser.tabs.length; + ContextualIdentityService.closeContainerTabs(userContextId); + + info("Wait for the unload dialog"); + await unloadDialogPromise; + is( + win.gBrowser.tabs.length, + tabCountBeforeClose, + "Tab was not closed because of the before unload prompt" + ); + + info("Call closeContainerTabs with skipPermitUnload"); + const closePromise = BrowserTestUtils.waitForTabClosing(tab); + ContextualIdentityService.closeContainerTabs(userContextId, { + skipPermitUnload: true, + }); + + info("Wait for the tab to be closed"); + await closePromise; + is( + win.gBrowser.tabs.length, + tabCountBeforeClose - 1, + "Tab was closed after ignoring the before unload prompt" + ); +});