Bug 1267388 - introduce a "state" object to represent actual/expected prompt state. r?MattN draft
authorJustin Dolske <dolske@mozilla.com>
Mon, 25 Apr 2016 13:17:39 -0700
changeset 356150 cee34b472d17bf9fdbcf78aafbd377a1db2e98bd
parent 356149 b4da8baa3356e66f54061fcfb1efc3e832f83030
child 356151 e577ba5f7e03eb231f0c332f7326cdc73efbd7a1
push id16458
push userjdolske@mozilla.com
push dateMon, 25 Apr 2016 20:17:50 +0000
reviewersMattN
bugs1267388
milestone49.0a1
Bug 1267388 - introduce a "state" object to represent actual/expected prompt state. r?MattN MozReview-Commit-ID: LfywPKYn7QZ
toolkit/components/passwordmgr/test/mochitest/prompt_common.js
toolkit/components/passwordmgr/test/mochitest/test_prompt.html
--- a/toolkit/components/passwordmgr/test/mochitest/prompt_common.js
+++ b/toolkit/components/passwordmgr/test/mochitest/prompt_common.js
@@ -65,8 +65,24 @@ function getDialogDoc() {
         //ok(true, "Got window: " + childDoc.location.href);
         if (childDoc.location.href == "chrome://global/content/commonDialog.xul")
           return childDoc;
     }
   }
 
   return null;
 }
+
+function checkPromptState(promptState, expectedState) {
+    // is(promptState.title,       expectedState.title,       "Checking expected title");
+    is(promptState.msg,         expectedState.msg,         "Checking expected message");
+    is(promptState.textValue, expectedState.textValue, "Checking textbox value");
+    is(promptState.passValue, expectedState.passValue, "Checking passbox value");
+}
+
+function getPromptState(ui) {
+  let state = {};
+  state.msg         = ui.infoBody.textContent;
+  state.title       = ui.infoTitle.textContent;
+  state.textValue   = ui.loginTextbox.getAttribute("value");
+  state.passValue   = ui.password1Textbox.getAttribute("value");
+  return state;
+}
--- a/toolkit/components/passwordmgr/test/mochitest/test_prompt.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt.html
@@ -263,279 +263,221 @@ var storageObserver = SpecialPowers.wrap
  * 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 body = doc.getElementById("info.body");
-  var userfield = doc.getElementById("loginTextbox");
-  var passfield = doc.getElementById("password1Textbox");
-  var username = userfield.getAttribute("value");
-  var password = passfield.getAttribute("value");
   var dialog    = doc.getElementById("commonDialog");
+  var ui = doc.defaultView.Dialog.ui;
+  var actualState = getPromptState(ui);
+
+  checkPromptState(actualState, state);
 
   switch(testNum) {
     case 1:
       action = {
         buttonClick : "ok",
         textField   : "xyz",
       };
-      is(username, "abc", "Checking provided username");
       // Temporarily commented out because of Bug #718543
       // is(doc.activeElement, userfield.inputField, "focus correct for test" + testNum);
       // doc.commandDispatcher.rewindFocus();
       // is(doc.activeElement, body, "description focusable");
       break;
     case 2:
       action = {
         buttonClick : "cancel",
       };
       break;
     case 10:
       action = {
         buttonClick : "ok",
         passField   : "secret",
       };
-      is(password, "inputpw", "Checking provided password");
       // Temporarily commented out because of Bug #718543
       // is(doc.activeElement, passfield.inputField, "focus correct for test" + testNum);
       break;
     case 11:
       action = {
         buttonClick : "cancel",
       };
-      is(password, "inputpw", "Checking provided password");
       break;
     case 12:
       action = {
         buttonClick : "ok",
         passField   : "secret",
       };
-      is(password, "", "Checking provided password");
       break;
     case 14:
       action = {
         buttonClick : "ok",
         passField   : "secret",
       };
-      is(password, "", "Checking provided password");
       break;
     case 30:
     case 31:
       action = {
         buttonClick : "ok",
         passField   : "fill2pass",
       };
-      is(password, "", "Checking provided password");
       break;
     case 100:
       action = {
         buttonClick : "ok",
         textField   : "outuser",
         passField   : "outpass",
       };
-      is(username, "inuser", "Checking provided username");
-      is(password, "inpass", "Checking provided password");
       break;
     case 101:
       action = {
         buttonClick : "cancel",
       };
       break;
     case 102:
       action = {
         buttonClick : "ok",
       };
-      is(username, "", "Checking provided username");
-      is(password, "examplepass", "Checking provided password");
       break;
     case 103:
       action = {
         buttonClick : "ok",
       };
-      ok(username == "user1name" || username == "user2name", "Checking filled username");
-      ok(password == "user1pass" || password == "user2pass", "Checking filled password");
       break;
     case 104:
       action = {
         buttonClick : "ok",
       };
-      is(username, "user1name", "Checking filled username");
-      is(password, "user1pass", "Checking filled password");
       break;
     case 105:
       action = {
         buttonClick : "ok",
       };
-      is(username, "user2name", "Checking filled username");
-      is(password, "user2pass", "Checking filled password");
       break;
     case 106:
       action = {
         buttonClick : "ok",
         passField   : "NEWuser2pass",
       };
-      is(username, "user2name", "Checking filled username");
-      is(password, "user2pass", "Checking filled password");
       break;
     case 107:
       action = {
         buttonClick : "ok",
         passField   : "user2pass",
       };
-      is(username, "user2name", "Checking filled username");
-      is(password, "NEWuser2pass", "Checking filled password");
       break;
     case 120:
     case 121:
       action = {
         buttonClick : "ok",
         textField   : "fill2user",
         passField   : "fill2pass",
       };
-      is(username, "", "Checking filled username");
-      is(password, "", "Checking filled password");
       break;
     case 500:
       action = {
         buttonClick : "ok",
         textField   : "outuser",
         passField   : "outpass",
       };
-      is(username, "inuser", "Checking unfilled username");
-      is(password, "inpass", "Checking unfilled password");
       break;
     case 501:
       action = {
         buttonClick : "cancel",
       };
       break;
     case 502:
       action = {
         buttonClick : "ok",
       };
-      is(username, "", "Checking filled username");
-      is(password, "examplepass", "Checking filled password");
       break;
     case 503:
       action = {
         buttonClick : "ok",
       };
-      // either of the two logins might have been filled in
-      ok(username == "user1name" || username == "user2name", "Checking filled username");
-      ok(password == "user1pass" || password == "user2pass", "Checking filled password");
       break;
     case 504:
       // enter one of the known logins, test 504+505 exercise the two possible states.
       action = {
         buttonClick : "ok",
         textField   : "user1name",
         passField   : "user1pass",
       };
-      // either of the two logins might have been filled in
-      ok(username == "user1name" || username == "user2name", "Checking filled username");
-      ok(password == "user1pass" || password == "user2pass", "Checking filled password");
       break;
     case 505:
       // enter one of the known logins, test 504+505 exercise the two possible states.
       action = {
         buttonClick : "ok",
         textField   : "user2name",
         passField   : "user2pass",
       };
-      // either of the two logins might have been filled in
-      ok(username == "user1name" || username == "user2name", "Checking filled username");
-      ok(password == "user1pass" || password == "user2pass", "Checking filled password");
       break;
     case 506:
       // force to user2, and change the password
       action = {
         buttonClick : "ok",
         textField   : "user2name",
         passField   : "NEWuser2pass",
       };
-      // either of the two logins might have been filled in
-      ok(username == "user1name" || username == "user2name", "Checking filled username");
-      ok(password == "user1pass" || password == "user2pass", "Checking filled password");
       break;
     case 507:
       // force to user2, and change the password back
       action = {
         buttonClick : "ok",
         textField   : "user2name",
         passField   : "user2pass",
       };
-      // either of the two logins might have been filled in
-      ok(username == "user1name" || username == "user2name", "Checking filled username");
-      ok(password == "user1pass" || password == "user2pass", "Checking filled password");
       break;
     case 508:
       action = {
         buttonClick : "ok",
       };
-      is(username, "proxuser", "Checking filled username");
-      is(password, "proxpass", "Checking filled password");
       break;
     // No case 509, it's unprompted.
     case 510:
       action = {
         buttonClick : "ok",
       };
-      is(username, "proxuser", "Checking filled username");
-      is(password, "proxpass", "Checking filled password");
       break;
     case 511:
       action = {
         buttonClick : "ok",
       };
-      is(username, "proxuser", "Checking filled username");
-      is(password, "proxpass", "Checking filled password");
       break;
     case 1000:
       action = {
         buttonClick : "ok",
       };
-      is(username, "mochiuser1", "Checking filled username");
-      is(password, "mochipass1", "Checking filled password");
       break;
     case 1001:
       action = {
         buttonClick : "ok",
       };
-      is(username, "mochiuser2", "Checking filled username");
-      is(password, "mochipass2", "Checking filled password");
       break;
     // (1002 doesn't trigger a dialog)
     case 1003:
       action = {
         buttonClick : "ok",
         passField   : "mochipass1-new",
       };
-      is(username, "mochiuser1", "Checking filled username");
-      is(password, "mochipass1", "Checking filled password");
       break;
     case 1004:
       action = {
         buttonClick : "ok",
         passField   : "mochipass3-new",
       };
-      is(username, "mochiuser3", "Checking filled username");
-      is(password, "mochipass3-old", "Checking filled password");
       break;
     case 1005:
       action = {
         buttonClick : "ok",
         textField   : "mochiuser3",
         passField   : "mochipass3-old",
       };
-      is(username, "", "Checking filled username");
-      is(password, "", "Checking filled password");
       break;
     default:
       ok(false, "Uhh, unhandled switch for testNum #" + testNum);
       break;
   }
 
   if ("textField" in action) {
     doc.getElementById("loginTextbox").setAttribute("value", action.textField);
@@ -573,16 +515,23 @@ function handleLoad() {
   var authok = iframe.contentDocument.getElementById("ok").textContent;
 
   switch(testNum) {
     case 1000:
       testNum++;
       is(authok, "PASS", "Checking for successful authentication");
       is(username, "mochiuser1", "Checking for echoed username");
       is(password, "mochipass1", "Checking for echoed password");
+
+      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",
+      };
       startCallbackTimer();
       // 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.
       iframe.src = "authenticate.sjs?user=mochiuser2&pass=mochipass2&realm=mochitest2";
       break;
     case 1001:
       testNum++;
@@ -598,16 +547,22 @@ function handleLoad() {
       testNum++;
       is(authok, "PASS", "Checking for successful authentication");
       is(username, "mochiuser1", "Checking for echoed username");
       is(password, "mochipass1", "Checking for echoed password");
 
       // 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",
+      };
       startCallbackTimer();
       iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1-new";
       break;
     case 1003:
       testNum++;
       is(authok, "PASS", "Checking for successful authentication");
       is(username, "mochiuser1", "Checking for echoed username");
       is(password, "mochipass1-new", "Checking for echoed password");
@@ -625,25 +580,37 @@ function handleLoad() {
       popup = getPopup(popupNotifications, "password-change");
       ok(popup, "got popup notification");
       clickPopupButton(popup, kChangeButton);
       popup.remove();
 
       // Same as last test, but for a realm we haven't already authenticated
       // to (but have an existing saved login for, so that we'll trigger
       // a change-password popup notification.
+      state = {
+        msg         : "A username and password are being requested by http://mochi.test:8888. The site says: \"mochitest3\"",
+        title       : "Authentication Required",
+        textValue   : "mochiuser3",
+        passValue   : "mochipass3-old",
+      };
       startCallbackTimer();
       iframe.src = "authenticate.sjs?user=mochiuser3&pass=mochipass3-new&realm=mochitest3";
       break;
     case 1004:
       testNum++;
       is(authok, "PASS", "Checking for successful authentication");
       is(username, "mochiuser3", "Checking for echoed username");
       is(password, "mochipass3-new", "Checking for echoed password");
 
+      state = {
+        msg         : "A username and password are being requested by http://mochi.test:8888. The site says: \"mochitest3\"",
+        title       : "Authentication Required",
+        textValue   : "",
+        passValue   : "",
+      };
       // Housekeeping: change it back to the original login4. Actually,
       // just delete it and we'll re-add it as the next test.
       function clearIt() {
         ok(true, "1004's clearIt() called.");
        try {
         tmpLogin.init("http://mochi.test:8888", null, "mochitest3",
                       "mochiuser3", "mochipass3-new", "", "");
         pwmgr.removeLogin(tmpLogin);
@@ -723,288 +690,398 @@ function doTests() {
   ok(Ci_promptFac != null, "Access Ci.nsIPromptFactory");
 
   const promptFac = Cc_promptFac.getService(Ci_promptFac);
   ok(promptFac != null, "promptFac getService()");
 
   var prompter1 = promptFac.getPrompt(window, Ci.nsIAuthPrompt);
   var prompter2 = promptFac.getPrompt(window, Ci.nsIAuthPrompt2);
 
-  function dialogTitle() { return "nsILoginManagerPrompter test #" + testNum; }
-  var dialogText  = "This dialog should be modified and dismissed by the test.";
   var uname  = { value : null };
   var pword  = { value : null };
   var result = { value : null };
   var isOk;
 
+  const defaultTitle = "the title";
+  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   : "",
+  };
   startCallbackTimer();
-  isOk = prompter1.prompt(dialogTitle(), dialogText, "http://example.com",
+  isOk = prompter1.prompt(defaultTitle, defaultMsg, "http://example.com",
                           Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
 
   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   : "",
+  };
   startCallbackTimer();
-  isOk = prompter1.prompt(dialogTitle(), dialogText, "http://example.com",
+  isOk = prompter1.prompt(defaultTitle, defaultMsg, "http://example.com",
                           Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
   ok(didDialog, "handleDialog was invoked");
   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",
+  };
   pword.value = "inputpw";
   startCallbackTimer();
-  isOk = prompter1.promptPassword(dialogTitle(), dialogText, "http://example.com",
+  isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   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",
+  };
   pword.value = "inputpw";
   startCallbackTimer();
-  isOk = prompter1.promptPassword(dialogTitle(), dialogText, "http://example.com",
+  isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   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   : "",
+  };
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptPassword(dialogTitle(), dialogText, "http://nonexample.com",
+  isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   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(dialogTitle(), dialogText, "http://example.com",
+  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   : "",
+  };
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptPassword(dialogTitle(), dialogText, "http://example2.com",
+  isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   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(dialogTitle(), dialogText, "http://user1name@example2.com",
+  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(dialogTitle(), dialogText, "http://user2name@example2.com",
+  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(dialogTitle(), dialogText, "http://user3%2Ename%40host@example2.com",
+  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(dialogTitle(), dialogText, "http://100@beef@example2.com",
+  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(dialogTitle(), dialogText, "http://100%25beef@example2.com",
+  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   : "",
+  };
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
+  isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
   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   : "",
+  };
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
+  isOk = prompter1.promptPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, pword);
   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",
+  };
   uname.value = "inuser";
   pword.value = "inpass";
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://nonexample.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
   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",
+  };
   uname.value = "inuser";
   pword.value = "inpass";
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://nonexample.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
   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",
+  };
   uname.value = null;
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://example.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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",
+  };
   uname.value = null;
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://example2.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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",
+  };
   uname.value = "user1name";
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://example2.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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",
+  };
   uname.value = "user2name";
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://example2.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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",
+  };
   uname.value = "user2name";
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://example2.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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",
+  };
   uname.value = "user2name";
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "http://example2.com",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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   : "",
+  };
   uname.value = null;
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
   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   : "",
+  };
   uname.value = null;
   pword.value = null;
   startCallbackTimer();
-  isOk = prompter1.promptUsernameAndPassword(dialogTitle(), dialogText, "example2.com:80 (somerealm)",
+  isOk = prompter1.promptUsernameAndPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
   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,
@@ -1024,132 +1101,191 @@ function doTests() {
                                        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",
+  };
   authinfo.username = "inuser";
   authinfo.password = "inpass";
   authinfo.realm    = "some realm";
 
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel1, level, authinfo);
 
   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",
+  };
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel1, level, authinfo);
 
   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",
+  };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example.com";
 
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel1, level, authinfo);
 
   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",
+  };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel2, level, authinfo);
 
   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",
+  };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel2, level, authinfo);
 
   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",
+  };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   dumpNotifications();
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel2, level, authinfo);
 
   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",
+  };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   dumpNotifications();
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel2, level, authinfo);
 
   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",
+  };
   authinfo.username = "";
   authinfo.password = "";
   authinfo.realm    = "http://example2.com";
 
   dumpNotifications();
   startCallbackTimer();
   isOk = prompter2.promptAuth(channel2, level, authinfo);
 
   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",
+  };
   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();
@@ -1181,16 +1317,22 @@ function doTests() {
   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",
+  };
 
   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();
@@ -1201,16 +1343,22 @@ function doTests() {
   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",
+  };
 
   proxyAuthinfo.username = "";
   proxyAuthinfo.password = "";
   proxyAuthinfo.realm    = "Proxy Realm";
   proxyAuthinfo.flags    = Ci.nsIAuthInformation.AUTH_PROXY;
 
   prefs.clearUserPref("signon.autologin.proxy");
 
@@ -1224,16 +1372,22 @@ function doTests() {
   // 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",
+  };
   startCallbackTimer();
   iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
 
   // ...remaining tests are driven by handleLoad()...
 }
 </script>
 </pre>
 </body>