diff --git a/browser/actors/PromptParent.jsm b/browser/actors/PromptParent.jsm index 48b16329dc74..3cbd66072c71 100644 --- a/browser/actors/PromptParent.jsm +++ b/browser/actors/PromptParent.jsm @@ -270,6 +270,15 @@ class PromptParent extends JSWindowActorParent { let browsingContext = this.browsingContext.top; let browser = browsingContext.embedderElement; + let promptRequiresBrowser = + args.modalType === Services.prompt.MODAL_TYPE_TAB || + args.modalType === Services.prompt.MODAL_TYPE_CONTENT; + if (promptRequiresBrowser && !browser) { + let modal_type = + args.modalType === Services.prompt.MODAL_TYPE_TAB ? "tab" : "content"; + throw new Error(`Cannot ${modal_type}-prompt without a browser!`); + } + let win; // If we are a chrome actor we can use the associated chrome win. @@ -284,7 +293,7 @@ class PromptParent extends JSWindowActorParent { // passed window is the hidden window). // See bug 875157 comment 30 for more.. if (win?.winUtils && !win.winUtils.isParentWindowMainWidgetVisible) { - throw new Error("Cannot call openModalWindow on a hidden window"); + throw new Error("Cannot open a prompt in a hidden window"); } try { @@ -304,18 +313,7 @@ class PromptParent extends JSWindowActorParent { // Convert args object to a prop bag for the dialog to consume. let bag; - if ( - (args.modalType === Services.prompt.MODAL_TYPE_TAB || - args.modalType === Services.prompt.MODAL_TYPE_CONTENT) && - win?.gBrowser?.getTabDialogBox - ) { - if (!browser) { - let modal_type = - args.modalType === Services.prompt.MODAL_TYPE_TAB - ? "tab" - : "content"; - throw new Error(`Cannot ${modal_type}-prompt without a browser!`); - } + if (promptRequiresBrowser && win?.gBrowser?.getTabDialogBox) { // Tab or content level prompt let dialogBox = win.gBrowser.getTabDialogBox(browser); diff --git a/browser/base/content/test/tabPrompts/browser.ini b/browser/base/content/test/tabPrompts/browser.ini index 2388fe98982d..e0ac6d5c4965 100644 --- a/browser/base/content/test/tabPrompts/browser.ini +++ b/browser/base/content/test/tabPrompts/browser.ini @@ -9,5 +9,6 @@ support-files = file_beforeunload_stop.html [browser_openPromptInBackgroundTab.js] support-files = openPromptOffTimeout.html [browser_promptFocus.js] +[browser_prompt_closed_window.js] [browser_switchTabPermissionPrompt.js] [browser_windowPrompt.js] diff --git a/browser/base/content/test/tabPrompts/browser_prompt_closed_window.js b/browser/base/content/test/tabPrompts/browser_prompt_closed_window.js new file mode 100644 index 000000000000..9b842bf57f0d --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_prompt_closed_window.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Check that if we loop prompts from a closed tab, they don't + * start showing up as window prompts. + */ +add_task(async function test_closed_tab_doesnt_show_prompt() { + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + + // Get a promise for the initial, in-tab prompt: + let promptPromise = BrowserTestUtils.promiseAlertDialogOpen(); + await ContentTask.spawn(newWin.gBrowser.selectedBrowser, [], function() { + // Don't want to block, so use setTimeout with 0 timeout: + content.setTimeout( + () => + content.eval( + 'let i = 0; while (!prompt("Prompts a lot!") && i++ < 10);' + ), + 0 + ); + }); + // wait for the first prompt to have appeared: + await promptPromise; + + // Now close the containing tab, and check for windowed prompts appearing. + let opened = false; + let obs = () => { + opened = true; + }; + Services.obs.addObserver(obs, "domwindowopened"); + registerCleanupFunction(() => + Services.obs.removeObserver(obs, "domwindowopened") + ); + await BrowserTestUtils.closeWindow(newWin); + + ok(!opened, "Should not have opened a prompt when closing the main window."); +});