Bug 1263784 - Fix test_modal_prompts.html and test_modal_select.html to run under E10S. r=adw draft
authorJustin Dolske <dolske@mozilla.com>
Fri, 15 Apr 2016 13:43:25 -0700
changeset 352166 244c8abd7e23d464f8f0cbe883dd41fecbd1d070
parent 352165 1d825baf000359c127707e0f1c77d1465f257788
child 518596 36195a9825f2bcab6b43fb063ea9ef53fbfdb6d8
push id15634
push userjdolske@mozilla.com
push dateFri, 15 Apr 2016 20:44:40 +0000
reviewersadw
bugs1263784
milestone48.0a1
Bug 1263784 - Fix test_modal_prompts.html and test_modal_select.html to run under E10S. r=adw Use chromeScript and message manager to fetch state of prompt and dismiss it. Enable tests in E10S. MozReview-Commit-ID: 5M9GYijlQPV
toolkit/components/prompts/test/chromeScript.js
toolkit/components/prompts/test/mochitest.ini
toolkit/components/prompts/test/test_modal_prompts.html
toolkit/components/prompts/test/test_modal_select.html
--- a/toolkit/components/prompts/test/chromeScript.js
+++ b/toolkit/components/prompts/test/chromeScript.js
@@ -1,21 +1,202 @@
+const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/Timer.jsm");
 
 // 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.isTabModal, msg.isSelect);
+});
+
+function handlePromptWhenItAppears(action, isTabModal, isSelect) {
+  let interval = setInterval(() => {
+    if (handlePrompt(action, isTabModal, isSelect)) {
+      clearInterval(interval);
+    }
+  }, 100);
+}
+
+function handlePrompt(action, isTabModal, isSelect) {
+  let ui;
+
+  if (isTabModal) {
+    let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
+    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;
+  } else {
+    let doc = getDialogDoc();
+    if (!doc) {
+      return false; // try again in a bit
+    }
+
+    if (isSelect)
+      ui = doc;
+    else
+      ui = doc.defaultView.Dialog.ui;
+
+  }
+
+  let promptState;
+  if (isSelect) {
+    promptState = getSelectState(ui);
+    dismissSelect(ui, action);
+  } else {
+    promptState = getPromptState(ui);
+    dismissPrompt(ui, action);
+  }
+  sendAsyncMessage("promptHandled", { promptState: 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.textHidden  = ui.loginContainer.hidden;
+  state.passHidden  = ui.password1Container.hidden;
+  state.checkHidden = ui.checkboxContainer.hidden;
+  state.checkMsg    = ui.checkbox.label;
+  state.checked     = ui.checkbox.checked;
+  // tab-modal prompts don't have an infoIcon
+  state.iconClass   = ui.infoIcon ? ui.infoIcon.className : null;
+  state.textValue   = ui.loginTextbox.getAttribute("value");
+  state.passValue   = ui.password1Textbox.getAttribute("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 fm = Cc["@mozilla.org/focus-manager;1"].
+           getService(Ci.nsIFocusManager);
+  let e = fm.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 (ui.loginTextbox.inputField.isSameNode(e)) {
+    state.focused = "textField";
+  } else if (ui.password1Textbox.inputField.isSameNode(e)) {
+    state.focused = "passField";
+  } else if (ui.infoBody.isSameNode(e)) {
+    state.focused = "infoBody";
+  } else {
+    state.focused = "ERROR: unexpected element focused: " + (e ? e.localName : "<null>");
+  }
+
+  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.setChecked(true);
+    ui.checkbox.doCommand();
+  }
+
+  if (action.textField) {
+    ui.loginTextbox.setAttribute("value", action.textField);
+  }
+
+  if (action.passField) {
+    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 "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;
+
+    default:
+      throw "dismissPrompt action listed unknown button.";
+  }
+}
+
+
 addMessageListener("cancelPrompt", message => {
   cancelPromptWhenItAppears();
 });
 
 function cancelPromptWhenItAppears() {
   let interval = setInterval(() => {
     if (cancelPrompt()) {
       clearInterval(interval);
@@ -37,8 +218,44 @@ function cancelPrompt() {
         hidden: prompts[0].ui.infoTitle.getAttribute("hidden") == "true",
       },
     },
   });
   EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" }, browserWin);
   return true;
 }
 
+
+function getDialogDoc() {
+  // Trudge through all the open windows, until we find the one
+  // that has either commonDialog.xul or selectDialog.xul loaded.
+  var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
+           getService(Ci.nsIWindowMediator);
+  //var enumerator = wm.getEnumerator("navigator:browser");
+  var enumerator = wm.getXULWindowEnumerator(null);
+
+  while (enumerator.hasMoreElements()) {
+    var win = enumerator.getNext();
+    var windowDocShell = win.QueryInterface(Ci.nsIXULWindow).docShell;
+
+    var containedDocShells = windowDocShell.getDocShellEnumerator(
+                                      Ci.nsIDocShellTreeItem.typeChrome,
+                                      Ci.nsIDocShell.ENUMERATE_FORWARDS);
+    while (containedDocShells.hasMoreElements()) {
+        // Get the corresponding document for this docshell
+        var childDocShell = containedDocShells.getNext();
+        // We don't want it if it's not done loading.
+        if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
+          continue;
+        var childDoc = childDocShell.QueryInterface(Ci.nsIDocShell)
+                                    .contentViewer
+                                    .DOMDocument;
+
+        //ok(true, "Got window: " + childDoc.location.href);
+        if (childDoc.location.href == "chrome://global/content/commonDialog.xul")
+          return childDoc;
+        if (childDoc.location.href == "chrome://global/content/selectDialog.xul")
+          return childDoc;
+    }
+  }
+
+  return null;
+}
--- a/toolkit/components/prompts/test/mochitest.ini
+++ b/toolkit/components/prompts/test/mochitest.ini
@@ -7,11 +7,11 @@ support-files =
   chromeScript.js
 
 [test_bug619644.html]
 [test_bug620145.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_bug625187.html]
 [test_bug861605.html]
 [test_modal_prompts.html]
-skip-if = toolkit == 'android' || (os == 'linux' && (debug || asan)) || e10s #android: TIMED_OUT (For Linux : 950636)
+skip-if = toolkit == 'android' || (os == 'linux' && (debug || asan)) #android: TIMED_OUT (For Linux : 950636)
 [test_modal_select.html]
-skip-if = toolkit == 'android' || e10s #android: TIMED_OUT
+skip-if = toolkit == 'android' #android: TIMED_OUT
--- a/toolkit/components/prompts/test/test_modal_prompts.html
+++ b/toolkit/components/prompts/test/test_modal_prompts.html
@@ -15,169 +15,74 @@ Prompter tests: modal prompts
   <iframe id="iframe"></iframe>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.8">
 
 var isOSX = ("nsILocalFileMac" in SpecialPowers.Ci);
 var isLinux = ("@mozilla.org/gnome-gconf-service;1" in SpecialPowers.Cc);
-
-function pollDialog(okButton) {
-    if (okButton.disabled)
-        return;
+var isE10S = SpecialPowers.Services.appinfo.processType == 2;
 
-    ok(true, "dialog button is enabled now");
-    pollTimer.cancel();
-    pollTimer = null;
-    okButton.click();
-    didDialog = true;
-}
-
-function checkExpectedState(ui, state, action) {
-
+function checkPromptState(promptState, expectedState) {
     // XXX check title? OS X has title in content
-    is(ui.infoBody.textContent,       state.msg,         "Checking expected message");
-    is(ui.loginContainer.hidden,      state.textHidden,  "Checking textbox visibility");
-    is(ui.password1Container.hidden,  state.passHidden,  "Checking passbox visibility");
-    is(ui.checkboxContainer.hidden,   state.checkHidden, "Checking checkbox visibility");
-    is(ui.checkbox.label,             state.checkMsg,    "Checking checkbox label");
-    is(ui.checkbox.checked,           state.checked,     "Checking checkbox checked");
+    is(promptState.msg,         expectedState.msg,         "Checking expected message");
+    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 (!isTabModal)
-      is(ui.infoIcon.className,       "spaced " + state.iconClass, "Checking expected icon CSS class");
-    is(ui.loginTextbox.getAttribute("value"),     state.textValue, "Checking textbox value");
-    is(ui.password1Textbox.getAttribute("value"), state.passValue, "Checking passbox value");
+      is(promptState.iconClass, "spaced " + expectedState.iconClass, "Checking expected icon CSS class");
+    is(promptState.textValue, expectedState.textValue, "Checking textbox value");
+    is(promptState.passValue, expectedState.passValue, "Checking passbox value");
 
-    if (state.butt0Label) {
-        is(ui.button0.label, state.butt0Label, "Checking accept-button label");
-    }
-    if (state.butt1Label) {
-        is(ui.button1.label, state.butt1Label, "Checking cancel-button label");
+    if (expectedState.butt0Label) {
+        is(promptState.butt0Label, expectedState.butt0Label, "Checking accept-button label");
     }
-    if (state.butt2Label) {
-        is(ui.button2.label, state.butt2Label, "Checking extra1-button label");
+    if (expectedState.butt1Label) {
+        is(promptState.butt1Label, expectedState.butt1Label, "Checking cancel-button label");
     }
-
-    function isDefaultButton(b) {
-        return (b.hasAttribute("default") &&
-                b.getAttribute("default") == "true");
+    if (expectedState.butt2Label) {
+        is(promptState.butt2Label, expectedState.butt2Label, "Checking extra1-button label");
     }
 
-    is(isDefaultButton(ui.button0), state.defButton == "button0", "checking button0 default");
-    is(isDefaultButton(ui.button1), state.defButton == "button1", "checking button1 default");
-    is(isDefaultButton(ui.button2), state.defButton == "button2", "checking button2 default");
-
-    let fm = Cc["@mozilla.org/focus-manager;1"].
-             getService(Ci.nsIFocusManager);
-    let e = fm.focusedElement;
-    ok(true, "focused element is a " + (e ? e.localName : "<null>"));
-    if (isLinux && !e) {
-        todo(false, "Focus seems missing on Linux");
-    } else if (isOSX && state.focused && state.focused.startsWith("button")) {
-        ok(SpecialPowers.compare(ui.infoBody, e), "buttons don't focus on OS X");
-    } else if (state.focused == null) {
-        is(e, null, "Not expecting a focused element");
-    } else {
-        let expectedElement;
-        switch (state.focused) {
-            case "button0":
-                expectedElement = ui.button0;
-                break;
-            case "button1":
-                expectedElement = ui.button1;
-                break;
-            case "button2":
-                expectedElement = ui.button2;
-                break;
-            case "textField":
-                expectedElement = ui.loginTextbox.inputField;
-                break;
-            case "passField":
-                expectedElement = ui.password1Textbox.inputField;
-                break;
-            case "infoBody":
-                expectedElement = ui.infoBody;
-                break;
-            default:
-                ok(false, "Test listed an unknown element as expecting to be focused!");
-                break;
-        }
-        ok(SpecialPowers.compare(expectedElement, e), "Checking focused element");
-    }
-
-
-    /* Actions */
-
-
-    if (action.setCheckbox) {
-        // Annoyingly, the prompt code is driven by oncommand.
-        ui.checkbox.setChecked(true);
-        ui.checkbox.doCommand();
+    // 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");
     }
 
-    if (action.textField) {
-        ui.loginTextbox.setAttribute("value", action.textField);
-    }
-
-    if (action.passField) {
-        ui.password1Textbox.setAttribute("value", action.passField);
-    }
-
-    if (action.buttonClick == "pollOk") {
-        is(ui.button0.disabled, true,  "Checking accept-button is disabled");
-        is(ui.button1.disabled, 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");
 
-    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 "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.
-            pollTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-            pollTimer.initWithCallback(SpecialPowers.wrapCallback(function() {
-              pollDialog(ui.button0);
-            }),
-                                   100, Ci.nsITimer.TYPE_REPEATING_SLACK);
-            break;
-        default:
-            ok(false, "checkExpectedState action listed unknown button.")
+    if (isLinux && (!promptState.focused || isE10S)) {
+        todo(false, "Focus seems missing or wrong on Linux"); // bug 1265077
+    } else if (isOSX && expectedState.focused && expectedState.focused.startsWith("button")) {
+        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 (action.buttonClick != "pollOK")
-        didDialog = true;
-}
-
-
-/*
- * handleDialog
- *
- * Invoked a short period of time after calling startCallbackTimer(), and
- * allows testing the actual prompt dialog while it's being displayed. Tests
- * should call startCallbackTimer() each time the auth dialog is expected (the
- * timer is a one-shot).
- */
-function handleDialog(ui, testNum) {
-    ok(true, "--- handleDialog for test " + testNum +
-             " --- (isTabModal=" + isTabModal + ", usePromptService=" + usePromptService + ")");
-    checkExpectedState(ui, state, action);
 }
 
 
 function* runTests() {
+
+    function handlePrompt() {
+      return new Promise(resolve => {
+        gChromeScript.addMessageListener("promptHandled", function handled(msg) {
+          gChromeScript.removeMessageListener("promptHandled", handled);
+          checkPromptState(msg.promptState, state);
+          resolve(true);
+        });
+        gChromeScript.sendAsyncMessage("handlePrompt", { action: action, isTabModal: isTabModal});
+      });
+    }
+
     let ioService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService);
     ok(true, "Running tests (isTabModal=" + isTabModal + ", usePromptService=" + usePromptService + ")");
 
     let prompter, promptArgs;
     if (usePromptService) {
         prompter = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                    getService(Ci.nsIPromptService2);
@@ -192,21 +97,18 @@ function* runTests() {
     }
 
     let checkVal  = {};
     let textVal   = {};
     let passVal   = {};
     let flags;
     let isOK, clickedButton;
 
-    testNum = 0;
-
-    // ===== test 1 =====
-    // Alert
-    testNum++;
+    // =====
+    info("Starting test: Alert");
     state = {
         msg   : "This is the alert text.",
         title : "TestTitle",
         iconClass   : "alert-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -214,29 +116,28 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     promptArgs = ["TestTitle", "This is the alert text."];
     if (usePromptService)
         promptArgs.unshift(window);
     prompter.alert.apply(null, promptArgs);
 
-    ok(didDialog, "handleDialog was invoked");
-
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 2 =====
-    // AlertCheck (null checkbox label, so it's hidden)
-    testNum++;
+    // =====
+    info("Starting test: AlertCheck (null checkbox label, so it's hidden)");
     state = {
         msg   : "This is the alertCheck text.",
         title : "TestTitle",
         iconClass   : "alert-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -244,28 +145,28 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     promptArgs = ["TestTitle", "This is the alertCheck text.", null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     prompter.alertCheck.apply(null, promptArgs);
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 3 =====
-    // AlertCheck
-    testNum++;
+    // =====
+    info("Starting test: AlertCheck");
     state = {
         msg   : "This is the alertCheck text.",
         title : "TestTitle",
         iconClass   : "alert-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : false,
         textValue   : "",
@@ -274,30 +175,30 @@ function* runTests() {
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the alertCheck text.", "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     prompter.alertCheck.apply(null, promptArgs);
-    ok(didDialog, "handleDialog was invoked");
     is(checkVal.value, true, "checkbox was checked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 4 =====
-    // Confirm (ok)
-    testNum++;
+    // =====
+    info("Starting test: Confirm (ok)");
     state = {
         msg   : "This is the confirm text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -305,29 +206,29 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     promptArgs = ["TestTitle", "This is the confirm text."];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.confirm.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 5 =====
-    // Confirm (cancel)
-    testNum++;
+    // =====
+    info("Starting test: Confirm (cancel)");
     state = {
         msg   : "This is the confirm text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -335,29 +236,29 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "cancel",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     promptArgs = ["TestTitle", "This is the confirm text."];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.confirm.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 6 =====
-    // ConfirmCheck (ok, null checkbox label)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmCheck (ok, null checkbox label)");
     state = {
         msg   : "This is the confirmCheck text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -365,29 +266,29 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     promptArgs = ["TestTitle", "This is the confirmCheck text.", null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.confirmCheck.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 7 =====
-    // ConfirmCheck (cancel, null checkbox label)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmCheck (cancel, null checkbox label)");
     state = {
         msg   : "This is the confirmCheck text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -395,29 +296,29 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "cancel",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     promptArgs = ["TestTitle", "This is the confirmCheck text.", null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.confirmCheck.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 8 =====
-    // ConfirmCheck (ok)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmCheck (ok)");
     state = {
         msg   : "This is the confirmCheck text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : false,
         textValue   : "",
@@ -426,31 +327,31 @@ function* runTests() {
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the confirmCheck text.", "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.confirmCheck.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 9 =====
-    // ConfirmCheck (cancel)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmCheck (cancel)");
     state = {
         msg   : "This is the confirmCheck text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : false,
         textValue   : "",
@@ -459,31 +360,31 @@ function* runTests() {
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "cancel",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the confirmCheck text.", "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.confirmCheck.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 10 =====
-    // Prompt (ok, no default text)
-    testNum++;
+    // =====
+    info("Starting test: Prompt (ok, no default text)");
     state = {
         msg   : "This is the prompt text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : false,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -492,31 +393,31 @@ function* runTests() {
         checked     : false,
         focused     : "textField",
         defButton   : "button0",
     };
     action = {
         buttonClick : "ok",
         textField   : "bacon",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value = "";
     promptArgs = ["TestTitle", "This is the prompt text.", textVal, null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.prompt.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
     is(textVal.value, "bacon", "checking expected text value");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 11 =====
-    // Prompt (ok, default text)
-    testNum++;
+    // =====
+    info("Starting test: Prompt (ok, default text)");
     state = {
         msg   : "This is the prompt text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : false,
         passHidden  : true,
         checkHidden : true,
         textValue   : "kittens",
@@ -524,31 +425,31 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "textField",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value = "kittens";
     promptArgs = ["TestTitle", "This is the prompt text.", textVal, null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.prompt.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
     is(textVal.value, "kittens", "checking expected text value");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 12 =====
-    // Prompt (cancel, default text)
-    testNum++;
+    // =====
+    info("Starting test: Prompt (cancel, default text)");
     state = {
         msg   : "This is the prompt text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : false,
         passHidden  : true,
         checkHidden : true,
         textValue   : "puppies",
@@ -556,31 +457,31 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "textField",
         defButton   : "button0",
     };
     action = {
         buttonClick: "cancel",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value = "puppies";
     promptArgs = ["TestTitle", "This is the prompt text.", textVal, null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.prompt.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
     is(textVal.value, "puppies", "checking expected text value");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 13 =====
-    // Prompt (cancel, default text modified)
-    testNum++;
+    // =====
+    info("Starting test: Prompt (cancel, default text modified)");
     state = {
         msg   : "This is the prompt text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : false,
         passHidden  : true,
         checkHidden : true,
         textValue   : "puppies",
@@ -589,31 +490,31 @@ function* runTests() {
         checked     : false,
         focused     : "textField",
         defButton   : "button0",
     };
     action = {
         buttonClick : "cancel",
         textField   : "bacon",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value = "puppies";
     promptArgs = ["TestTitle", "This is the prompt text.", textVal, null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.prompt.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
     is(textVal.value, "puppies", "checking expected text value");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 14 =====
-    // Prompt (ok, with checkbox)
-    testNum++;
+    // =====
+    info("Starting test: Prompt (ok, with checkbox)");
     state = {
         msg   : "This is the prompt text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : false,
         passHidden  : true,
         checkHidden : false,
         textValue   : "tribbles",
@@ -622,33 +523,33 @@ function* runTests() {
         checked     : false,
         focused     : "textField",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value  = "tribbles";
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the prompt text.", textVal, "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.prompt.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
     is(textVal.value, "tribbles", "checking expected text value");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 15 =====
-    // Prompt (cancel, with checkbox)
-    testNum++;
+    // =====
+    info("Starting test: Prompt (cancel, with checkbox)");
     state = {
         msg   : "This is the prompt text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : false,
         passHidden  : true,
         checkHidden : false,
         textValue   : "tribbles",
@@ -657,34 +558,34 @@ function* runTests() {
         checked     : false,
         focused     : "textField",
         defButton   : "button0",
     };
     action = {
         buttonClick: "cancel",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value  = "tribbles";
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the prompt text.", textVal, "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.prompt.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
     is(textVal.value, "tribbles", "checking expected text value");
     is(checkVal.value, false, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 16 =====
-    // PromptUsernameAndPassword (ok)
+    // =====
     // Just two tests for this, since password manager already tests this extensively.
-    testNum++;
+    info("Starting test: PromptUsernameAndPassword (ok)");
     state = {
         msg   : "This is the pUAP text.",
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         textHidden  : false,
         passHidden  : false,
         checkHidden : false,
         textValue   : "usr",
@@ -695,35 +596,35 @@ function* runTests() {
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
         setCheckbox: true,
         textField: "newusr",
         passField: "newssh",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value  = "usr";
     passVal.value  = "ssh";
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the pUAP text.", textVal, passVal, "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.promptUsernameAndPassword.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
     is(textVal.value, "newusr", "checking expected text value");
     is(passVal.value, "newssh", "checking expected pass value");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 17 =====
-    // PromptUsernameAndPassword (cancel)
-    testNum++;
+    // =====
+    info("Starting test: PromptUsernameAndPassword (cancel)");
     state = {
         msg   : "This is the pUAP text.",
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         textHidden  : false,
         passHidden  : false,
         checkHidden : false,
         textValue   : "usr",
@@ -734,35 +635,35 @@ function* runTests() {
         defButton   : "button0",
     };
     action = {
         buttonClick : "cancel",
         setCheckbox : true,
         textField   : "newusr",
         passField   : "newssh",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     textVal.value  = "usr";
     passVal.value  = "ssh";
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the pUAP text.", textVal, passVal, "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.promptUsernameAndPassword.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
     is(textVal.value, "usr", "checking expected text value");
     is(passVal.value, "ssh", "checking expected pass value");
     is(checkVal.value, false, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 18 =====
-    // PromptPassword (ok)
-    testNum++;
+    // =====
+    info("Starting test: PromptPassword (ok)");
     state = {
         msg   : "This is the promptPassword text.",
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         textHidden  : true,
         passHidden  : false,
         checkHidden : false,
         textValue   : "",
@@ -772,33 +673,33 @@ function* runTests() {
         focused     : "passField",
         defButton   : "button0",
     };
     action = {
         buttonClick : "ok",
         setCheckbox : true,
         passField   : "newssh",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     passVal.value  = "ssh";
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the promptPassword text.", passVal, "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.promptPassword.apply(null, promptArgs);
     is(isOK, true, "checked expected retval");
     is(passVal.value, "newssh", "checking expected pass value");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 19 =====
-    // PromptPassword (cancel)
-    testNum++;
+    // =====
+    info("Starting test: PromptPassword (cancel)");
     state = {
         msg   : "This is the promptPassword text.",
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         textHidden  : true,
         passHidden  : false,
         checkHidden : false,
         textValue   : "",
@@ -808,33 +709,33 @@ function* runTests() {
         focused     : "passField",
         defButton   : "button0",
     };
     action = {
         buttonClick : "cancel",
         setCheckbox : true,
         passField   : "newssh",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     passVal.value  = "ssh";
     checkVal.value = false;
     promptArgs = ["TestTitle", "This is the promptPassword text.", passVal, "Check me out!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     isOK = prompter.promptPassword.apply(null, promptArgs);
     is(isOK, false, "checked expected retval");
     is(passVal.value, "ssh", "checking expected pass value");
     is(checkVal.value, false, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 20 =====
-    // ConfirmEx (ok/cancel, ok)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmEx (ok/cancel, ok)");
     state = {
         msg   : "This is the confirmEx text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -844,30 +745,30 @@ function* runTests() {
         focused     : "button0",
         defButton   : "button0",
         butt0Label  : "OK",
         butt1Label  : "Cancel",
     };
     action = {
         buttonClick: "ok",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     flags = Ci.nsIPromptService.STD_OK_CANCEL_BUTTONS;
     promptArgs = ["TestTitle", "This is the confirmEx text.", flags, null, null, null, null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     clickedButton = prompter.confirmEx.apply(null, promptArgs);
     is(clickedButton, 0, "checked expected button num click");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 21 =====
-    // ConfirmEx (yes/no, cancel)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmEx (yes/no, cancel)");
     state = {
         msg   : "This is the confirmEx text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -877,30 +778,30 @@ function* runTests() {
         focused     : "button0",
         defButton   : "button0",
         butt0Label  : "Yes",
         butt1Label  : "No",
     };
     action = {
         buttonClick: "cancel",
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(action);
+
     flags = Ci.nsIPromptService.STD_YES_NO_BUTTONS;
     promptArgs = ["TestTitle", "This is the confirmEx text.", flags, null, null, null, null, {}];
     if (usePromptService)
         promptArgs.unshift(window);
     clickedButton = prompter.confirmEx.apply(null, promptArgs);
     is(clickedButton, 1, "checked expected button num click");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 22 =====
-    // ConfirmEx (buttons from args, checkbox, ok)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmEx (buttons from args, checkbox, ok)");
     state = {
         msg   : "This is the confirmEx text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : false,
         textValue   : "",
@@ -912,36 +813,36 @@ function* runTests() {
         butt0Label  : "butt0",
         butt1Label  : "butt1",
         butt2Label  : "butt2",
     };
     action = {
         buttonClick: "ok",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(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!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     clickedButton = prompter.confirmEx.apply(null, promptArgs);
     is(clickedButton, 0, "checked expected button num click");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 23 =====
-    // ConfirmEx (buttons from args, checkbox, cancel)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmEx (buttons from args, checkbox, cancel)");
     state = {
         msg   : "This is the confirmEx text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : false,
         textValue   : "",
@@ -953,37 +854,37 @@ function* runTests() {
         butt0Label  : "butt0",
         butt1Label  : "butt1",
         butt2Label  : "butt2",
     };
     action = {
         buttonClick: "cancel",
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(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!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     clickedButton = prompter.confirmEx.apply(null, promptArgs);
     is(clickedButton, 1, "checked expected button num click");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 24 =====
-    // ConfirmEx (buttons from args, checkbox, button3)
-    testNum++;
+    // =====
+    info("Starting test: ConfirmEx (buttons from args, checkbox, button3)");
     state = {
         msg   : "This is the confirmEx text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : false,
         textValue   : "",
@@ -995,38 +896,38 @@ function* runTests() {
         butt0Label  : "butt0",
         butt1Label  : "butt1",
         butt2Label  : "butt2",
     };
     action = {
         buttonClick: 2,
         setCheckbox: true,
     };
-    startCallbackTimer();
+
+    promptDone = handlePrompt(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!", checkVal];
     if (usePromptService)
         promptArgs.unshift(window);
     clickedButton = prompter.confirmEx.apply(null, promptArgs);
     is(clickedButton, 2, "checked expected button num click");
     is(checkVal.value, true, "expected checkbox setting");
-    ok(didDialog, "handleDialog was invoked");
 
-    yield Promise.resolve();
+    yield promptDone;
 
-    // ===== test 25  =====
-    // Alert, no window
-    // (skipped for tabmodal tests: window is required)
-    testNum++;
+    // =====
+    // (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",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
@@ -1034,65 +935,68 @@ function* runTests() {
         checkMsg    : "",
         checked     : false,
         focused     : "button0",
         defButton   : "button0",
     };
     action = {
         buttonClick: "ok",
     };
-    if (!isTabModal) {
-        startCallbackTimer();
-    promptArgs = ["TestTitle", "This is the alert text."];
-    if (usePromptService)
-        promptArgs.unshift(null);
+    if (!isTabModal && !isE10S) {
+        promptDone = handlePrompt(action);
+
+        promptArgs = ["TestTitle", "This is the alert text."];
+        if (usePromptService)
+          promptArgs.unshift(null);
         prompter.alert.apply(null, promptArgs);
-        ok(didDialog, "handleDialog was invoked");
+
+        yield promptDone;
     }
 
-    yield Promise.resolve();
 
-    // ===== test 26 =====
-    // ConfirmEx (delay, ok)
+    // =====
     // (skipped for tabmodal tests: delay not supported)
-    testNum++;
+    info("Starting test: ConfirmEx (delay, ok)");
     state = {
         msg   : "This is the confirmEx delay text.",
         title : "TestTitle",
         iconClass   : "question-icon",
         textHidden  : true,
         passHidden  : true,
         checkHidden : true,
         textValue   : "",
         passValue   : "",
         checkMsg    : "",
         checked     : false,
         focused     : null, // nothing focused until after delay fires
         defButton   : "button0",
         butt0Label  : "OK",
         butt1Label  : "Cancel",
+        butt0Disabled: true,
     };
 
     // OS X doesn't initially focus the button, but rather the infoBody.
     // The focus stays there even after the button-enable delay has fired.
     if (isOSX)
         state.focused = "infoBody";
 
     action = {
         buttonClick: "pollOK",
     };
     if (!isTabModal) {
-        startCallbackTimer();
+        promptDone = handlePrompt(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, {}];
         if (usePromptService)
             promptArgs.unshift(window);
         clickedButton = prompter.confirmEx.apply(null, promptArgs);
         is(clickedButton, 0, "checked expected button num click");
-        ok(didDialog, "handleDialog was invoked");
+
+        yield promptDone;
     }
 
     // promptAuth already tested via password manager but do a few specific things here.
 
 
     var channel = ioService.newChannel2("http://example.com",
                                         null,
                                         null,
@@ -1106,22 +1010,20 @@ function* runTests() {
         username : "",
         password : "",
         domain   : "",
         flags : Ci.nsIAuthInformation.AUTH_HOST,
         authenticationScheme : "basic",
         realm : ""
     };
 
-    yield Promise.resolve();
 
-    // ===== test 100 =====
-    // promptAuth with empty realm
+    // =====
     // (promptAuth is only accessible from the prompt service)
-    testNum = 100;
+    info("Starting test: promptAuth with empty realm");
     state = {
         msg : 'Enter username and password for http://example.com',
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         textHidden  : false,
         passHidden  : false,
         checkHidden : false,
         textValue   : "",
@@ -1133,32 +1035,32 @@ function* runTests() {
     };
     action = {
         buttonClick : "ok",
         setCheckbox : true,
         textField   : "username",
         passField   : "password",
     };
     if (usePromptService) {
-        startCallbackTimer();
+        promptDone = handlePrompt(action);
+
         checkVal.value = false;
         isOK = prompter.promptAuth(window, channel, level, authinfo, "Check me out!", checkVal);
         is(isOK, true, "checked expected retval");
         is(authinfo.username, "username", "checking filled username");
         is(authinfo.password, "password", "checking filled password");
         is(checkVal.value, true, "expected checkbox setting");
-        ok(didDialog, "handleDialog was invoked");
+
+        yield promptDone;
     }
 
-    yield Promise.resolve();
 
-    // ===== test 101 =====
-    // promptAuth with long realm
+    // =====
     // (promptAuth is only accessible from the prompt service)
-    testNum++;
+    info("Starting test: promptAuth with long realm");
     state = {
         msg : 'A username and password are being requested by http://example.com. The site '  +
               'says: "abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi ' +
               'abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi '        +
               'abcdefghi \u2026"',
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         textHidden  : false,
@@ -1173,54 +1075,64 @@ function* runTests() {
     };
     action = {
         buttonClick : "ok",
         setCheckbox : true,
         textField   : "username",
         passField   : "password",
     };
     if (usePromptService) {
-        startCallbackTimer();
+        promptDone = handlePrompt(action);
+
         checkVal.value = false;
         var longString = "";
         for (var i = 0; i < 20; i++)
             longString += "abcdefghi "; // 200 chars long
         authinfo.realm = longString;
         authinfo.username = "";
         authinfo.password = "";
         isOK = prompter.promptAuth(window, channel, level, authinfo, "Check me out!", checkVal);
         is(isOK, true, "checked expected retval");
         is(authinfo.username, "username", "checking filled username");
         is(authinfo.password, "password", "checking filled password");
         is(checkVal.value, true, "expected checkbox setting");
-        ok(didDialog, "handleDialog was invoked");
+
+        yield promptDone;
     }
 }
 
-let testNum;
-let pollTimer;
+let gChromeScript;
 let state, action;
 
 /*
  * Run the body of the 3 times:
  * - 1st pass: with window-modal prompts, using nsIPromptService
  * - 2nd pass: still window-modal, using nsIPrompt directly (via nsIPromptFactory)
  * - 3rd pass: with tab-modal prompts. Can't opt into these via * nsIPromptService.
  */
 
 add_task(function* runPromptTests() {
+  info("Process type: " + SpecialPowers.Services.appinfo.processType);
+
+  let url = SimpleTest.getTestFileURL("chromeScript.js");
+  gChromeScript = SpecialPowers.loadChromeScript(url);
 
   isTabModal = false; usePromptService = true;
+  info("Running tests with: isTabModal=" + isTabModal + ", usePromptService=" + usePromptService);
   yield* runTests();
 
   isTabModal = false; usePromptService = false;
+  info("Running tests with: isTabModal=" + isTabModal + ", usePromptService=" + usePromptService);
   yield* runTests();
 
-  if (getTabModalPromptBox(window)) {
+  if (SpecialPowers.getBoolPref("prompts.tab_modal.enabled")) {
       isTabModal = true; usePromptService = false;
+      info("Running tests with: isTabModal=" + isTabModal + ", usePromptService=" + usePromptService);
       yield* runTests();
   }
+
+  gChromeScript.destroy();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/prompts/test/test_modal_select.html
+++ b/toolkit/components/prompts/test/test_modal_select.html
@@ -1,13 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Modal Prompts Test</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
   <script type="text/javascript" src="prompt_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Prompter tests: modal prompts
 <p id="display"></p>
 
 <div id="content" style="display: none">
@@ -15,150 +16,138 @@ Prompter tests: modal prompts
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.8">
 
 let prompter = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                getService(Ci.nsIPromptService2);
 
-function checkExpectedSelectState(doc, state, action) {
-    let msg = doc.getElementById("info.txt").value;
-    // XXX check title? OS X has title in content
-    let dialog = doc.getElementsByTagName("dialog")[0];
-    let listbox = doc.getElementById("list");
-
-    is(msg, state.msg, "Checking expected message");
+function checkPromptState(promptState, expectedState) {
     // XXX check title? OS X has title in content
-    // Compare listbox contents
-    let count = listbox.itemCount;
-    is(count, state.items.length, "Checking listbox length");
-    if (count)
-        is(listbox.selectedIndex, 0, "Checking selected index");
-
-    for (let i = 0; i < count; i++) {
-        let item = listbox.getItemAtIndex(i).label;
-        is(item, items[i], "Checking item #" + i + " label");
-    }
-
     // XXX check focused element
     // XXX check button labels?
 
-    /* Actions */
+    is(promptState.msg, state.msg, "Checking expected message");
 
-    if (action.selectItem) {
-        listbox.selectedIndex = 1;
-    }
+    // Compare listbox contents
+    is(promptState.items.length, expectedState.items.length, "Checking listbox length");
 
-    if (action.buttonClick == "ok") {
-        dialog.acceptDialog();
-    } else if (action.buttonClick == "cancel") {
-        dialog.cancelDialog();
+    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);
     }
-
-    didDialog = true;
 }
 
-/*
- * handleDialog
- *
- * Invoked a short period of time after calling startCallbackTimer(), and
- * allows testing the actual prompt dialog while it's being displayed. Tests
- * should call startCallbackTimer() each time the auth dialog is expected (the
- * timer is a one-shot).
- */
-function handleDialog(doc, testNum) {
-    ok(true, "--- handleDialog for test " + testNum + " ---");
-
-    checkExpectedSelectState(doc, state, action);
-}
-
-let testNum   = 0;
 let selectVal = {};
 let isOK;
-let state, action;
+let gChromeScript, state, action;
 
-isSelectDialog = true;
-isTabModal = false;
-usePromptService = true;
+function handlePrompt() {
+  return new Promise(resolve => {
+    gChromeScript.addMessageListener("promptHandled", function handled(msg) {
+      gChromeScript.removeMessageListener("promptHandled", handled);
+      checkPromptState(msg.promptState, state);
+      resolve(true);
+    });
+    gChromeScript.sendAsyncMessage("handlePrompt", { action: action, isSelect: true});
+  });
+}
+
+let url = SimpleTest.getTestFileURL("chromeScript.js");
+gChromeScript = SpecialPowers.loadChromeScript(url);
 
-// ===== test 1 =====
-// Select (0 items, ok)
-testNum++;
-state = {
-    msg   : "This is the select text.",
-    title : "TestTitle",
-    items : [],
-};
-action = {
-    buttonClick: "ok",
-};
-startCallbackTimer();
-items = [];
-selectVal.value = null; // outparam, just making sure.
-isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
-is(isOK, true, "checked expected retval");
-is(selectVal.value, -1, "checking selected index");
-ok(didDialog, "handleDialog was invoked");
+// =====
+add_task(function* test_select_empty_list() {
+    info("Starting test: Select (0 items, ok)");
+    state = {
+        msg   : "This is the select text.",
+        title : "TestTitle",
+        items : [],
+    };
+    action = {
+        buttonClick: "ok",
+    };
+    promptDone = handlePrompt(action);
+    items = [];
+    selectVal.value = null; // outparam, just making sure.
+    isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
+    is(isOK, true, "checked expected retval");
+    is(selectVal.value, -1, "checking selected index");
+
+    yield promptDone;
+});
 
-// ===== test 2 =====
-// Select (3 items, ok)
-testNum++;
-state = {
-    msg   : "This is the select text.",
-    title : "TestTitle",
-    items : ["one", "two", "three"],
-};
-action = {
-    buttonClick: "ok",
-};
-startCallbackTimer();
-items = ["one", "two", "three"];
-selectVal.value = null; // outparam, just making sure.
-isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
-is(isOK, true, "checked expected retval");
-is(selectVal.value, 0, "checking selected index");
-ok(didDialog, "handleDialog was invoked");
+// =====
+add_task(function* test_select_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(action);
+    items = ["one", "two", "three"];
+    selectVal.value = null; // outparam, just making sure.
+    isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
+    is(isOK, true, "checked expected retval");
+    is(selectVal.value, 0, "checking selected index");
+
+    yield promptDone;
+});
 
-// ===== test 3 =====
-// Select (3 items, selection changed, ok)
-testNum++;
-state = {
-    msg   : "This is the select text.",
-    title : "TestTitle",
-    items : ["one", "two", "three"],
-};
-action = {
-    buttonClick: "ok",
-    selectItem: 1,
-};
-startCallbackTimer();
-items = ["one", "two", "three"];
-selectVal.value = null; // outparam, just making sure.
-isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
-is(isOK, true, "checked expected retval");
-is(selectVal.value, 1, "checking selected index");
-ok(didDialog, "handleDialog was invoked");
+// =====
+add_task(function* test_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(action);
+    items = ["one", "two", "three"];
+    selectVal.value = null; // outparam, just making sure.
+    isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
+    is(isOK, true, "checked expected retval");
+    is(selectVal.value, 1, "checking selected index");
+
+    yield promptDone;
+});
 
-// ===== test 4 =====
-// Select (3 items, cancel)
-testNum++;
-state = {
-    msg   : "This is the select text.",
-    title : "TestTitle",
-    items : ["one", "two", "three"],
-};
-action = {
-    buttonClick: "cancel",
-};
-startCallbackTimer();
-items = ["one", "two", "three"];
-selectVal.value = null; // outparam, just making sure.
-isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
-is(isOK, false, "checked expected retval");
-is(selectVal.value, 0, "checking selected index");
-ok(didDialog, "handleDialog was invoked");
+// =====
+add_task(function* test_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(action);
+    items = ["one", "two", "three"];
+    selectVal.value = null; // outparam, just making sure.
+    isOK = prompter.select(window, "TestTitle", "This is the select text.", items.length, items, selectVal);
+    is(isOK, false, "checked expected retval");
+    is(selectVal.value, 0, "checking selected index");
 
+    yield promptDone;
+});
+
+// =====
+add_task(function* cleanup() {
+    gChromeScript.destroy();
+});
 
 </script>
 </pre>
 </body>
 </html>