diff options
Diffstat (limited to '')
9 files changed, 845 insertions, 0 deletions
diff --git a/browser/base/content/test/tabdialogs/browser.ini b/browser/base/content/test/tabdialogs/browser.ini new file mode 100644 index 0000000000..2fbfa48b37 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser.ini @@ -0,0 +1,19 @@ +[DEFAULT] +support-files = + subdialog.xhtml + +[browser_multiple_dialog_navigation.js] +[browser_subdialog_esc.js] +support-files = + loadDelayedReply.sjs +[browser_tabdialogbox_content_prompts.js] +skip-if = + apple_silicon && !debug # Bug 1786514 + apple_catalina && !debug # Bug 1786514 + win10_2004 && !debug # Bug 1786514 +support-files = + test_page.html +[browser_tabdialogbox_focus.js] +https_first_disabled = true +[browser_tabdialogbox_navigation.js] +https_first_disabled = true diff --git a/browser/base/content/test/tabdialogs/browser_multiple_dialog_navigation.js b/browser/base/content/test/tabdialogs/browser_multiple_dialog_navigation.js new file mode 100644 index 0000000000..9d66ac1d7e --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_multiple_dialog_navigation.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_multiple_dialog_navigation() { + await BrowserTestUtils.withNewTab( + "https://example.com/gone", + async browser => { + let firstDialogPromise = BrowserTestUtils.promiseAlertDialogOpen(); + // We're gonna queue up some dialogs, and navigate. The tasks queueing the dialog + // are going to get aborted when the navigation happened, but that's OK because by + // that time they will have done their job. Detect and swallow that specific + // exception: + let navigationCatcher = e => { + if (e.name == "AbortError" && e.message.includes("destroyed before")) { + return; + } + throw e; + }; + // Queue up 2 dialogs + let firstTask = SpecialPowers.spawn(browser, [], async function () { + content.eval(`alert('hi');`); + }).catch(navigationCatcher); + let secondTask = SpecialPowers.spawn(browser, [], async function () { + content.eval(`alert('hi again');`); + }).catch(navigationCatcher); + info("Waiting for first dialog."); + let dialogWin = await firstDialogPromise; + + let secondDialogPromise = BrowserTestUtils.promiseAlertDialogOpen(); + dialogWin.document + .getElementById("commonDialog") + .getButton("accept") + .click(); + dialogWin = null; + + info("Wait for second dialog to appear."); + let secondDialogWin = await secondDialogPromise; + let closedPromise = BrowserTestUtils.waitForEvent( + secondDialogWin, + "unload" + ); + let loadedOtherPage = BrowserTestUtils.waitForLocationChange( + gBrowser, + "https://example.org/gone" + ); + BrowserTestUtils.loadURIString(browser, "https://example.org/gone"); + info("Waiting for the next page to load."); + await loadedOtherPage; + info( + "Waiting for second dialog to close. If we time out here that's a bug!" + ); + await closedPromise; + is(secondDialogWin.closed, true, "Should have closed second dialog."); + info("Ensure content tasks are done"); + await secondTask; + await firstTask; + } + ); +}); diff --git a/browser/base/content/test/tabdialogs/browser_subdialog_esc.js b/browser/base/content/test/tabdialogs/browser_subdialog_esc.js new file mode 100644 index 0000000000..63f2f276a3 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_subdialog_esc.js @@ -0,0 +1,122 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_ROOT_CHROME = getRootDirectory(gTestPath); +const TEST_DIALOG_PATH = TEST_ROOT_CHROME + "subdialog.xhtml"; + +const WEB_ROOT = TEST_ROOT_CHROME.replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com" +); +const TEST_LOAD_PAGE = WEB_ROOT + "loadDelayedReply.sjs"; + +/** + * Tests that ESC on a SubDialog does not cancel ongoing loads in the parent. + */ +add_task(async function test_subdialog_esc_does_not_cancel_load() { + await BrowserTestUtils.withNewTab( + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + async function (browser) { + // Start loading a page + let loadStartedPromise = BrowserTestUtils.loadURIString( + browser, + TEST_LOAD_PAGE + ); + let loadedPromise = BrowserTestUtils.browserLoaded(browser); + await loadStartedPromise; + + // Open a dialog + let dialogBox = gBrowser.getTabDialogBox(browser); + let dialogClose = dialogBox.open(TEST_DIALOG_PATH, { + keepOpenSameOriginNav: true, + }).closedPromise; + + let dialogs = dialogBox.getTabDialogManager()._dialogs; + + is(dialogs.length, 1, "Dialog manager has a dialog."); + + info("Waiting for dialogs to open."); + await dialogs[0]._dialogReady; + + // Close the dialog with esc key + EventUtils.synthesizeKey("KEY_Escape"); + + info("Waiting for dialog to close."); + await dialogClose; + + info("Triggering load complete"); + fetch(TEST_LOAD_PAGE, { + method: "POST", + }); + + // Load must complete + info("Waiting for load to complete"); + await loadedPromise; + ok(true, "Load completed"); + } + ); +}); + +/** + * Tests that ESC on a SubDialog with an open dropdown doesn't close the dialog. + */ +add_task(async function test_subdialog_esc_on_dropdown_does_not_close_dialog() { + await BrowserTestUtils.withNewTab( + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + async function (browser) { + // Open the test dialog + let dialogBox = gBrowser.getTabDialogBox(browser); + let dialogClose = dialogBox.open(TEST_DIALOG_PATH, { + keepOpenSameOriginNav: true, + }).closedPromise; + + let dialogs = dialogBox.getTabDialogManager()._dialogs; + + is(dialogs.length, 1, "Dialog manager has a dialog."); + + let dialog = dialogs[0]; + + info("Waiting for dialog to open."); + await dialog._dialogReady; + + // Open dropdown + let select = dialog._frame.contentDocument.getElementById("select"); + let shownPromise = BrowserTestUtils.waitForSelectPopupShown(window); + + info("Opening dropdown"); + select.focus(); + EventUtils.synthesizeKey("VK_SPACE", {}, dialog._frame.contentWindow); + + let selectPopup = await shownPromise; + + let hiddenPromise = BrowserTestUtils.waitForEvent( + selectPopup, + "popuphiding", + true + ); + + // Race dropdown closing vs SubDialog close + let race = Promise.race([ + hiddenPromise.then(() => true), + dialogClose.then(() => false), + ]); + + // Close the dropdown with esc key + info("Hitting escape key."); + await EventUtils.synthesizeKey("KEY_Escape"); + + let result = await race; + ok(result, "Select closed first"); + + await new Promise(resolve => executeSoon(resolve)); + + ok(!dialog._isClosing, "Dialog is not closing"); + ok(dialog._openedURL, "Dialog is open"); + } + ); +}); diff --git a/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js b/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js new file mode 100644 index 0000000000..3067c53873 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js @@ -0,0 +1,179 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const CONTENT_PROMPT_PREF = "prompts.contentPromptSubDialog"; +const TEST_ROOT_CHROME = getRootDirectory(gTestPath); +const TEST_DIALOG_PATH = TEST_ROOT_CHROME + "subdialog.xhtml"; + +const TEST_DATA_URI = "data:text/html,<body onload='alert(1)'>"; +const TEST_EXTENSION_DATA = { + background() { + // eslint-disable-next-line no-undef + browser.test.sendMessage("url", browser.runtime.getURL("alert.html")); + }, + manifest: { + name: "Test Extension", + }, + files: { + "alert.html": `<!DOCTYPE HTML> +<html> + <head> + <meta charset="utf-8"> + <title>TabDialogBox Content Modal Test page</title> + <script src="./alert.js"></script> + </head> + <body> + <h1>TabDialogBox Content Modal</h1> + </body> +</html>`, + "alert.js": `window.addEventListener("load", () => alert("Hi"));`, + }, +}; +// eslint-disable-next-line @microsoft/sdl/no-insecure-url +const TEST_ORIGIN = "http://example.com"; +const TEST_PAGE = + TEST_ROOT_CHROME.replace("chrome://mochitests/content", TEST_ORIGIN) + + "test_page.html"; + +var commonDialogsBundle = Services.strings.createBundle( + "chrome://global/locale/commonDialogs.properties" +); + +// Setup. +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [[CONTENT_PROMPT_PREF, true]], + }); +}); + +/** + * Test that a manager for content prompts is added to tab dialog box. + */ +add_task(async function test_tabdialog_content_prompts() { + await BrowserTestUtils.withNewTab( + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + async function (browser) { + info("Open a tab prompt."); + let dialogBox = gBrowser.getTabDialogBox(browser); + dialogBox.open(TEST_DIALOG_PATH); + + info("Check the content prompt dialog is only created when needed."); + let contentPromptDialog = document.querySelector( + ".content-prompt-dialog" + ); + ok(!contentPromptDialog, "Content prompt dialog should not be created."); + + info("Open a content prompt"); + dialogBox.open(TEST_DIALOG_PATH, { + modalType: Ci.nsIPrompt.MODAL_TYPE_CONTENT, + }); + + contentPromptDialog = document.querySelector(".content-prompt-dialog"); + ok(contentPromptDialog, "Content prompt dialog should be created."); + let contentPromptManager = dialogBox.getContentDialogManager(); + + is( + contentPromptManager._dialogs.length, + 1, + "Content prompt manager should have 1 dialog box." + ); + } + ); +}); + +/** + * Test origin text for a null principal. + */ +add_task(async function test_tabdialog_null_principal_title() { + let dialogShown = BrowserTestUtils.waitForEvent( + gBrowser, + "DOMWillOpenModalDialog" + ); + + await BrowserTestUtils.withNewTab(TEST_DATA_URI, async function (browser) { + info("Waiting for dialog to open."); + await dialogShown; + await checkOriginText(browser); + }); +}); + +/** + * Test origin text for an extension page. + */ +add_task(async function test_tabdialog_extension_title() { + let extension = ExtensionTestUtils.loadExtension(TEST_EXTENSION_DATA); + + await extension.startup(); + let url = await extension.awaitMessage("url"); + let dialogShown = BrowserTestUtils.waitForEvent( + gBrowser, + "DOMWillOpenModalDialog" + ); + + await BrowserTestUtils.withNewTab(url, async function (browser) { + info("Waiting for dialog to open."); + await dialogShown; + await checkOriginText(browser, "Test Extension"); + }); + + await extension.unload(); +}); + +/** + * Test origin text for a regular page. + */ +add_task(async function test_tabdialog_page_title() { + let dialogShown = BrowserTestUtils.waitForEvent( + gBrowser, + "DOMWillOpenModalDialog" + ); + + await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) { + info("Waiting for dialog to open."); + await dialogShown; + await checkOriginText(browser, TEST_ORIGIN); + }); +}); + +/** + * Test helper for checking the origin header of a dialog. + * + * @param {Object} browser + * The browser the dialog was opened from. + * @param {String|null} origin + * The page origin that should be displayed in the header, if any. + */ +async function checkOriginText(browser, origin = null) { + info("Check the title is visible."); + let dialogBox = gBrowser.getTabDialogBox(browser); + let contentPromptManager = dialogBox.getContentDialogManager(); + let dialog = contentPromptManager._dialogs[0]; + + info("Waiting for dialog frame to be ready."); + await dialog._dialogReady; + + let dialogDoc = dialog._frame.contentWindow.document; + let titleSelector = "#titleText"; + let infoTitle = dialogDoc.querySelector(titleSelector); + ok(BrowserTestUtils.is_visible(infoTitle), "Title text is visible"); + + info("Check the displayed origin text is correct."); + if (origin) { + let host = origin; + try { + host = new URL(origin).host; + } catch (ex) { + /* will fail for the extension case. */ + } + is(infoTitle.textContent, host, "Origin should be in header."); + } else { + is( + infoTitle.dataset.l10nId, + "common-dialog-title-null", + "Null principal string should be in header." + ); + } +} diff --git a/browser/base/content/test/tabdialogs/browser_tabdialogbox_focus.js b/browser/base/content/test/tabdialogs/browser_tabdialogbox_focus.js new file mode 100644 index 0000000000..08c0e8828d --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_focus.js @@ -0,0 +1,212 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_ROOT_CHROME = getRootDirectory(gTestPath); +const TEST_DIALOG_PATH = TEST_ROOT_CHROME + "subdialog.xhtml"; + +/** + * Tests that tab dialogs are focused when switching tabs. + */ +add_task(async function test_tabdialogbox_tab_switch_focus() { + // Open 3 tabs + let tabPromises = []; + for (let i = 0; i < 3; i += 1) { + tabPromises.push( + BrowserTestUtils.openNewForegroundTab( + gBrowser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + true + ) + ); + } + + // Wait for tabs to be ready + let tabs = await Promise.all(tabPromises); + + // Open subdialog in first two tabs + let dialogs = []; + for (let i = 0; i < 2; i += 1) { + let dialogBox = gBrowser.getTabDialogBox(tabs[i].linkedBrowser); + dialogBox.open(TEST_DIALOG_PATH); + dialogs.push(dialogBox.getTabDialogManager()._topDialog); + } + + // Wait for dialogs to be ready + await Promise.all([dialogs[0]._dialogReady, dialogs[1]._dialogReady]); + + // Switch to first tab which has dialog + await BrowserTestUtils.switchTab(gBrowser, tabs[0]); + + // The textbox in the dialogs content window should be focused + let dialogTextbox = + dialogs[0]._frame.contentDocument.querySelector("#textbox"); + is(Services.focus.focusedElement, dialogTextbox, "Dialog textbox is focused"); + + // Switch to second tab which has dialog + await BrowserTestUtils.switchTab(gBrowser, tabs[1]); + + // The textbox in the dialogs content window should be focused + let dialogTextbox2 = + dialogs[1]._frame.contentDocument.querySelector("#textbox"); + is( + Services.focus.focusedElement, + dialogTextbox2, + "Dialog2 textbox is focused" + ); + + // Switch to third tab which does not have a dialog + await BrowserTestUtils.switchTab(gBrowser, tabs[2]); + + // Test that content is focused + is( + Services.focus.focusedElement, + tabs[2].linkedBrowser, + "Top level browser is focused" + ); + + // Cleanup + tabs.forEach(tab => { + BrowserTestUtils.removeTab(tab); + }); +}); + +/** + * Tests that if we're showing multiple tab dialogs they are focused in the + * correct order and custom focus handlers are called. + */ +add_task(async function test_tabdialogbox_multiple_focus() { + await BrowserTestUtils.withNewTab(gBrowser, async browser => { + let dialogBox = gBrowser.getTabDialogBox(browser); + let dialogAClose = dialogBox.open( + TEST_DIALOG_PATH, + {}, + { + testCustomFocusHandler: true, + } + ).closedPromise; + let dialogBClose = dialogBox.open(TEST_DIALOG_PATH).closedPromise; + let dialogCClose = dialogBox.open( + TEST_DIALOG_PATH, + {}, + { + testCustomFocusHandler: true, + } + ).closedPromise; + + let dialogs = dialogBox._tabDialogManager._dialogs; + let [dialogA, dialogB, dialogC] = dialogs; + + // Wait until all dialogs are ready + await Promise.all(dialogs.map(dialog => dialog._dialogReady)); + + // Dialog A's custom focus target should be focused + let dialogElementA = + dialogA._frame.contentDocument.querySelector("#custom-focus-el"); + is( + Services.focus.focusedElement, + dialogElementA, + "Dialog A custom focus target is focused" + ); + + // Close top dialog + dialogA.close(); + await dialogAClose; + + // Dialog B's first focus target should be focused + let dialogElementB = + dialogB._frame.contentDocument.querySelector("#textbox"); + is( + Services.focus.focusedElement, + dialogElementB, + "Dialog B default focus target is focused" + ); + + // close top dialog + dialogB.close(); + await dialogBClose; + + // Dialog C's custom focus target should be focused + let dialogElementC = + dialogC._frame.contentDocument.querySelector("#custom-focus-el"); + is( + Services.focus.focusedElement, + dialogElementC, + "Dialog C custom focus target is focused" + ); + + // Close last dialog + dialogC.close(); + await dialogCClose; + + is( + dialogBox._tabDialogManager._dialogs.length, + 0, + "All dialogs should be closed" + ); + is( + Services.focus.focusedElement, + browser, + "Focus should be back on the browser" + ); + }); +}); + +/** + * Tests that other dialogs are still visible if one dialog is hidden. + */ +add_task(async function test_tabdialogbox_tab_switch_hidden() { + // Open 2 tabs + let tabPromises = []; + for (let i = 0; i < 2; i += 1) { + tabPromises.push( + BrowserTestUtils.openNewForegroundTab( + gBrowser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com", + true + ) + ); + } + + // Wait for tabs to be ready + let tabs = await Promise.all(tabPromises); + + // Open subdialog in tabs + let dialogs = []; + let dialogBox, dialogBoxManager, browser; + for (let i = 0; i < 2; i += 1) { + dialogBox = gBrowser.getTabDialogBox(tabs[i].linkedBrowser); + browser = tabs[i].linkedBrowser; + dialogBox.open(TEST_DIALOG_PATH); + dialogBoxManager = dialogBox.getTabDialogManager(); + dialogs.push(dialogBoxManager._topDialog); + } + + // Wait for dialogs to be ready + await Promise.all([dialogs[0]._dialogReady, dialogs[1]._dialogReady]); + + // Hide the top dialog + dialogBoxManager.hideDialog(browser); + + ok( + BrowserTestUtils.is_hidden(dialogBoxManager._dialogStack), + "Dialog stack is hidden" + ); + + // Switch to first tab + await BrowserTestUtils.switchTab(gBrowser, tabs[0]); + + // Check the dialog stack is showing in first tab + dialogBoxManager = gBrowser + .getTabDialogBox(tabs[0].linkedBrowser) + .getTabDialogManager(); + is(dialogBoxManager._dialogStack.hidden, false, "Dialog stack is showing"); + + // Cleanup + tabs.forEach(tab => { + BrowserTestUtils.removeTab(tab); + }); +}); diff --git a/browser/base/content/test/tabdialogs/browser_tabdialogbox_navigation.js b/browser/base/content/test/tabdialogs/browser_tabdialogbox_navigation.js new file mode 100644 index 0000000000..9e76f37f29 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_navigation.js @@ -0,0 +1,174 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_ROOT_CHROME = getRootDirectory(gTestPath); +const TEST_DIALOG_PATH = TEST_ROOT_CHROME + "subdialog.xhtml"; + +/** + * Tests that all tab dialogs are closed on navigation. + */ +add_task(async function test_tabdialogbox_multiple_close_on_nav() { + await BrowserTestUtils.withNewTab( + "https://example.com", + async function (browser) { + // Open two dialogs and wait for them to be ready. + let dialogBox = gBrowser.getTabDialogBox(browser); + let closedPromises = [ + dialogBox.open(TEST_DIALOG_PATH).closedPromise, + dialogBox.open(TEST_DIALOG_PATH).closedPromise, + ]; + + let dialogs = dialogBox.getTabDialogManager()._dialogs; + + is(dialogs.length, 2, "Dialog manager has two dialogs."); + + info("Waiting for dialogs to open."); + await Promise.all(dialogs.map(dialog => dialog._dialogReady)); + + // Navigate to a different page + BrowserTestUtils.loadURIString(browser, "https://example.org"); + + info("Waiting for dialogs to close."); + await closedPromises; + + ok(true, "All open dialogs should close on navigation"); + } + ); +}); + +/** + * Tests dialog close on navigation triggered by web content. + */ +add_task(async function test_tabdialogbox_close_on_content_nav() { + await BrowserTestUtils.withNewTab( + "https://example.com", + async function (browser) { + // Open a dialog and wait for it to be ready + let dialogBox = gBrowser.getTabDialogBox(browser); + let { closedPromise } = dialogBox.open(TEST_DIALOG_PATH); + + let dialog = dialogBox.getTabDialogManager()._topDialog; + + is( + dialogBox.getTabDialogManager()._dialogs.length, + 1, + "Dialog manager has one dialog." + ); + + info("Waiting for dialog to open."); + await dialog._dialogReady; + + // Trigger a same origin navigation by the content + await ContentTask.spawn(browser, {}, () => { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + content.location = "http://example.com/1"; + }); + + info("Waiting for dialog to close."); + await closedPromise; + ok( + true, + "Dialog should close for same origin navigation by the content." + ); + + // Open a new dialog + closedPromise = dialogBox.open(TEST_DIALOG_PATH, { + keepOpenSameOriginNav: true, + }).closedPromise; + + info("Waiting for dialog to open."); + await dialog._dialogReady; + + SimpleTest.requestFlakyTimeout("Waiting to ensure dialog does not close"); + let race = Promise.race([ + closedPromise, + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + new Promise(resolve => setTimeout(() => resolve("success"), 1000)), + ]); + + // Trigger a same origin navigation by the content + await ContentTask.spawn(browser, {}, () => { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + content.location = "http://example.com/test"; + }); + + is( + await race, + "success", + "Dialog should not close for same origin navigation by the content." + ); + + // Trigger a cross origin navigation by the content + await ContentTask.spawn(browser, {}, () => { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + content.location = "http://example.org/test2"; + }); + + info("Waiting for dialog to close"); + await closedPromise; + + ok( + true, + "Dialog should close for cross origin navigation by the content." + ); + } + ); +}); + +/** + * Hides a dialog stack and tests that behavior doesn't change. Ensures + * navigation triggered by web content still closes all dialogs. + */ +add_task(async function test_tabdialogbox_hide() { + await BrowserTestUtils.withNewTab( + "https://example.com", + async function (browser) { + // Open a dialog and wait for it to be ready + let dialogBox = gBrowser.getTabDialogBox(browser); + let dialogBoxManager = dialogBox.getTabDialogManager(); + let closedPromises = [ + dialogBox.open(TEST_DIALOG_PATH).closedPromise, + dialogBox.open(TEST_DIALOG_PATH).closedPromise, + ]; + + let dialogs = dialogBox.getTabDialogManager()._dialogs; + + is( + dialogBox.getTabDialogManager()._dialogs.length, + 2, + "Dialog manager has two dialogs." + ); + + info("Waiting for dialogs to open."); + await Promise.all(dialogs.map(dialog => dialog._dialogReady)); + + ok( + !BrowserTestUtils.is_hidden(dialogBoxManager._dialogStack), + "Dialog stack is showing" + ); + + dialogBoxManager.hideDialog(browser); + + is( + dialogBoxManager._dialogs.length, + 2, + "Dialog manager still has two dialogs." + ); + + ok( + BrowserTestUtils.is_hidden(dialogBoxManager._dialogStack), + "Dialog stack is hidden" + ); + + // Navigate to a different page + BrowserTestUtils.loadURIString(browser, "https://example.org"); + + info("Waiting for dialogs to close."); + await closedPromises; + + ok(true, "All open dialogs should still close on navigation"); + } + ); +}); diff --git a/browser/base/content/test/tabdialogs/loadDelayedReply.sjs b/browser/base/content/test/tabdialogs/loadDelayedReply.sjs new file mode 100644 index 0000000000..cf046967bf --- /dev/null +++ b/browser/base/content/test/tabdialogs/loadDelayedReply.sjs @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function handleRequest(request, response) { + response.processAsync(); + if (request.method === "POST") { + getObjectState("wait", queryResponse => { + if (!queryResponse) { + throw new Error("Wrong call order"); + } + queryResponse.finish(); + + response.setStatusLine(request.httpVersion, 200); + response.write("OK"); + response.finish(); + }); + return; + } + response.setStatusLine(request.httpVersion, 200); + response.write("OK"); + setObjectState("wait", response); +} diff --git a/browser/base/content/test/tabdialogs/subdialog.xhtml b/browser/base/content/test/tabdialogs/subdialog.xhtml new file mode 100644 index 0000000000..03b2b76d49 --- /dev/null +++ b/browser/base/content/test/tabdialogs/subdialog.xhtml @@ -0,0 +1,46 @@ +<?xml version="1.0"?> + +<!-- Any copyright is dedicated to the Public Domain. + - http://creativecommons.org/publicdomain/zero/1.0/ --> + +<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml" + title="Sample sub-dialog"> +<dialog id="subDialog"> + <script> + document.addEventListener("dialogaccept", acceptSubdialog); + function acceptSubdialog() { + window.arguments[0].acceptCount++; + } + document.addEventListener("DOMContentLoaded", () => { + if (!window.arguments) { + return; + } + let [options] = window.arguments; + if (options?.testCustomFocusHandler) { + document.subDialogSetDefaultFocus = () => { + document.getElementById("custom-focus-el").focus(); + } + } + }, {once: true}) + </script> + + <description id="desc">A sample sub-dialog for testing</description> + + <html:input id="textbox" value="Default text" /> + + <html:select id="select"> + <html:option>Foo</html:option> + <html:option>Bar</html:option> + </html:select> + + <html:input id="custom-focus-el" value="Custom Focus Test" /> + + <separator class="thin"/> + + <button oncommand="window.close();" label="Close" /> + +</dialog> +</window> diff --git a/browser/base/content/test/tabdialogs/test_page.html b/browser/base/content/test/tabdialogs/test_page.html new file mode 100644 index 0000000000..c5f17062cf --- /dev/null +++ b/browser/base/content/test/tabdialogs/test_page.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>TabDialogBox Content Modal Test page</title> +</head> +<body onload='alert("Hi");'> + <h1>TabDialogBox Content Modal</h1> +</body> +</html> |