summaryrefslogtreecommitdiffstats
path: root/toolkit/components/prompts/test
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/prompts/test')
-rw-r--r--toolkit/components/prompts/test/.eslintrc.js8
-rw-r--r--toolkit/components/prompts/test/PromptTestUtils.jsm248
-rw-r--r--toolkit/components/prompts/test/bug619644_inner.html7
-rw-r--r--toolkit/components/prompts/test/bug625187_iframe.html16
-rw-r--r--toolkit/components/prompts/test/chrome.ini11
-rw-r--r--toolkit/components/prompts/test/chromeScript.js354
-rw-r--r--toolkit/components/prompts/test/mochitest.ini17
-rw-r--r--toolkit/components/prompts/test/prompt_common.js444
-rw-r--r--toolkit/components/prompts/test/test_bug619644.html74
-rw-r--r--toolkit/components/prompts/test/test_bug620145.html96
-rw-r--r--toolkit/components/prompts/test/test_dom_prompts.html207
-rw-r--r--toolkit/components/prompts/test/test_modal_prompts.html1311
-rw-r--r--toolkit/components/prompts/test/test_modal_select.html138
-rw-r--r--toolkit/components/prompts/test/test_subresources_prompts.html200
14 files changed, 3131 insertions, 0 deletions
diff --git a/toolkit/components/prompts/test/.eslintrc.js b/toolkit/components/prompts/test/.eslintrc.js
new file mode 100644
index 0000000000..af973e82fe
--- /dev/null
+++ b/toolkit/components/prompts/test/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+ rules: {
+ // ownerGlobal doesn't exist in content privileged windows.
+ "mozilla/use-ownerGlobal": "off",
+ },
+};
diff --git a/toolkit/components/prompts/test/PromptTestUtils.jsm b/toolkit/components/prompts/test/PromptTestUtils.jsm
new file mode 100644
index 0000000000..53c9da01cd
--- /dev/null
+++ b/toolkit/components/prompts/test/PromptTestUtils.jsm
@@ -0,0 +1,248 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Utility module for tests to interact with prompts spawned by nsIPrompt or
+ * nsIPromptService.
+ */
+
+"use strict";
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+const { BrowserTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/BrowserTestUtils.sys.mjs"
+);
+
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+const EXPORTED_SYMBOLS = ["PromptTestUtils"];
+
+const kPrefs = {};
+
+// Whether prompts with modal type TAB are shown as SubDialog (true) or
+// TabModalPrompt (false).
+XPCOMUtils.defineLazyPreferenceGetter(
+ kPrefs,
+ "tabPromptSubDialogEnabled",
+ "prompts.tabChromePromptSubDialog",
+ false
+);
+
+// Whether web content prompts (alert etc.) are shown as SubDialog (true)
+// or TabModalPrompt (false)
+XPCOMUtils.defineLazyPreferenceGetter(
+ kPrefs,
+ "contentPromptSubDialogEnabled",
+ "prompts.contentPromptSubDialog",
+ false
+);
+
+function isCommonDialog(modalType) {
+ return (
+ modalType === Services.prompt.MODAL_TYPE_WINDOW ||
+ (kPrefs.tabPromptSubDialogEnabled &&
+ modalType === Services.prompt.MODAL_TYPE_TAB) ||
+ (kPrefs.contentPromptSubDialogEnabled &&
+ modalType === Services.prompt.MODAL_TYPE_CONTENT)
+ );
+}
+
+let PromptTestUtils = {
+ /**
+ * Wait for a prompt from nsIPrompt or nsIPromptsService, interact with it and
+ * click the specified button to close it.
+ * @param {Browser|Window} [parent] - Parent of the prompt. This can be
+ * either the parent window or the browser. For tab prompts, if given a
+ * window, the currently selected browser in that window will be used.
+ * @param {Object} promptOptions - @see waitForPrompt
+ * @param {Object} promptActions - @see handlePrompt
+ * @returns {Promise} - A promise which resolves once the prompt has been
+ * closed.
+ */
+ async handleNextPrompt(parent, promptOptions, promptActions) {
+ let dialog = await this.waitForPrompt(parent, promptOptions);
+ return this.handlePrompt(dialog, promptActions);
+ },
+
+ /**
+ * Interact with an existing prompt and close it.
+ * @param {Dialog} dialog - The dialog instance associated with the prompt.
+ * @param {Object} [actions] - Options on how to interact with the
+ * prompt and how to close it.
+ * @param {Boolean} [actions.checkboxState] - Set the checkbox state.
+ * true = checked, false = unchecked.
+ * @param {Number} [actions.buttonNumClick] - Which button to click to close
+ * the prompt.
+ * @param {String} [actions.loginInput] - Input text for the login text field.
+ * This field is also used for text input for the "prompt" type.
+ * @param {String} [actions.passwordInput] - Input text for the password text
+ * field.
+ * @returns {Promise} - A promise which resolves once the prompt has been
+ * closed.
+ */
+ handlePrompt(
+ dialog,
+ {
+ checkboxState = null,
+ buttonNumClick = 0,
+ loginInput = null,
+ passwordInput = null,
+ } = {}
+ ) {
+ let promptClosePromise;
+
+ // Get parent window to listen for prompt close event
+ let win;
+ if (isCommonDialog(dialog.args.modalType)) {
+ win = dialog.ui.prompt?.opener;
+ } else {
+ // Tab prompts should always have a parent window
+ win = dialog.ui.prompt.win;
+ }
+
+ if (win) {
+ promptClosePromise = BrowserTestUtils.waitForEvent(
+ win,
+ "DOMModalDialogClosed"
+ );
+ } else {
+ // We don't have a parent, wait for window close instead
+ promptClosePromise = BrowserTestUtils.windowClosed(dialog.ui.prompt);
+ }
+
+ if (typeof checkboxState == "boolean") {
+ dialog.ui.checkbox.checked = checkboxState;
+ }
+
+ if (loginInput != null) {
+ dialog.ui.loginTextbox.value = loginInput;
+ }
+
+ if (passwordInput != null) {
+ dialog.ui.password1Textbox.value = passwordInput;
+ }
+
+ let button = dialog.ui["button" + buttonNumClick];
+ if (!button) {
+ throw new Error("Could not find button with index " + buttonNumClick);
+ }
+ button.click();
+
+ return promptClosePromise;
+ },
+
+ /**
+ * Wait for a prompt from nsIPrompt or nsIPromptsService to open.
+ * @param {Browser|Window} [parent] - Parent of the prompt. This can be either
+ * the parent window or the browser. For tab prompts, if given a window, the
+ * currently selected browser in that window will be used.
+ * If not given a parent, the method will return on prompts of any window.
+ * @param {Object} attrs - The prompt attributes to filter for.
+ * @param {Number} attrs.modalType - Whether the expected prompt is a content, tab or window prompt.
+ * nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
+ * @param {String} [attrs.promptType] - Common dialog type of the prompt to filter for.
+ * @see {@link CommonDialog} for possible prompt types.
+ * @returns {Promise<CommonDialog>} - A Promise which resolves with a dialog
+ * object once the prompt has loaded.
+ */
+ async waitForPrompt(parent, { modalType, promptType = null } = {}) {
+ if (!modalType) {
+ throw new Error("modalType is mandatory");
+ }
+
+ // Get window by browser or browser by window, depending on what is passed
+ // via the parent arg. If the caller passes parent=null, both will be null.
+ let parentWindow;
+ let parentBrowser;
+ if (parent) {
+ if (Element.isInstance(parent)) {
+ // Parent is browser
+ parentBrowser = parent;
+ parentWindow = parentBrowser.ownerGlobal;
+ } else if (parent instanceof Ci.nsIDOMChromeWindow) {
+ // Parent is window
+ parentWindow = parent;
+ parentBrowser = parentWindow.gBrowser?.selectedBrowser;
+ } else {
+ throw new Error("Invalid parent. Expected browser or dom window");
+ }
+ }
+
+ let topic = isCommonDialog(modalType)
+ ? "common-dialog-loaded"
+ : "tabmodal-dialog-loaded";
+
+ let dialog;
+ await TestUtils.topicObserved(topic, subject => {
+ // If we are not given a browser, use the currently selected browser of the window
+ let browser =
+ parentBrowser || subject.ownerGlobal.gBrowser?.selectedBrowser;
+ if (isCommonDialog(modalType)) {
+ // Is not associated with given parent window, skip
+ if (parentWindow && subject.opener !== parentWindow) {
+ return false;
+ }
+
+ // For tab prompts, ensure that the associated browser matches.
+ if (browser && modalType == Services.prompt.MODAL_TYPE_TAB) {
+ let dialogBox = parentWindow.gBrowser.getTabDialogBox(browser);
+ let hasMatchingDialog = dialogBox
+ .getTabDialogManager()
+ ._dialogs.some(
+ d => d._frame?.browsingContext == subject.browsingContext
+ );
+ if (!hasMatchingDialog) {
+ return false;
+ }
+ }
+
+ if (browser && modalType == Services.prompt.MODAL_TYPE_CONTENT) {
+ let dialogBox = parentWindow.gBrowser.getTabDialogBox(browser);
+ let hasMatchingDialog = dialogBox
+ .getContentDialogManager()
+ ._dialogs.some(
+ d => d._frame?.browsingContext == subject.browsingContext
+ );
+ if (!hasMatchingDialog) {
+ return false;
+ }
+ }
+
+ // subject is the window object of the prompt which has a Dialog object
+ // attached.
+ dialog = subject.Dialog;
+ } else {
+ // subject is the tabprompt dom node
+ // Get the full prompt object which has the dialog object
+ let prompt = browser.tabModalPromptBox.getPrompt(subject);
+
+ // Is not associated with given parent browser, skip.
+ if (!prompt) {
+ return false;
+ }
+
+ dialog = prompt.Dialog;
+ }
+
+ // Not the modalType we're looking for.
+ // For window prompts dialog.args.modalType is undefined.
+ if (isCommonDialog(modalType) && dialog.args.modalType !== modalType) {
+ return false;
+ }
+
+ // Not the promptType we're looking for.
+ if (promptType && dialog.args.promptType !== promptType) {
+ return false;
+ }
+
+ // Prompt found
+ return true;
+ });
+
+ return dialog;
+ },
+};
diff --git a/toolkit/components/prompts/test/bug619644_inner.html b/toolkit/components/prompts/test/bug619644_inner.html
new file mode 100644
index 0000000000..cecfa78bad
--- /dev/null
+++ b/toolkit/components/prompts/test/bug619644_inner.html
@@ -0,0 +1,7 @@
+<head></head><body><p>Original content</p>
+<script>
+ window.opener.postMessage("", "*");
+ confirm("Message");
+ document.write("Extra content");
+ window.opener.postMessage(document.documentElement.innerHTML, "*");
+</script></body>
diff --git a/toolkit/components/prompts/test/bug625187_iframe.html b/toolkit/components/prompts/test/bug625187_iframe.html
new file mode 100644
index 0000000000..740d59a617
--- /dev/null
+++ b/toolkit/components/prompts/test/bug625187_iframe.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+ <title>Test for Bug 625187 - the iframe</title>
+<!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -
+ - Contributor(s):
+ - Mihai Sucan <mihai.sucan@gmail.com>
+ -->
+</head>
+<body>
+<p><button id="btn1" onclick="alert('hello world 2')">Button 2</button></p>
+<p><button id="btn2" onclick="window.parent.alert('hello world 3')">Button 3</button></p>
+</body>
+</html>
diff --git a/toolkit/components/prompts/test/chrome.ini b/toolkit/components/prompts/test/chrome.ini
new file mode 100644
index 0000000000..90eee3a761
--- /dev/null
+++ b/toolkit/components/prompts/test/chrome.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+support-files =
+ prompt_common.js
+ chromeScript.js
+
+[test_modal_prompts.html]
+skip-if =
+ toolkit == 'android' #android: TIMED_OUT
+ os == 'linux' && (debug || asan || tsan)
+[test_modal_select.html]
+skip-if = toolkit == 'android' #android: TIMED_OUT
diff --git a/toolkit/components/prompts/test/chromeScript.js b/toolkit/components/prompts/test/chromeScript.js
new file mode 100644
index 0000000000..e31fbdc851
--- /dev/null
+++ b/toolkit/components/prompts/test/chromeScript.js
@@ -0,0 +1,354 @@
+/* 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 => {
+ info("Received handlePrompt message");
+ handlePromptWhenItAppears(msg.action, msg.modalType, msg.isSelect);
+});
+
+async function handlePromptWhenItAppears(action, modalType, isSelect) {
+ try {
+ if (!(await handlePrompt(action, modalType, isSelect))) {
+ setTimeout(
+ () => this.handlePromptWhenItAppears(action, modalType, isSelect),
+ 100
+ );
+ }
+ } catch (e) {
+ info(`handlePromptWhenItAppears: exception: ${e}`);
+ }
+}
+
+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) {
+ info(`handlePrompt: modalType=${modalType}`);
+
+ 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) {
+ info("handlePrompt: no prompt found. retrying...");
+ return false; // try again in a bit
+ }
+
+ ui = prompts[0].Dialog.ui;
+ checkTabModal(prompts[0], gBrowser.selectedBrowser);
+ } else {
+ let doc = getDialogDoc();
+ if (!doc) {
+ info("handlePrompt: no document found. retrying...");
+ 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") {
+ info(`handlePrompt: wait for dialogClosed`);
+ await dialogClosed;
+ }
+
+ info(`handlePrompt: send promptHandled`);
+ 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) {
+ info(`dismissPrompt: action=${JSON.stringify(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.contentViewer.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;
+}
diff --git a/toolkit/components/prompts/test/mochitest.ini b/toolkit/components/prompts/test/mochitest.ini
new file mode 100644
index 0000000000..6f00eb3815
--- /dev/null
+++ b/toolkit/components/prompts/test/mochitest.ini
@@ -0,0 +1,17 @@
+[DEFAULT]
+support-files =
+ ../../passwordmgr/test/authenticate.sjs
+ bug619644_inner.html
+ bug625187_iframe.html
+ prompt_common.js
+ chromeScript.js
+
+[test_bug619644.html]
+skip-if = toolkit == 'android' # No tab prompts on android
+[test_bug620145.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_subresources_prompts.html]
+skip-if = toolkit == 'android' || verify
+fail-if = xorigin
+[test_dom_prompts.html]
+skip-if = toolkit == 'android' #android: bug 1267092
diff --git a/toolkit/components/prompts/test/prompt_common.js b/toolkit/components/prompts/test/prompt_common.js
new file mode 100644
index 0000000000..a47d421d3c
--- /dev/null
+++ b/toolkit/components/prompts/test/prompt_common.js
@@ -0,0 +1,444 @@
+const { Cc, Ci, Cu: ChromeUtils } = SpecialPowers;
+
+/**
+ * Converts a property bag to object.
+ * @param {nsIPropertyBag} bag - The property bag to convert
+ * @returns {Object} - The object representation of the nsIPropertyBag
+ */
+function propBagToObject(bag) {
+ if (!(bag instanceof Ci.nsIPropertyBag)) {
+ throw new TypeError("Not a property bag");
+ }
+ let result = {};
+ for (let { name, value } of bag.enumerator) {
+ result[name] = value;
+ }
+ return result;
+}
+
+var modalType;
+var tabSubDialogsEnabled = SpecialPowers.Services.prefs.getBoolPref(
+ "prompts.tabChromePromptSubDialog",
+ false
+);
+var contentSubDialogsEnabled = SpecialPowers.Services.prefs.getBoolPref(
+ "prompts.contentPromptSubDialog",
+ false
+);
+var isSelectDialog = false;
+var isOSX = "nsILocalFileMac" in SpecialPowers.Ci;
+var isE10S = SpecialPowers.Services.appinfo.processType == 2;
+
+var gChromeScript = SpecialPowers.loadChromeScript(
+ SimpleTest.getTestFileURL("chromeScript.js")
+);
+SimpleTest.registerCleanupFunction(() => gChromeScript.destroy());
+
+async function runPromptCombinations(window, testFunc) {
+ let util = new PromptTestUtil(window);
+ let run = () => {
+ info(
+ `Running tests (modalType=${modalType}, usePromptService=${util.usePromptService}, useBrowsingContext=${util.useBrowsingContext}, useAsync=${util.useAsync})`
+ );
+ return testFunc(util);
+ };
+
+ // Prompt service with dom window parent only supports window prompts
+ util.usePromptService = true;
+ util.useBrowsingContext = false;
+ util.modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
+ modalType = util.modalType;
+ util.useAsync = false;
+ await run();
+
+ let modalTypes = [
+ Ci.nsIPrompt.MODAL_TYPE_WINDOW,
+ Ci.nsIPrompt.MODAL_TYPE_TAB,
+ Ci.nsIPrompt.MODAL_TYPE_CONTENT,
+ ];
+
+ for (let type of modalTypes) {
+ util.modalType = type;
+ modalType = type;
+
+ // Prompt service with browsing context sync
+ util.usePromptService = true;
+ util.useBrowsingContext = true;
+ util.useAsync = false;
+ await run();
+
+ // Prompt service with browsing context async
+ util.usePromptService = true;
+ util.useBrowsingContext = true;
+ util.useAsync = true;
+ await run();
+
+ // nsIPrompt
+ // modalType is set via nsIWritablePropertyBag (legacy)
+ util.usePromptService = false;
+ util.useBrowsingContext = false;
+ util.useAsync = false;
+ await run();
+ }
+}
+
+class PromptTestUtil {
+ constructor(window) {
+ this.window = window;
+ this.browsingContext = SpecialPowers.wrap(
+ window
+ ).windowGlobalChild.browsingContext;
+ this.promptService = SpecialPowers.Services.prompt;
+ this.nsPrompt = Cc["@mozilla.org/prompter;1"]
+ .getService(Ci.nsIPromptFactory)
+ .getPrompt(window, Ci.nsIPrompt);
+
+ this.usePromptService = null;
+ this.useBrowsingContext = null;
+ this.useAsync = null;
+ this.modalType = null;
+ }
+
+ get _prompter() {
+ if (this.usePromptService) {
+ return this.promptService;
+ }
+ return this.nsPrompt;
+ }
+
+ async prompt(funcName, promptArgs) {
+ if (
+ this.useBrowsingContext == null ||
+ this.usePromptService == null ||
+ this.useAsync == null ||
+ this.modalType == null
+ ) {
+ throw new Error("Not initialized");
+ }
+ let args = [];
+ if (this.usePromptService) {
+ if (this.useBrowsingContext) {
+ if (this.useAsync) {
+ funcName = `async${funcName[0].toUpperCase()}${funcName.substring(
+ 1
+ )}`;
+ } else {
+ funcName += "BC";
+ }
+ args = [this.browsingContext, this.modalType];
+ } else {
+ args = [this.window];
+ }
+ } else {
+ let bag = this.nsPrompt.QueryInterface(Ci.nsIWritablePropertyBag2);
+ bag.setPropertyAsUint32("modalType", this.modalType);
+ }
+ // Append the prompt arguments
+ args = args.concat(promptArgs);
+
+ let interfaceName = this.usePromptService ? "Services.prompt" : "prompt";
+ ok(
+ this._prompter[funcName],
+ `${interfaceName} should have method ${funcName}.`
+ );
+
+ info(`Calling ${interfaceName}.${funcName}(${args})`);
+ let result = this._prompter[funcName](...args);
+ is(
+ this.useAsync,
+ result != null &&
+ result.constructor != null &&
+ result.constructor.name === "Promise",
+ "If method is async it should return a promise."
+ );
+
+ if (this.useAsync) {
+ let propBag = await result;
+ return propBag && propBagToObject(propBag);
+ }
+ return result;
+ }
+}
+
+function onloadPromiseFor(id) {
+ var iframe = document.getElementById(id);
+ return new Promise(resolve => {
+ iframe.addEventListener(
+ "load",
+ function(e) {
+ resolve(true);
+ },
+ { once: true }
+ );
+ });
+}
+
+/**
+ * Take an action on the next prompt that appears without checking the state in advance.
+ * This is useful when the action doesn't depend on which prompt is shown and you
+ * are expecting multiple prompts at once in an indeterminate order.
+ * If you know the state of the prompt you expect you should use `handlePrompt` instead.
+ * @param {object} action defining how to handle the prompt
+ * @returns {Promise} resolving with the prompt state.
+ */
+function handlePromptWithoutChecks(action) {
+ return new Promise(resolve => {
+ gChromeScript.addMessageListener("promptHandled", function handled(msg) {
+ gChromeScript.removeMessageListener("promptHandled", handled);
+ resolve(msg.promptState);
+ });
+ gChromeScript.sendAsyncMessage("handlePrompt", { action, modalType });
+ });
+}
+
+async function handlePrompt(state, action) {
+ let actualState = await handlePromptWithoutChecks(action);
+ checkPromptState(actualState, state);
+}
+
+function checkPromptState(promptState, expectedState) {
+ info(`checkPromptState: Expected: ${expectedState.msg}`);
+ // XXX check title? OS X has title in content
+ is(promptState.msg, expectedState.msg, "Checking expected message");
+
+ let isOldContentPrompt =
+ !promptState.isSubDialogPrompt &&
+ modalType === Ci.nsIPrompt.MODAL_TYPE_CONTENT;
+
+ if (isOldContentPrompt && !promptState.showCallerOrigin) {
+ ok(
+ promptState.titleHidden,
+ "The title should be hidden for content prompts opened with tab modal prompt."
+ );
+ } else if (
+ isOSX ||
+ promptState.isSubDialogPrompt ||
+ promptState.showCallerOrigin
+ ) {
+ ok(
+ !promptState.titleHidden,
+ "Checking title always visible on OS X or when opened with common dialog"
+ );
+ } else {
+ is(
+ promptState.titleHidden,
+ expectedState.titleHidden,
+ "Checking title visibility"
+ );
+ }
+ is(
+ promptState.textHidden,
+ expectedState.textHidden,
+ "Checking textbox visibility"
+ );
+ is(
+ promptState.passHidden,
+ expectedState.passHidden,
+ "Checking passbox visibility"
+ );
+ is(
+ promptState.checkHidden,
+ expectedState.checkHidden,
+ "Checking checkbox visibility"
+ );
+ is(promptState.checkMsg, expectedState.checkMsg, "Checking checkbox label");
+ is(promptState.checked, expectedState.checked, "Checking checkbox checked");
+ if (
+ modalType === Ci.nsIPrompt.MODAL_TYPE_WINDOW ||
+ (modalType === Ci.nsIPrompt.MODAL_TYPE_TAB && tabSubDialogsEnabled)
+ ) {
+ is(
+ promptState.iconClass,
+ expectedState.iconClass,
+ "Checking expected icon CSS class"
+ );
+ }
+ is(promptState.textValue, expectedState.textValue, "Checking textbox value");
+ is(promptState.passValue, expectedState.passValue, "Checking passbox value");
+
+ if (expectedState.butt0Label) {
+ is(
+ promptState.butt0Label,
+ expectedState.butt0Label,
+ "Checking accept-button label"
+ );
+ }
+ if (expectedState.butt1Label) {
+ is(
+ promptState.butt1Label,
+ expectedState.butt1Label,
+ "Checking cancel-button label"
+ );
+ }
+ if (expectedState.butt2Label) {
+ is(
+ promptState.butt2Label,
+ expectedState.butt2Label,
+ "Checking extra1-button label"
+ );
+ }
+
+ // For prompts with a time-delay button.
+ if (expectedState.butt0Disabled) {
+ is(promptState.butt0Disabled, true, "Checking accept-button is disabled");
+ is(
+ promptState.butt1Disabled,
+ false,
+ "Checking cancel-button isn't disabled"
+ );
+ }
+
+ is(
+ promptState.defButton0,
+ expectedState.defButton == "button0",
+ "checking button0 default"
+ );
+ is(
+ promptState.defButton1,
+ expectedState.defButton == "button1",
+ "checking button1 default"
+ );
+ is(
+ promptState.defButton2,
+ expectedState.defButton == "button2",
+ "checking button2 default"
+ );
+
+ if (
+ isOSX &&
+ expectedState.focused &&
+ expectedState.focused.startsWith("button") &&
+ !promptState.infoRowHidden
+ ) {
+ is(
+ promptState.focused,
+ "infoBody",
+ "buttons don't focus on OS X, but infoBody does instead"
+ );
+ } else {
+ is(promptState.focused, expectedState.focused, "Checking focused element");
+ }
+
+ if (expectedState.hasOwnProperty("chrome")) {
+ is(
+ promptState.chrome,
+ expectedState.chrome,
+ "Dialog should be opened as chrome"
+ );
+ }
+ if (expectedState.hasOwnProperty("dialog")) {
+ is(
+ promptState.dialog,
+ expectedState.dialog,
+ "Dialog should be opened as a dialog"
+ );
+ }
+ if (expectedState.hasOwnProperty("chromeDependent")) {
+ is(
+ promptState.chromeDependent,
+ expectedState.chromeDependent,
+ "Dialog should be opened as dependent"
+ );
+ }
+ if (expectedState.hasOwnProperty("isWindowModal")) {
+ is(
+ promptState.isWindowModal,
+ expectedState.isWindowModal,
+ "Dialog should be modal"
+ );
+ }
+}
+
+function checkEchoedAuthInfo(expectedState, browsingContext) {
+ return SpecialPowers.spawn(
+ browsingContext,
+ [expectedState.user, expectedState.pass],
+ (expectedUser, expectedPass) => {
+ let doc = this.content.document;
+
+ // The server echos back the HTTP auth info it received.
+ let username = doc.getElementById("user").textContent;
+ let password = doc.getElementById("pass").textContent;
+ let authok = doc.getElementById("ok").textContent;
+
+ Assert.equal(authok, "PASS", "Checking for successful authentication");
+ Assert.equal(username, expectedUser, "Checking for echoed username");
+ Assert.equal(password, expectedPass, "Checking for echoed password");
+ }
+ );
+}
+
+/**
+ * Create a Proxy to relay method calls on an nsIAuthPrompt[2] prompter to a chrome script which can
+ * perform the calls in the parent. Out and inout params will be copied back from the parent to
+ * content.
+ *
+ * @param chromeScript The reference to the chrome script that will listen to `proxyPrompter`
+ * messages in the parent and call the `methodName` method.
+ * The return value from the message handler should be an object with properties:
+ * `rv` - containing the return value of the method call.
+ * `args` - containing the array of arguments passed to the method since out or inout ones could have
+ * been modified.
+ */
+function PrompterProxy(chromeScript) {
+ return new Proxy(
+ {},
+ {
+ get(target, prop, receiver) {
+ return (...args) => {
+ // Array of indices of out/inout params to copy from the parent back to the caller.
+ let outParams = [];
+
+ switch (prop) {
+ case "prompt": {
+ outParams = [/* result */ 5];
+ break;
+ }
+ case "promptAuth": {
+ outParams = [];
+ break;
+ }
+ case "promptPassword": {
+ outParams = [/* pwd */ 4];
+ break;
+ }
+ case "promptUsernameAndPassword": {
+ outParams = [/* user */ 4, /* pwd */ 5];
+ break;
+ }
+ default: {
+ throw new Error("Unknown nsIAuthPrompt method");
+ }
+ }
+
+ let result;
+ chromeScript
+ .sendQuery("proxyPrompter", {
+ args,
+ methodName: prop,
+ })
+ .then(val => {
+ result = val;
+ });
+ SpecialPowers.Services.tm.spinEventLoopUntil(
+ "Test(prompt_common.js:get)",
+ () => result
+ );
+
+ for (let outParam of outParams) {
+ // Copy the out or inout param value over the original
+ args[outParam].value = result.args[outParam].value;
+ }
+
+ if (prop == "promptAuth") {
+ args[2].username = result.args[2].username;
+ args[2].password = result.args[2].password;
+ args[2].domain = result.args[2].domain;
+ }
+
+ return result.rv;
+ };
+ },
+ }
+ );
+}
diff --git a/toolkit/components/prompts/test/test_bug619644.html b/toolkit/components/prompts/test/test_bug619644.html
new file mode 100644
index 0000000000..2b424c71a6
--- /dev/null
+++ b/toolkit/components/prompts/test/test_bug619644.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=619644
+-->
+<head>
+ <title>Test for Bug 619644</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=619644">Mozilla Bug 619644</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+// This is a little yucky, but it works
+// The contents of bug619644_inner.html
+const expectedFinalDoc =
+"<head><\/head><body><p>Original content<\/p>\n<script>\n window.opener.postMessage(\"\", \"*\");\n confirm(\"Message\");\n document.write(\"Extra content\");\n window.opener.postMessage(document.documentElement.innerHTML, \"*\");\n<\/script>Extra content<\/body>";
+
+inittest();
+
+var promptDone;
+
+function inittest() {
+ window.addEventListener("message", runtest);
+ window.open("bug619644_inner.html", "619644");
+
+ SimpleTest.waitForExplicitFinish();
+}
+
+function runtest(e) {
+ modalType = Ci.nsIPrompt.MODAL_TYPE_CONTENT;
+
+ window.removeEventListener("message", runtest);
+ window.addEventListener("message", checktest);
+
+ let state = {
+ msg: "Message",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ let action = {
+ buttonClick: "ESC",
+ };
+
+ promptDone = handlePrompt(state, action);
+}
+
+function checktest(e) {
+ is(e.data, expectedFinalDoc, "ESC press should not abort document load");
+ e.source.close();
+ promptDone.then(endtest);
+}
+
+function endtest() {
+ info("Ending test");
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/toolkit/components/prompts/test/test_bug620145.html b/toolkit/components/prompts/test/test_bug620145.html
new file mode 100644
index 0000000000..3894a528ae
--- /dev/null
+++ b/toolkit/components/prompts/test/test_bug620145.html
@@ -0,0 +1,96 @@
+<html>
+<head>
+ <title>Test for Bug 620145</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=620145">Mozilla Bug 620145</a>
+<pre id="test">
+</pre>
+
+<div id="text" style="max-width: 100px" onmouseup="openAlert()">
+ This is a short piece of text used for testing that mouse selecting is
+ stopped when an alert appears.
+</div>
+<div id="text2" style="max-width: 100px">
+ This is another short piece of text used for testing that mouse selecting is
+ stopped when an alert appears.
+</div>
+<button id="button" onmouseup="openAlert()">Button</button>
+
+<script class="testbody" type="text/javascript">
+
+function openAlert() {
+ info("opening alert...");
+ alert("hello!");
+ info("...alert done.");
+}
+
+add_task(async function runTest() {
+ var state, action;
+ // The <button> in this test's HTML opens a prompt when clicked.
+ // Here we send the events to simulate clicking it.
+ modalType = Ci.nsIPrompt.MODAL_TYPE_CONTENT;
+
+ state = {
+ msg: "hello!",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ var button = $("button");
+ dispatchMouseEvent(button, "mousedown");
+ dispatchMouseEvent(button, "mouseup");
+ // alert appears at this point, to be closed by the chrome script.
+
+ await promptDone;
+ checkSelection();
+
+ // using same state and action.
+ promptDone = handlePrompt(state, action);
+
+ var text = $("text");
+ dispatchMouseEvent(text, "mousedown");
+ dispatchMouseEvent(text, "mouseup");
+ // alert appears at this point, to be closed by the chrome script.
+
+ await promptDone;
+ checkSelection();
+});
+
+function dispatchMouseEvent(target, type) {
+ var win = target.ownerDocument.defaultView;
+ let e = document.createEvent("MouseEvent");
+ e.initEvent(type, false, false, win, 0, 1, 1, 1, 1,
+ false, false, false, false, 0, null);
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ utils.dispatchDOMEventViaPresShellForTesting(target, e);
+ ok(true, type + " sent to " + target.id);
+}
+
+function checkSelection() {
+ synthesizeMouse($("text"), 25, 55, { type: "mousemove" });
+ is(window.getSelection().toString(), "", "selection not made");
+}
+</script>
+
+</body>
+</html>
diff --git a/toolkit/components/prompts/test/test_dom_prompts.html b/toolkit/components/prompts/test/test_dom_prompts.html
new file mode 100644
index 0000000000..95595b8df2
--- /dev/null
+++ b/toolkit/components/prompts/test/test_dom_prompts.html
@@ -0,0 +1,207 @@
+<html>
+<head>
+ <title>Test for DOM prompts</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="text/javascript">
+var rv;
+var state, action;
+modalType = Ci.nsIPrompt.MODAL_TYPE_CONTENT;
+
+add_task(async function test_alert_ok() {
+ info("Starting test: Alert");
+ state = {
+ msg: "This is the alert text.",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ alert("This is the alert text.");
+
+ await promptDone;
+});
+
+// bug 861605 made the arguments to alert/confirm optional (prompt already was).
+add_task(async function test_alert_noargs() {
+ info("Starting test: Alert with no args");
+ state = {
+ msg: "",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ try {
+ alert();
+ ok(true, "alert() without arguments should not throw!");
+ } catch (e) {
+ ok(false, "alert() without arguments should not throw!");
+ }
+
+ await promptDone;
+});
+
+add_task(async function test_confirm_ok() {
+ info("Starting test: Confirm");
+ state = {
+ msg: "This is the confirm text.",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ rv = confirm("This is the confirm text.");
+ is(rv, true, "check prompt return value");
+
+ await promptDone;
+});
+
+// bug 861605 made the arguments to alert/confirm optional (prompt already was).
+add_task(async function test_confirm_noargs() {
+ info("Starting test: Confirm with no args");
+ state = {
+ msg: "",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ try {
+ rv = confirm();
+ ok(true, "confirm() without arguments should not throw!");
+ } catch (e) {
+ ok(false, "confirm() without arguments should not throw!");
+ }
+ is(rv, true, "check prompt return value");
+
+ await promptDone;
+});
+
+
+add_task(async function test_prompt_ok() {
+ info("Starting test: Prompt");
+ state = {
+ msg: "This is the Prompt text.",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ rv = prompt("This is the Prompt text.");
+ is(rv, "", "check prompt return value");
+
+ await promptDone;
+});
+
+// bug 861605 made the arguments to alert/confirm optional (prompt already was).
+add_task(async function test_prompt_noargs() {
+ info("Starting test: Prompt with no args");
+ state = {
+ msg: "",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ try {
+ rv = prompt();
+ ok(true, "prompt() without arguments should not throw!");
+ } catch (e) {
+ ok(false, "prompt() without arguments should not throw!");
+ }
+ is(rv, "", "check prompt return value");
+
+ await promptDone;
+});
+
+</script>
+
+</body>
+</html>
diff --git a/toolkit/components/prompts/test/test_modal_prompts.html b/toolkit/components/prompts/test/test_modal_prompts.html
new file mode 100644
index 0000000000..df3438dbba
--- /dev/null
+++ b/toolkit/components/prompts/test/test_modal_prompts.html
@@ -0,0 +1,1311 @@
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Modal Prompts Test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+</head>
+<body>
+Prompter tests: modal prompts
+<p id="display"></p>
+
+<div id="content" style="display: none">
+ <iframe id="iframe"></iframe>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/* eslint-disable complexity */
+async function runTests(util) {
+ const { NetUtil } = SpecialPowers.ChromeUtils.import(
+ "resource://gre/modules/NetUtil.jsm"
+ );
+
+ // The ConfirmEx + delay test has slightly different behavior with the focus
+ // fixup rule vs. without.
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.focus.fixup", true]],
+ });
+
+ let state, action, promptDone;
+
+ let checkVal = {};
+ let textVal = {};
+ let passVal = {};
+ let flags;
+ let isOK;
+
+ // =====
+ info("Starting test: Alert");
+ state = {
+ msg: "This is the alert text.",
+ title: "TestTitle",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = ["TestTitle", "This is the alert text."];
+ await util.prompt("alert", promptArgs);
+
+ await promptDone;
+
+ // =====
+ info("Starting test: AlertCheck (null checkbox label, so it's hidden)");
+ state = {
+ msg: "This is the alertCheck text.",
+ title: "TestTitle",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = [
+ "TestTitle",
+ "This is the alertCheck text.",
+ null,
+ util.useAsync ? false : {},
+ ];
+ util.prompt("alertCheck", promptArgs);
+
+ await promptDone;
+
+ // =====
+ info("Starting test: AlertCheck");
+ state = {
+ msg: "This is the alertCheck text.",
+ title: "TestTitle",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the alertCheck text.",
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ let result = await util.prompt("alertCheck", promptArgs);
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "checkbox was checked"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Confirm (ok)");
+ state = {
+ msg: "This is the confirm text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = ["TestTitle", "This is the confirm text."];
+ result = await util.prompt("confirm", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Confirm (cancel)");
+ state = {
+ msg: "This is the confirm text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = ["TestTitle", "This is the confirm text."];
+ result = await util.prompt("confirm", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmCheck (ok, null checkbox label)");
+ state = {
+ msg: "This is the confirmCheck text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmCheck text.",
+ null,
+ util.useAsync ? false : {},
+ ];
+ result = await util.prompt("confirmCheck", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmCheck (cancel, null checkbox label)");
+ state = {
+ msg: "This is the confirmCheck text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmCheck text.",
+ null,
+ util.useAsync ? false : {},
+ ];
+ result = await util.prompt("confirmCheck", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmCheck (ok)");
+ state = {
+ msg: "This is the confirmCheck text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmCheck text.",
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("confirmCheck", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmCheck (cancel)");
+ state = {
+ msg: "This is the confirmCheck text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmCheck text.",
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("confirmCheck", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Prompt (ok, no default text)");
+ state = {
+ msg: "This is the prompt text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ textField: "bacon",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "";
+ promptArgs = ["TestTitle", "This is the prompt text.", util.useAsync ? textVal.value : textVal , null, util.useAsync ? false : {}];
+ result = await util.prompt("prompt", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(
+ util.useAsync ? result.value : textVal.value,
+ "bacon",
+ "checking expected text value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Prompt (ok, default text)");
+ state = {
+ msg: "This is the prompt text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "kittens",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "kittens";
+ promptArgs = ["TestTitle", "This is the prompt text.", util.useAsync ? textVal.value : textVal, null, util.useAsync ? false : {}];
+ result = await util.prompt("prompt", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(
+ util.useAsync ? result.value : textVal.value,
+ "kittens",
+ "checking expected text value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Prompt (cancel, default text)");
+ state = {
+ msg: "This is the prompt text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "puppies",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "puppies";
+ promptArgs = ["TestTitle", "This is the prompt text.", util.useAsync ? textVal.value : textVal, null, util.useAsync ? false : {}];
+ result = await util.prompt("prompt", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ is(
+ util.useAsync ? result.value : textVal.value,
+ "puppies",
+ "checking expected text value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Prompt (cancel, default text modified)");
+ state = {
+ msg: "This is the prompt text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "puppies",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ textField: "bacon",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "puppies";
+ promptArgs = ["TestTitle", "This is the prompt text.", util.useAsync ? textVal.value : textVal, null, util.useAsync ? false : {}];
+ result = await util.prompt("prompt", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ is(
+ util.useAsync ? result.value : textVal.value,
+ "puppies",
+ "checking expected text value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Prompt (ok, with checkbox)");
+ state = {
+ msg: "This is the prompt text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "tribbles",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "tribbles";
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the prompt text.",
+ util.useAsync ? textVal.value : textVal,
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("prompt", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(
+ util.useAsync ? result.value : textVal.value,
+ "tribbles",
+ "checking expected text value"
+ );
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: Prompt (cancel, with checkbox)");
+ state = {
+ msg: "This is the prompt text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "tribbles",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ setCheckbox: true,
+ };
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "tribbles";
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the prompt text.",
+ util.useAsync ? textVal.value : textVal,
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("prompt", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ is(
+ util.useAsync ? result.value : textVal.value,
+ "tribbles",
+ "checking expected text value"
+ );
+ ok(
+ util.useAsync ? result.checked : !checkVal.value,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ // Just two tests for this, since password manager already tests this extensively.
+ info("Starting test: PromptUsernameAndPassword (ok)");
+ state = {
+ msg: "This is the pUAP text.",
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "usr",
+ passValue: "ssh",
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ textField: "newusr",
+ passField: "newssh",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "usr";
+ passVal.value = "ssh";
+ promptArgs = [
+ "TestTitle",
+ "This is the pUAP text.",
+ util.useAsync ? textVal.value : textVal,
+ util.useAsync ? passVal.value : passVal
+ ];
+ result = await util.prompt("promptUsernameAndPassword", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(
+ util.useAsync ? result.user : textVal.value,
+ "newusr",
+ "checking expected text value"
+ );
+ is(
+ util.useAsync ? result.pass : passVal.value,
+ "newssh",
+ "checking expected pass value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: PromptUsernameAndPassword (cancel)");
+ state = {
+ msg: "This is the pUAP text.",
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "usr",
+ passValue: "ssh",
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ textField: "newusr",
+ passField: "newssh",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ textVal.value = "usr";
+ passVal.value = "ssh";
+ promptArgs = [
+ "TestTitle",
+ "This is the pUAP text.",
+ util.useAsync ? textVal.value : textVal,
+ util.useAsync ? passVal.value : passVal
+ ];
+ result = await util.prompt("promptUsernameAndPassword", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ ok(
+ (util.useAsync && result.user == "newusr") || textVal.value == "usr",
+ "checking expected text value"
+ );
+ ok(
+ (util.useAsync && result.pass == "newpass") || passVal.value == "ssh",
+ "checking expected pass value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: PromptPassword (ok)");
+ state = {
+ msg: "This is the promptPassword text.",
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "",
+ passValue: "ssh",
+ focused: "passField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ passField: "newssh",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ passVal.value = "ssh";
+ promptArgs = [
+ "TestTitle",
+ "This is the promptPassword text.",
+ util.useAsync ? passVal.value : passVal
+ ];
+ result = await util.prompt("promptPassword", promptArgs);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(
+ util.useAsync ? result.pass : passVal.value,
+ "newssh",
+ "checking expected pass value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: PromptPassword (cancel)");
+ state = {
+ msg: "This is the promptPassword text.",
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "",
+ passValue: "ssh",
+ focused: "passField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "cancel",
+ passField: "newssh",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ passVal.value = "ssh";
+ promptArgs = [
+ "TestTitle",
+ "This is the promptPassword text.",
+ util.useAsync ? passVal.value : passVal
+ ];
+ result = await util.prompt("promptPassword", promptArgs);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ ok(
+ (util.useAsync && result.pass == "newssh") || passVal.value == "ssh",
+ "checking expected pass value"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmEx (ok/cancel, ok)");
+ state = {
+ msg: "This is the confirmEx text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ butt0Label: "OK",
+ butt1Label: "Cancel",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ flags = Ci.nsIPromptService.STD_OK_CANCEL_BUTTONS;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmEx text.",
+ flags,
+ null,
+ null,
+ null,
+ null,
+ util.useAsync ? false : {},
+ ];
+ result = await util.prompt("confirmEx", promptArgs);
+ is(
+ util.useAsync ? result.buttonNumClicked : result,
+ 0,
+ "checked expected button num click"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmEx (yes/no, cancel)");
+ state = {
+ msg: "This is the confirmEx text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ butt0Label: "Yes",
+ butt1Label: "No",
+ };
+ action = {
+ buttonClick: "cancel",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ flags = Ci.nsIPromptService.STD_YES_NO_BUTTONS;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmEx text.",
+ flags,
+ null,
+ null,
+ null,
+ null,
+ util.useAsync ? false : {},
+ ];
+ result = await util.prompt("confirmEx", promptArgs);
+ is(
+ util.useAsync ? result.buttonNumClicked : result,
+ 1,
+ "checked expected button num click"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmEx (buttons from args, checkbox, ok)");
+ state = {
+ msg: "This is the confirmEx text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ butt0Label: "butt0",
+ butt1Label: "butt1",
+ butt2Label: "butt2",
+ };
+ action = {
+ buttonClick: "ok",
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ let b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING;
+ flags =
+ b * Ci.nsIPromptService.BUTTON_POS_2 +
+ b * Ci.nsIPromptService.BUTTON_POS_1 +
+ b * Ci.nsIPromptService.BUTTON_POS_0;
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmEx text.",
+ flags,
+ "butt0",
+ "butt1",
+ "butt2",
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("confirmEx", promptArgs);
+ is(
+ util.useAsync ? result.buttonNumClicked : result,
+ 0,
+ "checked expected button num click"
+ );
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmEx (buttons from args, checkbox, cancel)");
+ state = {
+ msg: "This is the confirmEx text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "button1", // Default changed!
+ defButton: "button1",
+ butt0Label: "butt0",
+ butt1Label: "butt1",
+ butt2Label: "butt2",
+ };
+ action = {
+ buttonClick: "cancel",
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING;
+ flags =
+ b * Ci.nsIPromptService.BUTTON_POS_2 +
+ b * Ci.nsIPromptService.BUTTON_POS_1 +
+ b * Ci.nsIPromptService.BUTTON_POS_0;
+ flags ^= Ci.nsIPromptService.BUTTON_POS_1_DEFAULT;
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmEx text.",
+ flags,
+ "butt0",
+ "butt1",
+ "butt2",
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("confirmEx", promptArgs);
+ is(
+ util.useAsync ? result.buttonNumClicked : result,
+ 1,
+ "checked expected button num click"
+ );
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ info("Starting test: ConfirmEx (buttons from args, checkbox, button3)");
+ state = {
+ msg: "This is the confirmEx text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: false,
+ textValue: "",
+ passValue: "",
+ checkMsg: "Check me out!",
+ checked: false,
+ focused: "button2", // Default changed!
+ defButton: "button2",
+ butt0Label: "butt0",
+ butt1Label: "butt1",
+ butt2Label: "butt2",
+ };
+ action = {
+ buttonClick: 2,
+ setCheckbox: true,
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING;
+ flags =
+ b * Ci.nsIPromptService.BUTTON_POS_2 +
+ b * Ci.nsIPromptService.BUTTON_POS_1 +
+ b * Ci.nsIPromptService.BUTTON_POS_0;
+ flags ^= Ci.nsIPromptService.BUTTON_POS_2_DEFAULT;
+ checkVal.value = false;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmEx text.",
+ flags,
+ "butt0",
+ "butt1",
+ "butt2",
+ "Check me out!",
+ util.useAsync ? checkVal.value : checkVal,
+ ];
+ result = await util.prompt("confirmEx", promptArgs);
+ is(
+ util.useAsync ? result.buttonNumClicked : result,
+ 2,
+ "checked expected button num click"
+ );
+ is(
+ util.useAsync ? result.checked : checkVal.value,
+ true,
+ "expected checkbox setting"
+ );
+
+ await promptDone;
+
+ // =====
+ // (skipped for E10S and tabmodal tests: window is required)
+ info("Starting test: Alert, no window");
+ state = {
+ msg: "This is the alert text.",
+ title: "TestTitle",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+ if (util.modalType === Ci.nsIPrompt.MODAL_TYPE_WINDOW && !isE10S) {
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = ["TestTitle", "This is the alert text."];
+ await util.prompt("alert", promptArgs);
+
+ await promptDone;
+ }
+
+ // =====
+ // (skipped for tabmodal tests: delay not supported)
+ info("Starting test: ConfirmEx (delay, ok)");
+ state = {
+ msg: "This is the confirmEx delay text.",
+ title: "TestTitle",
+ iconClass: "question-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: null, // Nothing focused until the delay triggers.
+ defButton: "button0",
+ butt0Label: "OK",
+ butt1Label: "Cancel",
+ butt0Disabled: true,
+ };
+
+ if (isOSX) {
+ // OS X doesn't initially focus the button, but rather the infoBody.
+ // The focus stays there even after the button-enable delay has fired.
+ state.focused = "infoBody";
+ }
+
+ action = {
+ buttonClick: "pollOK",
+ };
+ if (util.modalType === Ci.nsIPrompt.MODAL_TYPE_WINDOW) {
+ promptDone = handlePrompt(state, action);
+
+ flags =
+ Ci.nsIPromptService.STD_OK_CANCEL_BUTTONS |
+ Ci.nsIPromptService.BUTTON_DELAY_ENABLE;
+ promptArgs = [
+ "TestTitle",
+ "This is the confirmEx delay text.",
+ flags,
+ null,
+ null,
+ null,
+ null,
+ util.useAsync ? false : {},
+ ];
+ result = await util.prompt("confirmEx", promptArgs);
+ is(
+ util.useAsync ? result.buttonNumClicked : result,
+ 0,
+ "checked expected button num click"
+ );
+
+ await promptDone;
+ }
+
+ // promptAuth already tested via password manager but do a few specific things here.
+ var channel = NetUtil.newChannel({
+ uri: "http://example.com",
+ loadUsingSystemPrincipal: true,
+ });
+
+ var level = Ci.nsIAuthPrompt2.LEVEL_NONE;
+ var authinfo = {
+ username: "",
+ password: "",
+ domain: "",
+ flags: Ci.nsIAuthInformation.AUTH_HOST,
+ authenticationScheme: "basic",
+ realm: "",
+ };
+
+ let msg =
+ util.modalType == Ci.nsIPrompt.MODAL_TYPE_TAB
+ ? "This site is asking you to sign in."
+ : "http://example.com is requesting your username and password.";
+ // =====
+ // (promptAuth is only accessible from the prompt service)
+ info("Starting test: promptAuth with empty realm");
+ state = {
+ msg,
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "",
+ passValue: "",
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ textField: "username",
+ passField: "password",
+ };
+ if (util.usePromptService && !util.useAsync) {
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = [channel, level, authinfo];
+ isOK = await util.prompt("promptAuth", promptArgs);
+ is(isOK, true, "checked expected retval");
+ is(authinfo.username, "username", "checking filled username");
+ is(authinfo.password, "password", "checking filled password");
+
+ await promptDone;
+ }
+
+ // =====
+ // (promptAuth is only accessible from the prompt service)
+ msg =
+ util.modalType == Ci.nsIPrompt.MODAL_TYPE_TAB
+ ? "This site is asking you to sign in."
+ : "http://example.com is requesting your username and password. The site " +
+ "says: \u201cabcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi " +
+ "abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi " +
+ "abcdefghi \u2026\u201d";
+
+ info("Starting test: promptAuth with long realm");
+ state = {
+ msg,
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "",
+ passValue: "",
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ textField: "username",
+ passField: "password",
+ };
+ if (util.usePromptService && !util.useAsync) {
+ promptDone = handlePrompt(state, action);
+
+ var longString = "";
+ for (var i = 0; i < 20; i++) longString += "abcdefghi "; // 200 chars long
+ authinfo.realm = longString;
+ authinfo.username = "";
+ authinfo.password = "";
+ promptArgs = [channel, level, authinfo];
+ isOK = await util.prompt("promptAuth", promptArgs);
+ is(isOK, true, "checked expected retval");
+ is(authinfo.username, "username", "checking filled username");
+ is(authinfo.password, "password", "checking filled password");
+
+ await promptDone;
+ }
+
+ msg =
+ util.modalType == Ci.nsIPrompt.MODAL_TYPE_TAB
+ ? ("This site is asking you to sign in. Warning: Your login information " +
+ "will be shared with example.com, not the website you are currently visiting.")
+ : ("http://example.com is requesting your username and password. " +
+ "WARNING: Your password will not be sent to the website you are currently visiting!");
+ info("Starting test: promptAuth for a cross-origin and a empty realm");
+ authinfo = {
+ username: "",
+ password: "",
+ domain: "",
+ flags:
+ Ci.nsIAuthInformation.AUTH_HOST |
+ Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE,
+ authenticationScheme: "basic",
+ realm: "",
+ };
+ state = {
+ msg,
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "",
+ passValue: "",
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ textField: "username",
+ passField: "password",
+ };
+ if (util.usePromptService && !util.useAsync) {
+ promptDone = handlePrompt(state, action);
+ promptArgs = [channel, level, authinfo];
+ isOK = await util.prompt("promptAuth", promptArgs);
+ is(isOK, true, "checked expected retval");
+ is(authinfo.username, "username", "checking filled username");
+ is(authinfo.password, "password", "checking filled password");
+
+ await promptDone;
+ }
+
+ info("Starting test: promptAuth for a cross-origin with realm");
+ authinfo = {
+ username: "",
+ password: "",
+ domain: "",
+ flags:
+ Ci.nsIAuthInformation.AUTH_HOST |
+ Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE,
+ authenticationScheme: "basic",
+ realm: "Something!!!",
+ };
+ state = {
+ msg, // Same as previous test, see above.
+ title: "TestTitle",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ textValue: "",
+ passValue: "",
+ focused: "textField",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ textField: "username",
+ passField: "password",
+ };
+ if (util.usePromptService && !util.useAsync) {
+ promptDone = handlePrompt(state, action);
+
+ promptArgs = [channel, level, authinfo];
+ isOK = await util.prompt("promptAuth", promptArgs);
+ is(isOK, true, "checked expected retval");
+ is(authinfo.username, "username", "checking filled username");
+ is(authinfo.password, "password", "checking filled password");
+
+ await promptDone;
+ }
+}
+
+let promptArgs;
+
+add_task(async function runPromptTests() {
+ await runPromptCombinations(window, runTests);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/toolkit/components/prompts/test/test_modal_select.html b/toolkit/components/prompts/test/test_modal_select.html
new file mode 100644
index 0000000000..27688cf329
--- /dev/null
+++ b/toolkit/components/prompts/test/test_modal_select.html
@@ -0,0 +1,138 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Modal Prompts Test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+</head>
+<body>
+Prompter tests: modal prompts
+<p id="display"></p>
+
+<div id="content" style="display: none">
+ <iframe id="iframe"></iframe>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function checkPromptState(promptState, expectedState) {
+ // XXX check title? OS X has title in content
+ // XXX check focused element
+ // XXX check button labels?
+
+ is(promptState.msg, expectedState.msg, "Checking expected message");
+
+ // Compare listbox contents
+ is(promptState.items.length, expectedState.items.length, "Checking listbox length");
+
+ if (promptState.items.length)
+ is(promptState.selectedIndex, 0, "Checking selected index");
+
+ for (let i = 0; i < promptState.items; i++) {
+ is(promptState.items[i], expectedState.items[i], "Checking list item #" + i);
+ }
+}
+
+let selectVal = {};
+let isOK;
+
+function handlePrompt(state, action) {
+ return new Promise(resolve => {
+ gChromeScript.addMessageListener("promptHandled", function handled(msg) {
+ gChromeScript.removeMessageListener("promptHandled", handled);
+ checkPromptState(msg.promptState, state);
+ resolve(true);
+ });
+ gChromeScript.sendAsyncMessage("handlePrompt", { action, isSelect: true});
+ });
+}
+
+async function runTests(util) {
+ // Select prompt does not support tab or content prompts yet. See Bug 1622817.
+ if(util.modalType != Ci.nsIPrompt.MODAL_TYPE_WINDOW) {
+ info('Skipping modal type for select prompt...');
+ return;
+ }
+
+ // Empty list
+ info("Starting test: Select (0 items, ok)");
+ let state = {
+ msg: "This is the select text.",
+ title: "TestTitle",
+ items: [],
+ };
+ let action = {
+ buttonClick: "ok",
+ };
+ let promptDone = handlePrompt(state, action);
+ let items = [];
+ selectVal.value = null; // outparam, just making sure.
+ let result = await util.prompt("select", ["TestTitle", "This is the select text.", items, util.useAsync ? false : selectVal]);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(util.useAsync ? result.selected : selectVal.value, -1, "checking selected index");
+ await promptDone;
+
+ // ok
+ info("Starting test: Select (3 items, ok)");
+ state = {
+ msg: "This is the select text.",
+ title: "TestTitle",
+ items: ["one", "two", "three"],
+ };
+ action = {
+ buttonClick: "ok",
+ };
+ promptDone = handlePrompt(state, action);
+ items = ["one", "two", "three"];
+ selectVal.value = null; // outparam, just making sure.
+ result = await util.prompt("select", ["TestTitle", "This is the select text.", items, util.useAsync ? false : selectVal]);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(util.useAsync ? result.selected : selectVal.value, 0, "checking selected index");
+ await promptDone;
+
+ // select item
+ info("Starting test: Select (3 items, selection changed, ok)");
+ state = {
+ msg: "This is the select text.",
+ title: "TestTitle",
+ items: ["one", "two", "three"],
+ };
+ action = {
+ buttonClick: "ok",
+ selectItem: 1,
+ };
+ promptDone = handlePrompt(state, action);
+ items = ["one", "two", "three"];
+ selectVal.value = null; // outparam, just making sure.
+ result = await util.prompt("select", ["TestTitle", "This is the select text.", items, util.useAsync ? false : selectVal]);
+ is(util.useAsync ? result.ok : result, true, "checked expected retval");
+ is(util.useAsync ? result.selected : selectVal.value, 1, "checking selected index");
+ await promptDone;
+
+ // cancel prompt
+ info("Starting test: Select (3 items, cancel)");
+ state = {
+ msg: "This is the select text.",
+ title: "TestTitle",
+ items: ["one", "two", "three"],
+ };
+ action = {
+ buttonClick: "cancel",
+ };
+ promptDone = handlePrompt(state, action);
+ items = ["one", "two", "three"];
+ selectVal.value = null; // outparam, just making sure.
+ result = await util.prompt("select", ["TestTitle", "This is the select text.", items, util.useAsync ? false : selectVal]);
+ is(util.useAsync ? result.ok : result, false, "checked expected retval");
+ ok(util.useAsync && result.selected == -1 || selectVal.value == 0, "checking selected index");
+ await promptDone;
+}
+
+add_task(async function runPromptTests() {
+ await runPromptCombinations(window, runTests);
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/toolkit/components/prompts/test/test_subresources_prompts.html b/toolkit/components/prompts/test/test_subresources_prompts.html
new file mode 100644
index 0000000000..b71ad0694e
--- /dev/null
+++ b/toolkit/components/prompts/test/test_subresources_prompts.html
@@ -0,0 +1,200 @@
+<html>
+<head>
+ <title>Test subresources prompts (Bug 625187 and bug 1230462)</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -
+ - Contributor(s):
+ - Mihai Sucan <mihai.sucan@gmail.com>
+ -->
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=625187">Mozilla Bug 625187</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230462">Mozilla Bug 1230462</a>
+
+<p><button id="topbutton" onclick="alert('hello world')">Button</button></p>
+
+<iframe id="iframe_diff_origin" src="http://example.com/tests/toolkit/components/prompts/test/bug625187_iframe.html"></iframe>
+
+<iframe id="iframe_same_origin" src="bug625187_iframe.html"></iframe>
+
+<iframe id="iframe_prompt"></iframe>
+
+<pre id="test"></pre>
+
+<script class="testbody" type="text/javascript">
+var iframe1Loaded = onloadPromiseFor("iframe_diff_origin");
+var iframe2Loaded = onloadPromiseFor("iframe_same_origin");
+var iframe_prompt = document.getElementById("iframe_prompt");
+
+// Depending on pref state we either show auth prompts as windows or on tab level.
+let authPromptModalType = SpecialPowers.Services.prefs.getIntPref(
+ "prompts.modalType.httpAuth"
+);
+
+add_task(async function runTest() {
+ modalType = Ci.nsIPrompt.MODAL_TYPE_CONTENT;
+
+ info("Ensuring iframe1 has loaded...");
+ await iframe1Loaded;
+ info("Ensuring iframe2 has loaded...");
+ await iframe2Loaded;
+ let state, action;
+
+ state = {
+ msg: "hello world",
+ iconClass: "alert-icon",
+ titleHidden: true,
+ textHidden: true,
+ passHidden: true,
+ checkHidden: true,
+ textValue: "",
+ passValue: "",
+ checkMsg: "",
+ checked: false,
+ focused: "button0",
+ defButton: "button0",
+ };
+ action = {
+ buttonClick: "ok",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ await SpecialPowers.spawn(window, ["topbutton", "click"], dispatchMouseEvent);
+
+ await promptDone;
+
+ // mostly reusing same state/action
+ state.titleHidden = false;
+ state.msg = "hello world 2";
+ promptDone = handlePrompt(state, action);
+
+ var iframe = document.getElementById("iframe_diff_origin");
+ await SpecialPowers.spawn(iframe.contentWindow, ["btn1", "click"], dispatchMouseEvent);
+
+ await promptDone;
+
+ // mostly reusing same state/action
+ state.titleHidden = true;
+ state.msg = "hello world 2";
+ promptDone = handlePrompt(state, action);
+
+ iframe = document.getElementById("iframe_same_origin");
+ await SpecialPowers.spawn(iframe.contentWindow, ["btn1", "click"], dispatchMouseEvent);
+
+ await promptDone;
+
+ // mostly reusing same state/action
+ state.msg = "hello world 3";
+ promptDone = handlePrompt(state, action);
+ await SpecialPowers.spawn(iframe.contentWindow, ["btn2", "click"], dispatchMouseEvent);
+
+ await promptDone;
+});
+
+add_task(async function runTestAuth() {
+ // Following tests check prompt message for a cross-origin and not
+ // cross-origin subresources load
+
+ // Let prompt_common know what kind of modal type is enabled for auth prompts.
+ modalType = authPromptModalType;
+
+ let state, action;
+
+ state = {
+ msg: "This site is asking you to sign in.",
+ title: "Authentication Required",
+ textValue: "",
+ passValue: "",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+
+ action = {
+ buttonClick: "ok",
+ setCheckbox: false,
+ textField: "mochiuser1",
+ passField: "mochipass1",
+ };
+
+ let promptDone = handlePrompt(state, action);
+
+ var iframe3Loaded = onloadPromiseFor("iframe_prompt");
+ iframe_prompt.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
+ await promptDone;
+ await iframe3Loaded;
+ await checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"},
+ iframe_prompt);
+
+ // Cross-origin subresourse test.
+ state = {
+ msg: "This site is asking you to sign in. Warning: Your login information " +
+ "will be shared with example.com, not the website you are currently visiting.",
+ title: "Authentication Required",
+ textValue: "",
+ passValue: "",
+ iconClass: "authentication-icon question-icon",
+ titleHidden: true,
+ textHidden: false,
+ passHidden: false,
+ checkHidden: true,
+ checkMsg: "",
+ checked: false,
+ focused: "textField",
+ defButton: "button0",
+ };
+
+ action = {
+ buttonClick: "ok",
+ setCheckbox: false,
+ textField: "mochiuser2",
+ passField: "mochipass2",
+ };
+
+ promptDone = handlePrompt(state, action);
+
+ iframe3Loaded = onloadPromiseFor("iframe_prompt");
+ iframe_prompt.src = "http://example.com/tests/toolkit/components/prompts/test/authenticate.sjs?user=mochiuser2&pass=mochipass2&realm=mochitest";
+ await promptDone;
+ await iframe3Loaded;
+ await checkEchoedAuthInfo({user: "mochiuser2", pass: "mochipass2"},
+ iframe_prompt);
+});
+
+/**
+ * Function to be passed to SpecialPowers.spawn that dispatches a MouseEvent
+ * of a certain type to some element in a subframe.
+ *
+ * @param {String} targetID The ID of the element that will have the event
+ * dispatched on.
+ * @param {String} type The type of MouseEvent.
+ * @returns Promise
+ * @resolves Once the event has been dispatched.
+ */
+async function dispatchMouseEvent(targetID, type) {
+ /* eslint-disable no-undef */
+ let document = content.document;
+ let element = document.getElementById(targetID);
+ let event = document.createEvent("MouseEvent");
+ event.initEvent(type, false, false, content, 0, 1, 1, 1, 1,
+ false, false, false, false, 0, null);
+ content.windowUtils.dispatchDOMEventViaPresShellForTesting(element, event);
+ /* eslint-enable no-undef */
+}
+</script>
+</body>
+</html>