diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /toolkit/components/prompts/test/chromeScript.js | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/prompts/test/chromeScript.js')
-rw-r--r-- | toolkit/components/prompts/test/chromeScript.js | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/toolkit/components/prompts/test/chromeScript.js b/toolkit/components/prompts/test/chromeScript.js new file mode 100644 index 0000000000..1e71224f6b --- /dev/null +++ b/toolkit/components/prompts/test/chromeScript.js @@ -0,0 +1,341 @@ +/* eslint-env mozilla/chrome-script */ + +const { clearInterval, setInterval, setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +const { BrowserTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/BrowserTestUtils.sys.mjs" +); + +var tabSubDialogsEnabled = Services.prefs.getBoolPref( + "prompts.tabChromePromptSubDialog", + false +); + +var contentPromptSubdialogsEnabled = Services.prefs.getBoolPref( + "prompts.contentPromptSubDialog", + false +); + +// Define these to make EventUtils happy. +let window = this; +let parent = {}; + +let EventUtils = {}; +Services.scriptloader.loadSubScript( + "chrome://mochikit/content/tests/SimpleTest/EventUtils.js", + EventUtils +); + +addMessageListener("handlePrompt", msg => { + handlePromptWhenItAppears(msg.action, msg.modalType, msg.isSelect); +}); + +async function handlePromptWhenItAppears(action, modalType, isSelect) { + if (!(await handlePrompt(action, modalType, isSelect))) { + setTimeout( + () => this.handlePromptWhenItAppears(action, modalType, isSelect), + 100 + ); + } +} + +function checkTabModal(prompt, browser) { + let doc = browser.ownerDocument; + + let { bottom: toolboxBottom } = doc + .getElementById("navigator-toolbox") + .getBoundingClientRect(); + + let { mainContainer } = prompt.ui; + + let { x, y } = mainContainer.getBoundingClientRect(); + ok(y > 0, "Container should have y > 0"); + // Inset by 1px since the corner point doesn't return the frame due to the + // border-radius. + is( + doc.elementFromPoint(x + 1, y + 1).parentNode, + mainContainer, + "Check tabmodalprompt is visible" + ); + + info("Click to the left of the dialog over the content area"); + isnot( + doc.elementFromPoint(x - 10, y + 50), + browser, + "Check clicks on the content area don't go to the browser" + ); + is( + doc.elementFromPoint(x - 10, y + 50), + prompt.element, + "Check clicks on the content area go to the prompt dialog background" + ); + + if (prompt.args.modalType == Ci.nsIPrompt.MODAL_TYPE_TAB) { + ok( + y <= toolboxBottom - 5, + "Dialog should overlap the toolbox by at least 5px" + ); + } else { + ok(y >= toolboxBottom, "Dialog must not overlap with toolbox."); + } + + ok( + browser.hasAttribute("tabmodalPromptShowing"), + "Check browser has @tabmodalPromptShowing" + ); +} + +async function handlePrompt(action, modalType, isSelect) { + let ui; + let browserWin = Services.wm.getMostRecentWindow("navigator:browser"); + + if ( + (!contentPromptSubdialogsEnabled && + modalType === Services.prompt.MODAL_TYPE_CONTENT) || + (!tabSubDialogsEnabled && modalType === Services.prompt.MODAL_TYPE_TAB) + ) { + let gBrowser = browserWin.gBrowser; + let promptManager = gBrowser.getTabModalPromptBox(gBrowser.selectedBrowser); + let prompts = promptManager.listPrompts(); + if (!prompts.length) { + return false; // try again in a bit + } + + ui = prompts[0].Dialog.ui; + checkTabModal(prompts[0], gBrowser.selectedBrowser); + } else { + let doc = getDialogDoc(); + if (!doc) { + return false; // try again in a bit + } + + if (isSelect) { + ui = doc; + } else { + ui = doc.defaultView.Dialog.ui; + } + } + + let dialogClosed = BrowserTestUtils.waitForEvent( + browserWin, + "DOMModalDialogClosed" + ); + + let promptState; + if (isSelect) { + promptState = getSelectState(ui); + dismissSelect(ui, action); + } else { + promptState = getPromptState(ui); + dismissPrompt(ui, action); + } + + // Wait until the prompt has been closed before sending callback msg. + // Unless the test explicitly doesn't request a button click. + if (action.buttonClick !== "none") { + await dialogClosed; + } + + sendAsyncMessage("promptHandled", { promptState }); + return true; +} + +function getSelectState(ui) { + let listbox = ui.getElementById("list"); + + let state = {}; + state.msg = ui.getElementById("info.txt").value; + state.selectedIndex = listbox.selectedIndex; + state.items = []; + + for (let i = 0; i < listbox.itemCount; i++) { + let item = listbox.getItemAtIndex(i).label; + state.items.push(item); + } + + return state; +} + +function getPromptState(ui) { + let state = {}; + state.msg = ui.infoBody.textContent; + state.infoRowHidden = ui.infoRow?.hidden || false; + state.titleHidden = ui.infoTitle.hidden; + state.textHidden = ui.loginContainer.hidden; + state.passHidden = ui.password1Container.hidden; + state.checkHidden = ui.checkboxContainer.hidden; + state.checkMsg = state.checkHidden ? "" : ui.checkbox.label; + state.checked = state.checkHidden ? false : ui.checkbox.checked; + // TabModalPrompts don't have an infoIcon + state.iconClass = ui.infoIcon ? ui.infoIcon.className : null; + state.textValue = ui.loginTextbox.value; + state.passValue = ui.password1Textbox.value; + + state.butt0Label = ui.button0.label; + state.butt1Label = ui.button1.label; + state.butt2Label = ui.button2.label; + + state.butt0Disabled = ui.button0.disabled; + state.butt1Disabled = ui.button1.disabled; + state.butt2Disabled = ui.button2.disabled; + + function isDefaultButton(b) { + return b.hasAttribute("default") && b.getAttribute("default") == "true"; + } + state.defButton0 = isDefaultButton(ui.button0); + state.defButton1 = isDefaultButton(ui.button1); + state.defButton2 = isDefaultButton(ui.button2); + + let e = Services.focus.focusedElement; + + if (e == null) { + state.focused = null; + } else if (ui.button0.isSameNode(e)) { + state.focused = "button0"; + } else if (ui.button1.isSameNode(e)) { + state.focused = "button1"; + } else if (ui.button2.isSameNode(e)) { + state.focused = "button2"; + } else if (e.isSameNode(ui.loginTextbox)) { + state.focused = "textField"; + } else if (e.isSameNode(ui.password1Textbox)) { + state.focused = "passField"; + } else if (ui.infoBody.isSameNode(e)) { + state.focused = "infoBody"; + } else { + state.focused = + "ERROR: unexpected element focused: " + (e ? e.localName : "<null>"); + } + + let treeOwner = + ui.prompt && ui.prompt.docShell && ui.prompt.docShell.treeOwner; + if (treeOwner && treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)) { + // Check that the dialog is modal, chrome and dependent; + // We can't just check window.opener because that'll be + // a content window, which therefore isn't exposed (it'll lie and + // be null). + let flags = treeOwner.getInterface(Ci.nsIAppWindow).chromeFlags; + state.chrome = (flags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_CHROME) != 0; + state.dialog = (flags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG) != 0; + state.chromeDependent = + (flags & Ci.nsIWebBrowserChrome.CHROME_DEPENDENT) != 0; + let wbc = treeOwner.getInterface(Ci.nsIWebBrowserChrome); + state.isWindowModal = wbc.isWindowModal(); + } + + // Check the dialog is a common dialog document and has been embedded. + let isEmbedded = !!ui.prompt?.docShell?.chromeEventHandler; + let isCommonDialogDoc = + getDialogDoc()?.location.href.includes("commonDialog.xhtml"); + state.isSubDialogPrompt = isCommonDialogDoc && isEmbedded; + state.showCallerOrigin = ui.prompt.args.showCallerOrigin; + + return state; +} + +function dismissSelect(ui, action) { + let dialog = ui.getElementsByTagName("dialog")[0]; + let listbox = ui.getElementById("list"); + + if (action.selectItem) { + listbox.selectedIndex = 1; + } + + if (action.buttonClick == "ok") { + dialog.acceptDialog(); + } else if (action.buttonClick == "cancel") { + dialog.cancelDialog(); + } +} + +function dismissPrompt(ui, action) { + if (action.setCheckbox) { + // Annoyingly, the prompt code is driven by oncommand. + ui.checkbox.checked = true; + ui.checkbox.doCommand(); + } + + if ("textField" in action) { + ui.loginTextbox.setAttribute("value", action.textField); + } + + if ("passField" in action) { + ui.password1Textbox.setAttribute("value", action.passField); + } + + switch (action.buttonClick) { + case "ok": + case 0: + ui.button0.click(); + break; + case "cancel": + case 1: + ui.button1.click(); + break; + case 2: + ui.button2.click(); + break; + case "ESC": + // XXX This is assuming tab-modal. + let browserWin = Services.wm.getMostRecentWindow("navigator:browser"); + EventUtils.synthesizeKey("KEY_Escape", {}, browserWin); + break; + case "pollOK": + // Buttons are disabled at the moment, poll until they're reenabled. + // Can't use setInterval here, because the window's in a modal state + // and thus DOM events are suppressed. + let interval = setInterval(() => { + if (ui.button0.disabled) { + return; + } + ui.button0.click(); + clearInterval(interval); + }, 100); + break; + case "none": + break; + + default: + throw new Error("dismissPrompt action listed unknown button."); + } +} + +function getDialogDoc() { + // Trudge through all the open windows, until we find the one + // that has either commonDialog.xhtml or selectDialog.xhtml loaded. + // var enumerator = Services.wm.getEnumerator("navigator:browser"); + for (let { docShell } of Services.wm.getEnumerator(null)) { + var containedDocShells = docShell.getAllDocShellsInSubtree( + docShell.typeChrome, + docShell.ENUMERATE_FORWARDS + ); + for (let childDocShell of containedDocShells) { + // Get the corresponding document for this docshell + // We don't want it if it's not done loading. + if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) { + continue; + } + var childDoc = childDocShell.docViewer.DOMDocument; + + if ( + childDoc.location.href != + "chrome://global/content/commonDialog.xhtml" && + childDoc.location.href != "chrome://global/content/selectDialog.xhtml" + ) { + continue; + } + + // We're expecting the dialog to be focused. If it's not yet, try later. + // (In particular, this is needed on Linux to reliably check focused elements.) + if (Services.focus.focusedWindow != childDoc.defaultView) { + continue; + } + + return childDoc; + } + } + + return null; +} |