Bug 1267388 - Use test helpers from prompt tests. r?MattN draft
authorJustin Dolske <dolske@mozilla.com>
Mon, 25 Apr 2016 13:17:39 -0700
changeset 356155 fa001615f43f159fe8a3fa4f31d7e1689689527d
parent 356154 a736d1182afb54cd3d2ccc97163da09490ac344b
child 519352 4302dffc0a644effa0294a6531da9653fd58cb4d
push id16458
push userjdolske@mozilla.com
push dateMon, 25 Apr 2016 20:17:50 +0000
reviewersMattN
bugs1267388
milestone49.0a1
Bug 1267388 - Use test helpers from prompt tests. r?MattN MozReview-Commit-ID: 6qFoOYutLOt
toolkit/components/passwordmgr/test/mochitest/mochitest.ini
toolkit/components/passwordmgr/test/mochitest/prompt_common.js
toolkit/components/passwordmgr/test/mochitest/test_prompt.html
--- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
+++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
@@ -2,17 +2,18 @@
 skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 support-files =
   ../../../satchel/test/parent_utils.js
   ../../../satchel/test/satchel_common.js
   ../authenticate.sjs
   ../pwmgr_common.js
   ../notification_common.js
   auth2/authenticate.sjs
-  prompt_common.js
+  ../../../prompts/test/prompt_common.js
+  ../../../prompts/test/chromeScript.js
 
 [test_autofill_password-only.html]
 [test_basic_form.html]
 [test_basic_form_0pw.html]
 [test_basic_form_1pw.html]
 [test_basic_form_1pw_2.html]
 [test_basic_form_2pw_1.html]
 [test_basic_form_2pw_2.html]
deleted file mode 100644
--- a/toolkit/components/passwordmgr/test/mochitest/prompt_common.js
+++ /dev/null
@@ -1,188 +0,0 @@
-var Ci = SpecialPowers.Ci;
-ok(Ci != null, "Access Ci");
-var Cc = SpecialPowers.Cc;
-ok(Cc != null, "Access Cc");
-
-var didDialog;
-
-var timer; // keep in outer scope so it's not GC'd before firing
-function startCallbackTimer() {
-    didDialog = false;
-
-    // Delay before the callback twiddles the prompt.
-    const dialogDelay = 10;
-
-    // Use a timer to invoke a callback to twiddle the authentication dialog
-    timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    timer.init(observer, dialogDelay, Ci.nsITimer.TYPE_ONE_SHOT);
-}
-
-
-var observer = SpecialPowers.wrapCallbackObject({
-    QueryInterface : function (iid) {
-        const interfaces = [Ci.nsIObserver,
-                            Ci.nsISupports, Ci.nsISupportsWeakReference];
-
-        if (!interfaces.some( function(v) { return iid.equals(v) } ))
-            throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
-        return this;
-    },
-
-    observe : function (subject, topic, data) {
-        var doc = getDialogDoc();
-        if (doc)
-            handleDialog(doc, testNum);
-        else
-            startCallbackTimer(); // try again in a bit
-    }
-});
-
-function getDialogDoc() {
-  // Find the <browser> which contains notifyWindow, by looking
-  // through all the open windows and all the <browsers> in each.
-  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;
-    }
-  }
-
-  return null;
-}
-
-function getPromptState(ui) {
-  let state = {};
-  state.msg         = ui.infoBody.textContent;
-  state.titleHidden = ui.infoTitle.getAttribute("hidden") == "true";
-  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;
-}
-
-var isTabModal = false;
-var isOSX = ("nsILocalFileMac" in SpecialPowers.Ci);
-var isLinux = ("@mozilla.org/gnome-gconf-service;1" in SpecialPowers.Cc);
-var isE10S = SpecialPowers.Services.appinfo.processType == 2;
-
-function checkPromptState(promptState, expectedState) {
-    // XXX check title? OS X has title in content
-    is(promptState.msg,         expectedState.msg,         "Checking expected message");
-    if (isOSX && !isTabModal)
-      ok(!promptState.titleHidden, "Checking title always visible on OS X");
-    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 (!isTabModal)
-      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 (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 (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");
-    }
-}
-
-function onloadPromiseFor(id) {
-  var iframe = document.getElementById(id);
-  return new Promise(resolve => {
-    iframe.addEventListener("load", function onload(e) {
-      iframe.removeEventListener("load", onload);
-      resolve(true);
-    });
-  });
-}
--- a/toolkit/components/passwordmgr/test/mochitest/test_prompt.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt.html
@@ -22,20 +22,22 @@ Login Manager test: username/password pr
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: username / password prompts. **/
 var state, action;
 var pwmgr, ioService, observerService;
 var tmplogin, login1, login2A, login2B, login2C, login2D, login2E, login3A, login3B, login4, proxyLogin;
 var mozproxy, proxiedHost = "http://mochi.test:8888";
 var proxyChannel;
-var testNum = 1;
 var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal();
 var iframe = document.getElementById("iframe");
 
+// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
+isTabModal = false;
+
 function initLogins(pi) {
   observerService = Cc["@mozilla.org/observer-service;1"].
                       getService(Ci.nsIObserverService);
   observerService.addObserver(storageObserver, "passwordmgr-storage-changed", false);
 
   pwmgr = Cc["@mozilla.org/login-manager;1"].
           getService(Ci.nsILoginManager);
   ioService = Cc["@mozilla.org/network/io-service;1"].
@@ -251,52 +253,16 @@ var storageObserver = SpecialPowers.wrap
       if (this.notificationCallbacks.length)
         this.notificationCallbacks.splice(0, 1)[0]();
     } catch (e) {
       ok(false, "OBSERVER FAILED: " + e);
     }
   }
 });
 
-/*
- * handleDialog
- *
- * Invoked a short period of time after calling startCallbackTimer(), and
- * allows testing the actual auth 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, "."); // make it easier to see next line in logs.
-  ok(true, "handleDialog running for test " + testNum);
-  ok(true, "Time is " + (new Date()).toUTCString());
-  dumpNotifications();
-
-  var dialog    = doc.getElementById("commonDialog");
-  var ui = doc.defaultView.Dialog.ui;
-  var actualState = getPromptState(ui);
-
-  checkPromptState(actualState, state);
-
-  if ("textField" in action) {
-    doc.getElementById("loginTextbox").setAttribute("value", action.textField);
-  }
-  if ("passField" in action) {
-    doc.getElementById("password1Textbox").setAttribute("value", action.passField);
-  }
-
-  if (action.buttonClick == "ok")
-    dialog.acceptDialog();
-  else
-    dialog.cancelDialog();
-
-  ok(true, "handleDialog done");
-  didDialog = true;
-}
-
 startup();
 
 add_task(function* runTests() {
   info("Waiting for startup to complete...");
   yield startupComplete;
 
   var authinfo = {
     username : "",
@@ -342,17 +308,16 @@ add_task(function* runTests() {
   const defaultMsg = "the message";
 
   // popupNotifications (not *popup*) is a constant, per-tab container. So, we
   // only need to fetch it once.
   var popupNotifications = getPopupNotifications(window.top);
   ok(popupNotifications, "Got popupNotifications");
 
   // ===== test 1 =====
-  testNum = 1;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "abc",
     passValue   : "",
     iconClass   : "question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -362,26 +327,25 @@ add_task(function* runTests() {
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     textField   : "xyz",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.prompt(defaultTitle, defaultMsg, "http://example.com",
                           Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(result.value, "xyz", "Checking prompt() returned value");
 
   // ===== test 2 =====
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "abc",
     passValue   : "",
     iconClass   : "question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -390,25 +354,24 @@ add_task(function* runTests() {
     checkMsg    : "",
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "cancel",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.prompt(defaultTitle, defaultMsg, "http://example.com",
                           Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
-  ok(didDialog, "handleDialog was invoked");
+  yield promptDone;
   ok(!isOk, "Checking dialog return value (cancel)");
 
   // ===== test 10 =====
   // Default password provided, existing logins are ignored.
-  testNum = 10;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "inputpw",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : true,
@@ -419,26 +382,25 @@ add_task(function* runTests() {
     focused     : "passField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "secret",
   };
   pword.value = "inputpw";
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(pword.value, "secret", "Checking returned password");
 
   // ===== test 11 =====
   // Default password provided, existing logins are ignored.
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "inputpw",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : true,
@@ -448,25 +410,24 @@ add_task(function* runTests() {
     checked     : false,
     focused     : "passField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "cancel",
   };
   pword.value = "inputpw";
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
+  yield promptDone;
   ok(!isOk, "Checking dialog return value (cancel)");
-  ok(didDialog, "handleDialog was invoked");
 
   // ===== test 12 =====
   // No default password provided, realm does not match existing login.
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : true,
@@ -477,36 +438,34 @@ add_task(function* runTests() {
     focused     : "passField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "secret",
   };
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(pword.value, "secret", "Checking returned password");
 
   // ===== test 13 =====
   // No default password provided, matching login is returned w/o prompting.
-  testNum++;
   pword.value = null;
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   ok(isOk, "Checking dialog return value (accept)");
   is(pword.value, "examplepass", "Checking returned password");
 
   // ===== test 14 =====
   // No default password provided, none of the logins from this host are
   // password-only so the user is prompted.
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : true,
@@ -517,73 +476,67 @@ add_task(function* runTests() {
     focused     : "passField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "secret",
   };
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(pword.value, "secret", "Checking returned password");
 
   // ===== test 15 =====
   // No default password provided, matching login is returned w/o prompting.
-  testNum++;
   pword.value = null;
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://user1name@example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   ok(isOk, "Checking dialog return value (accept)");
   is(pword.value, "user1pass", "Checking returned password");
 
   // ===== test 16 =====
   // No default password provided, matching login is returned w/o prompting.
-  testNum++;
   pword.value = null;
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://user2name@example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   ok(isOk, "Checking dialog return value (accept)");
   is(pword.value, "user2pass", "Checking returned password");
 
   // ===== test 17 =====
   // No default password provided, matching login is returned w/o prompting.
-  testNum++;
   pword.value = null;
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://user3%2Ename%40host@example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   ok(isOk, "Checking dialog return value (accept)");
   is(pword.value, "user3pass", "Checking returned password");
 
   // ===== test 18 =====
   // No default password provided, matching login is returned w/o prompting.
-  testNum++;
   pword.value = null;
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://100@beef@example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   ok(isOk, "Checking dialog return value (accept)");
   is(pword.value, "user3pass", "Checking returned password");
 
   // ===== test 19 =====
   // No default password provided, matching login is returned w/o prompting.
-  testNum++;
   pword.value = null;
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://100%25beef@example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   ok(isOk, "Checking dialog return value (accept)");
   is(pword.value, "user3pass", "Checking returned password");
 
   // XXX test saving a password with  Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY
 
   // ===== test 30 =====
   // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
-  testNum = 30;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : true,
@@ -594,26 +547,25 @@ add_task(function* runTests() {
     focused     : "passField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "fill2pass",
   };
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(pword.value, "fill2pass", "Checking returned password");
 
   // ===== test 31 =====
   // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : true,
@@ -624,25 +576,24 @@ add_task(function* runTests() {
     focused     : "passField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "fill2pass",
   };
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(pword.value, "fill2pass", "Checking returned password");
 
   // ===== test 100 =====
-  testNum = 100;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "inuser",
     passValue   : "inpass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -655,26 +606,25 @@ add_task(function* runTests() {
   };
   action = {
     buttonClick : "ok",
     textField   : "outuser",
     passField   : "outpass",
   };
   uname.value = "inuser";
   pword.value = "inpass";
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "outuser", "Checking returned username");
   is(pword.value, "outpass", "Checking returned password");
 
   // ===== test 101 =====
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "inuser",
     passValue   : "inpass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -685,25 +635,24 @@ add_task(function* runTests() {
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "cancel",
   };
   uname.value = "inuser";
   pword.value = "inpass";
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
+  yield promptDone;
   ok(!isOk, "Checking dialog return value (cancel)");
-  ok(didDialog, "handleDialog was invoked");
 
   // ===== test 102 =====
   // test filling in existing password-only login
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "examplepass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -714,27 +663,26 @@ add_task(function* runTests() {
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
   };
   uname.value = null;
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "", "Checking returned username");
   is(pword.value, "examplepass", "Checking returned password");
 
   // ===== test 103 =====
   // test filling in existing login (undetermined from multiple selection)
-  testNum++;
   // user2name/user2pass would also be valid to fill here.
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
@@ -746,27 +694,26 @@ add_task(function* runTests() {
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
   };
   uname.value = null;
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   ok(uname.value == "user1name" || uname.value == "user2name", "Checking returned username");
   ok(pword.value == "user1pass" || uname.value == "user2pass", "Checking returned password");
 
   // ===== test 104 =====
   // test filling in existing login (user1 from multiple selection)
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -777,27 +724,26 @@ add_task(function* runTests() {
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
   };
   uname.value = "user1name";
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "user1name", "Checking returned username");
   is(pword.value, "user1pass", "Checking returned password");
 
   // ===== test 105 =====
   // test filling in existing login (user2 from multiple selection)
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "user2name",
     passValue   : "user2pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -808,27 +754,26 @@ add_task(function* runTests() {
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
   };
   uname.value = "user2name";
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "user2name", "Checking returned username");
   is(pword.value, "user2pass", "Checking returned password");
 
   // ===== test 106 =====
   // test changing password
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "user2name",
     passValue   : "user2pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -840,27 +785,26 @@ add_task(function* runTests() {
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "NEWuser2pass",
   };
   uname.value = "user2name";
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "user2name", "Checking returned username");
   is(pword.value, "NEWuser2pass", "Checking returned password");
 
   // ===== test 107 =====
   // test changing password (back to original value)
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "user2name",
     passValue   : "NEWuser2pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -872,27 +816,26 @@ add_task(function* runTests() {
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "user2pass",
   };
   uname.value = "user2name";
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "user2name", "Checking returned username");
   is(pword.value, "user2pass", "Checking returned password");
 
   // ===== test 120 =====
   // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
-  testNum = 120;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -905,27 +848,26 @@ add_task(function* runTests() {
   };
   action = {
     buttonClick : "ok",
     textField   : "fill2user",
     passField   : "fill2pass",
   };
   uname.value = null;
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "fill2user", "Checking returned username");
   is(pword.value, "fill2pass", "Checking returned password");
 
   // ===== test 121 =====
   // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "",
     passValue   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -938,21 +880,21 @@ add_task(function* runTests() {
   };
   action = {
     buttonClick : "ok",
     textField   : "fill2user",
     passField   : "fill2pass",
   };
   uname.value = null;
   pword.value = null;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
+  yield promptDone;
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(uname.value, "fill2user", "Checking returned username");
   is(pword.value, "fill2pass", "Checking returned password");
 
   var channel1 = ioService.newChannel2("http://example.com",
                                        null,
                                        null,
                                        null,      // aLoadingNode
                                        SpecialPowers.Services.
@@ -968,17 +910,16 @@ add_task(function* runTests() {
                                        scriptSecurityManager.getSystemPrincipal(),
                                        null,      // aTriggeringPrincipal
                                        Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
                                        Ci.nsIContentPolicy.TYPE_OTHER);
 
   var level = Ci.nsIAuthPrompt2.LEVEL_NONE;
 
   // ===== test 500 =====
-  testNum = 500;
   state = {
     msg         : "A username and password are being requested by http://example.com. The site says: \"some realm\"",
     title       : "Authentication Required",
     textValue   : "inuser",
     passValue   : "inpass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -993,26 +934,25 @@ add_task(function* runTests() {
     buttonClick : "ok",
     textField   : "outuser",
     passField   : "outpass",
   };
   authinfo.username = "inuser";
   authinfo.password = "inpass";
   authinfo.realm    = "some realm";
 
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel1, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(authinfo.username, "outuser", "Checking returned username");
   is(authinfo.password, "outpass", "Checking returned password");
 
   // ===== test 501 =====
-  testNum++;
   state = {
     msg         : "A username and password are being requested by http://example.com. The site says: \"some realm\"",
     title       : "Authentication Required",
     textValue   : "outuser",
     passValue   : "outpass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -1021,25 +961,24 @@ add_task(function* runTests() {
     checkMsg    : "",
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "cancel",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel1, level, authinfo);
+  yield promptDone;
 
   ok(!isOk, "Checking dialog return value (cancel)");
-  ok(didDialog, "handleDialog was invoked");
 
   // ===== test 502 =====
   // test filling in password-only login
-  testNum++;
   state = {
     msg         : "A username and password are being requested by http://example.com. The site says: \"http://example.com\"",
     title       : "Authentication Required",
     textValue   : "",
     passValue   : "examplepass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -1052,27 +991,26 @@ add_task(function* runTests() {
   };
   action = {
     buttonClick : "ok",
   };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example.com";
 
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel1, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(authinfo.username, "", "Checking returned username");
   is(authinfo.password, "examplepass", "Checking returned password");
 
   // ===== test 503 =====
   // test filling in existing login (undetermined from multiple selection)
-  testNum++;
   // user2name/user2pass would also be valid to fill here.
   state = {
     msg         : "A username and password are being requested by http://example2.com. The site says: \"http://example2.com\"",
     title       : "Authentication Required",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
@@ -1086,27 +1024,26 @@ add_task(function* runTests() {
   };
   action = {
     buttonClick : "ok",
   };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel2, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   ok(authinfo.username == "user1name" || authinfo.username == "user2name", "Checking returned username");
   ok(authinfo.password == "user1pass" || authinfo.password == "user2pass", "Checking returned password");
 
   // ===== test 504 =====
   // test filling in existing login (undetermined --> user1)
-  testNum++;
   // user2name/user2pass would also be valid to fill here.
   state = {
     msg         : "A username and password are being requested by http://example2.com. The site says: \"http://example2.com\"",
     title       : "Authentication Required",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
@@ -1123,27 +1060,26 @@ add_task(function* runTests() {
     buttonClick : "ok",
     textField   : "user1name",
     passField   : "user1pass",
   };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel2, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(authinfo.username, "user1name", "Checking returned username");
   is(authinfo.password, "user1pass", "Checking returned password");
 
   // ===== test 505 =====
   // test filling in existing login (undetermined --> user2)
-  testNum++;
   // user2name/user2pass would also be valid to fill here.
   state = {
     msg         : "A username and password are being requested by http://example2.com. The site says: \"http://example2.com\"",
     title       : "Authentication Required",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
@@ -1161,27 +1097,26 @@ add_task(function* runTests() {
     textField   : "user2name",
     passField   : "user2pass",
   };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   dumpNotifications();
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel2, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(authinfo.username, "user2name", "Checking returned username");
   is(authinfo.password, "user2pass", "Checking returned password");
 
   // ===== test 506 =====
   // test changing a password (undetermined --> user2 w/ newpass)
-  testNum++;
   // user2name/user2pass would also be valid to fill here.
   state = {
     msg         : "A username and password are being requested by http://example2.com. The site says: \"http://example2.com\"",
     title       : "Authentication Required",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
@@ -1199,27 +1134,26 @@ add_task(function* runTests() {
     textField   : "user2name",
     passField   : "NEWuser2pass",
   };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   dumpNotifications();
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel2, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(authinfo.username, "user2name", "Checking returned username");
   is(authinfo.password, "NEWuser2pass", "Checking returned password");
 
   // ===== test 507 =====
   // test changing a password (undetermined --> user2 w/ origpass)
-  testNum++;
   // user2name/user2pass would also be valid to fill here.
   state = {
     msg         : "A username and password are being requested by http://example2.com. The site says: \"http://example2.com\"",
     title       : "Authentication Required",
     textValue   : "user1name",
     passValue   : "user1pass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
@@ -1237,27 +1171,26 @@ add_task(function* runTests() {
     textField   : "user2name",
     passField   : "user2pass",
   };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   dumpNotifications();
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(channel2, level, authinfo);
+  yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   is(authinfo.username, "user2name", "Checking returned username");
   is(authinfo.password, "user2pass", "Checking returned password");
 
   // ===== test 508 =====
   // test proxy login (default = no autologin), make sure it prompts.
-  testNum++;
   state = {
     msg         : "The proxy moz-proxy://127.0.0.1:8888 is requesting a username and password. The site says: \"Proxy Realm\"",
     title       : "Authentication Required",
     textValue   : "proxuser",
     passValue   : "proxpass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -1273,29 +1206,28 @@ add_task(function* runTests() {
   };
   proxyAuthinfo.username = "";
   proxyAuthinfo.password = "";
   proxyAuthinfo.realm    = "Proxy Realm";
   proxyAuthinfo.flags    = Ci.nsIAuthInformation.AUTH_PROXY;
 
   dumpNotifications();
   var time1 = pwmgr.findLogins({}, mozproxy, null, "Proxy Realm")[0].QueryInterface(Ci.nsILoginMetaInfo).timeLastUsed;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(proxyChannel, level, proxyAuthinfo);
+  yield promptDone;
   var time2 = pwmgr.findLogins({}, mozproxy, null, "Proxy Realm")[0].QueryInterface(Ci.nsILoginMetaInfo).timeLastUsed;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   isnot(time1, time2, "Checking that timeLastUsed was updated");
   is(proxyAuthinfo.username, "proxuser", "Checking returned username");
   is(proxyAuthinfo.password, "proxpass", "Checking returned password");
 
   // ===== test 509 =====
   // test proxy login (with autologin)
-  testNum++;
 
   // Enable the autologin pref.
   prefs.setBoolPref("signon.autologin.proxy", true);
 
   proxyAuthinfo.username = "";
   proxyAuthinfo.password = "";
   proxyAuthinfo.realm    = "Proxy Realm";
   proxyAuthinfo.flags    = Ci.nsIAuthInformation.AUTH_PROXY;
@@ -1306,17 +1238,16 @@ add_task(function* runTests() {
 
   ok(isOk, "Checking dialog return value (accept)");
   isnot(time1, time2, "Checking that timeLastUsed was updated");
   is(proxyAuthinfo.username, "proxuser", "Checking returned username");
   is(proxyAuthinfo.password, "proxpass", "Checking returned password");
 
   // ===== test 510 =====
   // test proxy login (with autologin), ensure it prompts after a failed auth.
-  testNum++;
   state = {
     msg         : "The proxy moz-proxy://127.0.0.1:8888 is requesting a username and password. The site says: \"Proxy Realm\"",
     title       : "Authentication Required",
     textValue   : "proxuser",
     passValue   : "proxpass",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -1332,29 +1263,28 @@ add_task(function* runTests() {
   };
 
   proxyAuthinfo.username = "";
   proxyAuthinfo.password = "";
   proxyAuthinfo.realm    = "Proxy Realm";
   proxyAuthinfo.flags    = (Ci.nsIAuthInformation.AUTH_PROXY | Ci.nsIAuthInformation.PREVIOUS_FAILED);
 
   time1 = pwmgr.findLogins({}, mozproxy, null, "Proxy Realm")[0].QueryInterface(Ci.nsILoginMetaInfo).timeLastUsed;
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   isOk = prompter2.promptAuth(proxyChannel, level, proxyAuthinfo);
+  yield promptDone;
   time2 = pwmgr.findLogins({}, mozproxy, null, "Proxy Realm")[0].QueryInterface(Ci.nsILoginMetaInfo).timeLastUsed;
 
   ok(isOk, "Checking dialog return value (accept)");
-  ok(didDialog, "handleDialog was invoked");
   isnot(time1, time2, "Checking that timeLastUsed was updated");
   is(proxyAuthinfo.username, "proxuser", "Checking returned username");
   is(proxyAuthinfo.password, "proxpass", "Checking returned password");
 
   // ===== test 511 =====
   // test proxy login (with autologin), ensure it prompts in Private Browsing mode.
-  testNum++;
   state = {
     msg         : "the message",
     title       : "the title",
     textValue   : "proxuser",
     passValue   : "proxpass",
   };
   action = {
     buttonClick : "ok",
@@ -1373,17 +1303,16 @@ add_task(function* runTests() {
 
   // clear plain HTTP auth sessions before the test, to allow
   // running them more than once.
   var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
                 getService(Ci.nsIHttpAuthManager);
   authMgr.clearAll();
 
   // ===== test 1000 =====
-  testNum = 1000;
   state = {
     msg         : "A username and password are being requested by http://mochi.test:8888. The site says: \"mochitest\"",
     title       : "Authentication Required",
     textValue   : "mochiuser1",
     passValue   : "mochipass1",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -1392,37 +1321,37 @@ add_task(function* runTests() {
     checkMsg    : "",
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
 
   // The following tests are driven by iframe loads
 
   function checkEchoedAuthInfo(expectedState) {
     // The server echos back the HTTP auth info it received.
     let username = iframe.contentDocument.getElementById("user").textContent;
     let password = iframe.contentDocument.getElementById("pass").textContent;
     let authok = iframe.contentDocument.getElementById("ok").textContent;
 
     is(authok, "PASS", "Checking for successful authentication");
     is(username, expectedState.user, "Checking for echoed username");
     is(password, expectedState.pass, "Checking for echoed password");
   }
 
   var iframeLoaded = onloadPromiseFor("iframe");
   iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
+  yield promptDone;
   yield iframeLoaded;
   checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"});
 
-  testNum++;
   state = {
     msg         : "A username and password are being requested by http://mochi.test:8888. The site says: \"mochitest2\"",
     title       : "Authentication Required",
     textValue   : "mochiuser2",
     passValue   : "mochipass2",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
@@ -1431,35 +1360,34 @@ add_task(function* runTests() {
     checkMsg    : "",
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   // We've already authenticated to this host:port. For this next
   // request, the existing auth should be sent, we'll get a 401 reply,
   // and we should prompt for new auth.
   iframeLoaded = onloadPromiseFor("iframe");
   iframe.src = "authenticate.sjs?user=mochiuser2&pass=mochipass2&realm=mochitest2";
+  yield promptDone;
   yield iframeLoaded;
   checkEchoedAuthInfo({user: "mochiuser2", pass: "mochipass2"});
 
-  testNum++;
   // Now make a load that requests the realm from test 1000. It was
   // already provided there, so auth will *not* be prompted for -- the
   // networking layer already knows it!
   iframeLoaded = onloadPromiseFor("iframe");
   iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
   yield iframeLoaded;
   checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"});
 
-  testNum++;
   // Same realm we've already authenticated to, but with a different
   // expected password (to trigger an auth prompt, and change-password
   // popup notification).
   state = {
     msg         : "A username and password are being requested by http://mochi.test:8888. The site says: \"mochitest\"",
     title       : "Authentication Required",
     textValue   : "mochiuser1",
     passValue   : "mochipass1",
@@ -1472,23 +1400,23 @@ add_task(function* runTests() {
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "mochipass1-new",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   iframeLoaded = onloadPromiseFor("iframe");
   iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1-new";
+  yield promptDone;
   yield iframeLoaded;
   checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1-new"});
 
-  testNum++;
   // Housekeeping: change it back
   var pwchanged = new Promise(resolve => {
     function resetIt() {
       tmpLogin.init("http://mochi.test:8888", null, "mochitest",
                     "mochiuser1", "mochipass1-new", "", "");
       pwmgr.modifyLogin(tmpLogin, login3A);
       resolve(true);
     }
@@ -1521,23 +1449,23 @@ add_task(function* runTests() {
     checked     : false,
     focused     : "textField",
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     passField   : "mochipass3-new",
   };
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
   iframeLoaded = onloadPromiseFor("iframe");
   iframe.src = "authenticate.sjs?user=mochiuser3&pass=mochipass3-new&realm=mochitest3";
+  yield promptDone;
   yield iframeLoaded;
   checkEchoedAuthInfo({user: "mochiuser3", pass: "mochipass3-new"});
 
-  testNum++;
   // Housekeeping: change it back to the original login4. Actually,
   // just delete it and we'll re-add it as the next test.
   pwchanged = new Promise(resolve => {
     function clearIt() {
       ok(true, "1004's clearIt() called.");
       try {
         tmpLogin.init("http://mochi.test:8888", null, "mochitest3",
                       "mochiuser3", "mochipass3-new", "", "");
@@ -1579,24 +1507,24 @@ add_task(function* runTests() {
     defButton   : "button0",
   };
   action = {
     buttonClick : "ok",
     textField   : "mochiuser3",
     passField   : "mochipass3-old",
   };
   // Trigger a new prompt, so we can test adding a new login.
-  startCallbackTimer();
+  promptDone = handlePrompt(action);
 
   iframeLoaded = onloadPromiseFor("iframe");
   iframe.src = "authenticate.sjs?user=mochiuser3&pass=mochipass3-old&realm=mochitest3";
+  yield promptDone;
   yield iframeLoaded;
   checkEchoedAuthInfo({user: "mochiuser3", pass: "mochipass3-old"});
 
-  testNum++;
   var pwsaved = new Promise(resolve => {
     function finishIt() {
       finishTest();
       resolve(true);
     }
     addNotificationCallback(finishIt);
   });