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/tabPrompts | |
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/tabPrompts')
9 files changed, 549 insertions, 0 deletions
diff --git a/browser/base/content/test/tabPrompts/.eslintrc.js b/browser/base/content/test/tabPrompts/.eslintrc.js new file mode 100644 index 0000000000..1779fd7f1c --- /dev/null +++ b/browser/base/content/test/tabPrompts/.eslintrc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/browser-test"], +}; diff --git a/browser/base/content/test/tabPrompts/browser.ini b/browser/base/content/test/tabPrompts/browser.ini new file mode 100644 index 0000000000..ad88b73060 --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser.ini @@ -0,0 +1,8 @@ +[browser_beforeunload_urlbar.js] +support-files = file_beforeunload_stop.html +[browser_closeTabSpecificPanels.js] +skip-if = verify && debug && (os == 'linux') +[browser_confirmFolderUpload.js] +[browser_multiplePrompts.js] +[browser_openPromptInBackgroundTab.js] +support-files = openPromptOffTimeout.html diff --git a/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js b/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js new file mode 100644 index 0000000000..8d6e9bdf40 --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +add_task(async function test_beforeunload_stay_clears_urlbar() { + await SpecialPowers.pushPrefEnv({ + set: [["dom.require_user_interaction_for_beforeunload", false]], + }); + await SpecialPowers.pushPrefEnv({ + set: [["prompts.contentPromptSubDialog", false]], + }); + + const TEST_URL = TEST_ROOT + "file_beforeunload_stop.html"; + await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) { + gURLBar.focus(); + const inputValue = "http://example.org/?q=typed"; + gURLBar.inputField.value = inputValue.slice(0, -1); + EventUtils.sendString(inputValue.slice(-1)); + + let promptOpenedPromise = TestUtils.topicObserved("tabmodal-dialog-loaded"); + EventUtils.synthesizeKey("VK_RETURN"); + await promptOpenedPromise; + let promptElement = browser.parentNode.querySelector("tabmodalprompt"); + + // Click the cancel button + promptElement.querySelector(".tabmodalprompt-button1").click(); + + await TestUtils.waitForCondition( + () => promptElement.parentNode == null, + "tabprompt should be removed" + ); + // Can't just compare directly with TEST_URL because the URL may be trimmed. + // Just need it to not be the example.org thing we typed in. + ok( + gURLBar.value.endsWith("_stop.html"), + "Url bar should be reset to point to the stop html file" + ); + ok( + gURLBar.value.includes("example.com"), + "Url bar should be reset to example.com" + ); + // Check the lock/identity icons are back: + is( + gURLBar.textbox.getAttribute("pageproxystate"), + "valid", + "Should be in valid pageproxy state." + ); + + // Now we need to get rid of the handler to avoid the prompt coming up when trying to close the + // tab when we exit `withNewTab`. :-) + await SpecialPowers.spawn(browser, [], function() { + content.window.onbeforeunload = null; + }); + }); +}); diff --git a/browser/base/content/test/tabPrompts/browser_closeTabSpecificPanels.js b/browser/base/content/test/tabPrompts/browser_closeTabSpecificPanels.js new file mode 100644 index 0000000000..3919957957 --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_closeTabSpecificPanels.js @@ -0,0 +1,51 @@ +"use strict"; + +/* + * This test creates multiple panels, one that has been tagged as specific to its tab's content + * and one that isn't. When a tab loses focus, panel specific to that tab should close. + * The non-specific panel should remain open. + * + */ + +add_task(async function() { + let tab1 = BrowserTestUtils.addTab(gBrowser, "http://mochi.test:8888/#0"); + let tab2 = BrowserTestUtils.addTab(gBrowser, "http://mochi.test:8888/#1"); + let specificPanel = document.createXULElement("panel"); + specificPanel.setAttribute("tabspecific", "true"); + let generalPanel = document.createXULElement("panel"); + let anchor = document.getElementById(CustomizableUI.AREA_NAVBAR); + + anchor.appendChild(specificPanel); + anchor.appendChild(generalPanel); + is(specificPanel.state, "closed", "specificPanel starts as closed"); + is(generalPanel.state, "closed", "generalPanel starts as closed"); + + let specificPanelPromise = BrowserTestUtils.waitForEvent( + specificPanel, + "popupshown" + ); + specificPanel.openPopupAtScreen(210, 210); + await specificPanelPromise; + is(specificPanel.state, "open", "specificPanel has been opened"); + + let generalPanelPromise = BrowserTestUtils.waitForEvent( + generalPanel, + "popupshown" + ); + generalPanel.openPopupAtScreen(510, 510); + await generalPanelPromise; + is(generalPanel.state, "open", "generalPanel has been opened"); + + gBrowser.tabContainer.advanceSelectedTab(-1, true); + is( + specificPanel.state, + "closed", + "specificPanel panel is closed after its tab loses focus" + ); + is(generalPanel.state, "open", "generalPanel is still open after tab switch"); + + specificPanel.remove(); + generalPanel.remove(); + gBrowser.removeTab(tab1); + gBrowser.removeTab(tab2); +}); diff --git a/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js b/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js new file mode 100644 index 0000000000..e9231647f9 --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js @@ -0,0 +1,140 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PromptTestUtils } = ChromeUtils.import( + "resource://testing-common/PromptTestUtils.jsm" +); + +/** + * Create a temporary test directory that will be cleaned up on test shutdown. + * @returns {String} - absolute directory path. + */ +function getTestDirectory() { + let tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile); + tmpDir.append("testdir"); + if (!tmpDir.exists()) { + tmpDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); + registerCleanupFunction(() => { + tmpDir.remove(true); + }); + } + + let file1 = tmpDir.clone(); + file1.append("foo.txt"); + if (!file1.exists()) { + file1.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + } + + let file2 = tmpDir.clone(); + file2.append("bar.txt"); + if (!file2.exists()) { + file2.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + } + + return tmpDir.path; +} + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [ + // Allow using our MockFilePicker in the content process. + ["dom.filesystem.pathcheck.disabled", true], + ["dom.webkitBlink.dirPicker.enabled", true], + ], + }); +}); + +/** + * Create a file input, select a folder and wait for the upload confirmation + * prompt to open. + * @param {boolean} confirmUpload - Whether to accept (true) or cancel the + * prompt (false). + * @returns {Promise} - Resolves once the prompt has been closed. + */ +async function testUploadPrompt(confirmUpload) { + await BrowserTestUtils.withNewTab("http://example.com", async browser => { + // Create file input element + await ContentTask.spawn(browser, null, () => { + let input = content.document.createElement("input"); + input.id = "filepicker"; + input.setAttribute("type", "file"); + input.setAttribute("webkitdirectory", ""); + content.document.body.appendChild(input); + }); + + // If we're confirming the dialog, register a "change" listener on the + // file input. + let changePromise; + if (confirmUpload) { + changePromise = ContentTask.spawn(browser, null, async () => { + let input = content.document.getElementById("filepicker"); + return ContentTaskUtils.waitForEvent(input, "change").then( + e => e.target.files.length + ); + }); + } + + // Register prompt promise + let promptPromise = PromptTestUtils.waitForPrompt(browser, { + modalType: Services.prompt.MODAL_TYPE_TAB, + promptType: "confirmEx", + }); + + // Open filepicker + let path = getTestDirectory(); + await ContentTask.spawn(browser, { path }, args => { + let MockFilePicker = content.SpecialPowers.MockFilePicker; + MockFilePicker.init( + content, + "A Mock File Picker", + content.SpecialPowers.Ci.nsIFilePicker.modeGetFolder + ); + MockFilePicker.useDirectory(args.path); + + let input = content.document.getElementById("filepicker"); + input.click(); + }); + + // Wait for confirmation prompt + let prompt = await promptPromise; + ok(prompt, "Shown upload confirmation prompt"); + is(prompt.ui.button0.label, "Upload", "Accept button label"); + ok(prompt.ui.button1.hasAttribute("default"), "Cancel is default button"); + + // Close confirmation prompt + await PromptTestUtils.handlePrompt(prompt, { + buttonNumClick: confirmUpload ? 0 : 1, + }); + + // If we accepted, wait for the input elements "change" event + if (changePromise) { + let fileCount = await changePromise; + is(fileCount, 2, "Should have selected 2 files"); + } else { + let fileCount = await ContentTask.spawn(browser, null, () => { + return content.document.getElementById("filepicker").files.length; + }); + + is(fileCount, 0, "Should not have selected any files"); + } + + // Cleanup + await ContentTask.spawn(browser, null, () => { + content.SpecialPowers.MockFilePicker.cleanup(); + }); + }); +} + +// Tests the confirmation prompt that shows after the user picked a folder. + +// Confirm the prompt +add_task(async function test_confirm() { + await testUploadPrompt(true); +}); + +// Cancel the prompt +add_task(async function test_cancel() { + await testUploadPrompt(false); +}); diff --git a/browser/base/content/test/tabPrompts/browser_multiplePrompts.js b/browser/base/content/test/tabPrompts/browser_multiplePrompts.js new file mode 100644 index 0000000000..18f41245fd --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_multiplePrompts.js @@ -0,0 +1,96 @@ +"use strict"; + +/* + * This test triggers multiple alerts on one single tab, because it"s possible + * for web content to do so. The behavior is described in bug 1266353. + * + * We assert the presentation of the multiple alerts, ensuring we show only + * the oldest one. + */ +add_task(async function() { + await SpecialPowers.pushPrefEnv({ + set: [["prompts.contentPromptSubDialog", false]], + }); + + const PROMPTCOUNT = 9; + + let contentScript = function(MAX_PROMPT) { + var i = MAX_PROMPT; + let fns = ["alert", "prompt", "confirm"]; + function openDialog() { + i--; + if (i) { + SpecialPowers.Services.tm.dispatchToMainThread(openDialog); + } + window[fns[i % 3]](fns[i % 3] + " countdown #" + i); + } + SpecialPowers.Services.tm.dispatchToMainThread(openDialog); + }; + let url = + "data:text/html,<script>(" + + encodeURIComponent(contentScript.toSource()) + + ")(" + + PROMPTCOUNT + + ");</script>"; + + let promptsOpenedPromise = new Promise(function(resolve) { + let unopenedPromptCount = PROMPTCOUNT; + Services.obs.addObserver(function observer() { + unopenedPromptCount--; + if (!unopenedPromptCount) { + Services.obs.removeObserver(observer, "tabmodal-dialog-loaded"); + info("Prompts opened."); + resolve(); + } + }, "tabmodal-dialog-loaded"); + }); + + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url, true); + info("Tab loaded"); + + await promptsOpenedPromise; + + let promptElementsCount = PROMPTCOUNT; + while (promptElementsCount--) { + let promptElements = tab.linkedBrowser.parentNode.querySelectorAll( + "tabmodalprompt" + ); + is( + promptElements.length, + promptElementsCount + 1, + "There should be " + (promptElementsCount + 1) + " prompt(s)." + ); + // The oldest should be the first. + let i = 0; + for (let promptElement of promptElements) { + let prompt = tab.linkedBrowser.tabModalPromptBox.getPrompt(promptElement); + let expectedType = ["alert", "prompt", "confirm"][i % 3]; + is( + prompt.Dialog.args.text, + expectedType + " countdown #" + i, + "The #" + i + " alert should be labelled as such." + ); + if (i !== promptElementsCount) { + is(prompt.element.hidden, true, "This prompt should be hidden."); + i++; + continue; + } + + is(prompt.element.hidden, false, "The last prompt should not be hidden."); + prompt.onButtonClick(0); + + // The click is handled async; wait for an event loop turn for that to + // happen. + await new Promise(function(resolve) { + Services.tm.dispatchToMainThread(resolve); + }); + } + } + + let promptElements = tab.linkedBrowser.parentNode.querySelectorAll( + "tabmodalprompt" + ); + is(promptElements.length, 0, "Prompts should all be dismissed."); + + BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js new file mode 100644 index 0000000000..7d2fe03db6 --- /dev/null +++ b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js @@ -0,0 +1,170 @@ +"use strict"; + +const { PermissionTestUtils } = ChromeUtils.import( + "resource://testing-common/PermissionTestUtils.jsm" +); + +const ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://example.com/" +); +let pageWithAlert = ROOT + "openPromptOffTimeout.html"; + +registerCleanupFunction(function() { + Services.perms.removeAll(); +}); + +/* + * This test opens a tab that alerts when it is hidden. We then switch away + * from the tab, and check that by default the tab is not automatically + * re-selected. We also check that a checkbox appears in the alert that allows + * the user to enable this automatically re-selecting. We then check that + * checking the checkbox does actually enable that behaviour. + */ +add_task(async function test_old_modal_ui() { + await SpecialPowers.pushPrefEnv({ + set: [["prompts.contentPromptSubDialog", false]], + }); + + let firstTab = gBrowser.selectedTab; + // load page that opens prompt when page is hidden + let openedTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + pageWithAlert, + true + ); + let openedTabGotAttentionPromise = BrowserTestUtils.waitForAttribute( + "attention", + openedTab, + "true" + ); + // switch away from that tab again - this triggers the alert. + await BrowserTestUtils.switchTab(gBrowser, firstTab); + // ... but that's async on e10s... + await openedTabGotAttentionPromise; + // check for attention attribute + is( + openedTab.getAttribute("attention"), + "true", + "Tab with alert should have 'attention' attribute." + ); + ok(!openedTab.selected, "Tab with alert should not be selected"); + + // switch tab back, and check the checkbox is displayed: + await BrowserTestUtils.switchTab(gBrowser, openedTab); + // check the prompt is there, and the extra row is present + let promptElements = openedTab.linkedBrowser.parentNode.querySelectorAll( + "tabmodalprompt" + ); + is(promptElements.length, 1, "There should be 1 prompt"); + let ourPromptElement = promptElements[0]; + let checkbox = ourPromptElement.querySelector( + "checkbox[label*='example.com']" + ); + ok(checkbox, "The checkbox should be there"); + ok(!checkbox.checked, "Checkbox shouldn't be checked"); + // tick box and accept dialog + checkbox.checked = true; + let ourPrompt = openedTab.linkedBrowser.tabModalPromptBox.getPrompt( + ourPromptElement + ); + ourPrompt.onButtonClick(0); + // Wait for that click to actually be handled completely. + await new Promise(function(resolve) { + Services.tm.dispatchToMainThread(resolve); + }); + // check permission is set + is( + Services.perms.ALLOW_ACTION, + PermissionTestUtils.testPermission(pageWithAlert, "focus-tab-by-prompt"), + "Tab switching should now be allowed" + ); + + // Check if the control center shows the correct permission. + let shown = BrowserTestUtils.waitForEvent( + window, + "popupshown", + true, + event => event.target == gIdentityHandler._identityPopup + ); + gIdentityHandler._identityBox.click(); + await shown; + let labelText = SitePermissions.getPermissionLabel("focus-tab-by-prompt"); + let permissionsList = document.getElementById( + "identity-popup-permission-list" + ); + let label = permissionsList.querySelector(".identity-popup-permission-label"); + is(label.textContent, labelText); + gIdentityHandler._identityPopup.hidePopup(); + + // Check if the identity icon signals granted permission. + ok( + gIdentityHandler._identityBox.classList.contains("grantedPermissions"), + "identity-box signals granted permissions" + ); + + let openedTabSelectedPromise = BrowserTestUtils.waitForAttribute( + "selected", + openedTab, + "true" + ); + // switch to other tab again + await BrowserTestUtils.switchTab(gBrowser, firstTab); + + // This is sync in non-e10s, but in e10s we need to wait for this, so yield anyway. + // Note that the switchTab promise doesn't actually guarantee anything about *which* + // tab ends up as selected when its event fires, so using that here wouldn't work. + await openedTabSelectedPromise; + // should be switched back + ok(openedTab.selected, "Ta-dah, the other tab should now be selected again!"); + + // In e10s, with the conformant promise scheduling, we have to wait for next tick + // to ensure that the prompt is open before removing the opened tab, because the + // promise callback of 'openedTabSelectedPromise' could be done at the middle of + // RemotePrompt.openTabPrompt() while 'DOMModalDialogClosed' event is fired. + await TestUtils.waitForTick(); + + BrowserTestUtils.removeTab(openedTab); +}); + +add_task(async function test_new_modal_ui() { + await SpecialPowers.pushPrefEnv({ + set: [["prompts.contentPromptSubDialog", true]], + }); + // Make sure we clear the focus tab permission set in the previous test + PermissionTestUtils.remove(pageWithAlert, "focus-tab-by-prompt"); + + let firstTab = gBrowser.selectedTab; + // load page that opens prompt when page is hidden + let openedTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + pageWithAlert, + true + ); + let openedTabGotAttentionPromise = BrowserTestUtils.waitForAttribute( + "attention", + openedTab, + "true" + ); + // switch away from that tab again - this triggers the alert. + await BrowserTestUtils.switchTab(gBrowser, firstTab); + // ... but that's async on e10s... + await openedTabGotAttentionPromise; + // check for attention attribute + is( + openedTab.getAttribute("attention"), + "true", + "Tab with alert should have 'attention' attribute." + ); + ok(!openedTab.selected, "Tab with alert should not be selected"); + + // switch tab back, and check the checkbox is displayed: + await BrowserTestUtils.switchTab(gBrowser, openedTab); + // check the prompt is there, and the extra row is present + let promptElements = openedTab.linkedBrowser.parentNode.querySelectorAll( + ".content-prompt-dialog" + ); + is(promptElements.length, 1, "There should be 1 prompt"); + + BrowserTestUtils.removeTab(openedTab); +}); diff --git a/browser/base/content/test/tabPrompts/file_beforeunload_stop.html b/browser/base/content/test/tabPrompts/file_beforeunload_stop.html new file mode 100644 index 0000000000..7273e60c65 --- /dev/null +++ b/browser/base/content/test/tabPrompts/file_beforeunload_stop.html @@ -0,0 +1,8 @@ +<body> + <p>I will ask not to be closed.</p> + <script> + window.onbeforeunload = function() { + return "true"; + }; + </script> +</body> diff --git a/browser/base/content/test/tabPrompts/openPromptOffTimeout.html b/browser/base/content/test/tabPrompts/openPromptOffTimeout.html new file mode 100644 index 0000000000..5dfd8cbeff --- /dev/null +++ b/browser/base/content/test/tabPrompts/openPromptOffTimeout.html @@ -0,0 +1,10 @@ +<body> +This page opens an alert box when the page is hidden. +<script> +document.addEventListener("visibilitychange", () => { + if (document.hidden) { + alert("You hid my page!"); + } +}); +</script> +</body> |