diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /browser/base/content/test/tabdialogs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/base/content/test/tabdialogs')
8 files changed, 557 insertions, 0 deletions
diff --git a/browser/base/content/test/tabdialogs/.eslintrc.js b/browser/base/content/test/tabdialogs/.eslintrc.js new file mode 100644 index 0000000000..1779fd7f1c --- /dev/null +++ b/browser/base/content/test/tabdialogs/.eslintrc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/browser-test"], +}; diff --git a/browser/base/content/test/tabdialogs/browser.ini b/browser/base/content/test/tabdialogs/browser.ini new file mode 100644 index 0000000000..4c3369b022 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser.ini @@ -0,0 +1,10 @@ +[DEFAULT] +support-files = + subdialog.xhtml + +[browser_tabdialogbox_content_prompts.js] +[browser_tabdialogbox_navigation.js] +[browser_tabdialogbox_tab_switch_focus.js] +[browser_subdialog_esc.js] +support-files = + loadDelayedReply.sjs 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..5ad3335b50 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_subdialog_esc.js @@ -0,0 +1,118 @@ +/* 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", + "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("http://example.com", async function( + browser + ) { + // Start loading a page + let loadStartedPromise = BrowserTestUtils.loadURI(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, + }); + + 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("http://example.com", async function( + browser + ) { + // Open the test dialog + let dialogBox = gBrowser.getTabDialogBox(browser); + let dialogClose = dialogBox.open(TEST_DIALOG_PATH, { + keepOpenSameOriginNav: true, + }); + + 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.waitForEvent( + select, + "popupshowing", + true + ); + + info("Opening dropdown"); + select.focus(); + EventUtils.synthesizeKey("VK_SPACE", {}, dialog._frame.contentWindow); + + await shownPromise; + + let hiddenPromise = BrowserTestUtils.waitForEvent( + select, + "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..5544853c91 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js @@ -0,0 +1,76 @@ +/* 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_URL = "data:text/html,<body onload='alert(1)'>"; + +// Setup. +add_task(async function setup() { + 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("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 that title text is shown in tabmodal alert/confirm/prompt dialogs. + */ +add_task(async function test_tabdialog_show_title() { + let dialogShown = BrowserTestUtils.waitForEvent( + gBrowser, + "DOMWillOpenModalDialog" + ); + + await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) { + info("Waiting for dialog to open."); + await dialogShown; + + 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 infoTitle = dialogDoc.querySelector("#infoTitle"); + + ok(BrowserTestUtils.is_visible(infoTitle), "Title text is visible"); + }); +}); 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..7520875afd --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_navigation.js @@ -0,0 +1,162 @@ +/* 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), + dialogBox.open(TEST_DIALOG_PATH), + ]; + + 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.loadURI(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, {}, () => { + 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, + }); + + 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, {}, () => { + 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, {}, () => { + 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), + dialogBox.open(TEST_DIALOG_PATH), + ]; + + 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.loadURI(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/browser_tabdialogbox_tab_switch_focus.js b/browser/base/content/test/tabdialogs/browser_tabdialogbox_tab_switch_focus.js new file mode 100644 index 0000000000..2f19d48022 --- /dev/null +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_tab_switch_focus.js @@ -0,0 +1,131 @@ +/* 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, + "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 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, + "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/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..3dfe537f47 --- /dev/null +++ b/browser/base/content/test/tabdialogs/subdialog.xhtml @@ -0,0 +1,33 @@ +<?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++; + } + </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> + + <separator class="thin"/> + + <button oncommand="window.close();" label="Close" /> + +</dialog> +</window> |