Backed out changeset 8c1ee05fbbd6 (bug 949617)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 27 Jun 2014 15:17:42 +0200
changeset 204892 990442eb272d99a69197242b2f9093cefae2c4c6
parent 204891 edce393d18312a54903add099a1d37fc3b54dc01
child 204893 115171f8216d3b15f142e53e11a495b6c79d3c8b
push idunknown
push userunknown
push dateunknown
bugs949617
milestone33.0a1
backs out8c1ee05fbbd6eabaaa438703b7018443a0e86fb3
Backed out changeset 8c1ee05fbbd6 (bug 949617)
browser/base/content/content.js
browser/components/nsBrowserGlue.js
browser/metro/base/content/browser-ui.js
mobile/android/chrome/content/browser.js
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/LoginManagerParent.jsm
toolkit/components/passwordmgr/moz.build
toolkit/components/passwordmgr/nsILoginManager.idl
toolkit/components/passwordmgr/nsLoginManager.js
toolkit/components/passwordmgr/test/pwmgr_common.js
toolkit/components/passwordmgr/test/subtst_privbrowsing_3.html
toolkit/components/passwordmgr/test/subtst_privbrowsing_4.html
toolkit/components/passwordmgr/test/test_basic_form.html
toolkit/components/passwordmgr/test/test_basic_form_0pw.html
toolkit/components/passwordmgr/test/test_basic_form_1pw.html
toolkit/components/passwordmgr/test/test_basic_form_1pw_2.html
toolkit/components/passwordmgr/test/test_basic_form_2.html
toolkit/components/passwordmgr/test/test_basic_form_2pw_1.html
toolkit/components/passwordmgr/test/test_basic_form_2pw_2.html
toolkit/components/passwordmgr/test/test_basic_form_3pw_1.html
toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
toolkit/components/passwordmgr/test/test_basic_form_html5.html
toolkit/components/passwordmgr/test/test_basic_form_observer_autocomplete.html
toolkit/components/passwordmgr/test/test_basic_form_observer_autofillForms.html
toolkit/components/passwordmgr/test/test_basic_form_observer_foundLogins.html
toolkit/components/passwordmgr/test/test_basic_form_pwevent.html
toolkit/components/passwordmgr/test/test_basic_form_pwonly.html
toolkit/components/passwordmgr/test/test_bug_227640.html
toolkit/components/passwordmgr/test/test_bug_242956.html
toolkit/components/passwordmgr/test/test_bug_360493_1.html
toolkit/components/passwordmgr/test/test_bug_360493_2.html
toolkit/components/passwordmgr/test/test_bug_391514.html
toolkit/components/passwordmgr/test/test_bug_427033.html
toolkit/components/passwordmgr/test/test_bug_444968.html
toolkit/components/passwordmgr/test/test_case_differences.html
toolkit/components/passwordmgr/test/test_master_password.html
toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -29,32 +29,32 @@ addMessageListener("Browser:HideSessionR
   let doc = content.document;
   let container;
   if (doc.documentURI.toLowerCase() == "about:home" &&
       (container = doc.getElementById("sessionRestoreContainer"))){
     container.hidden = true;
   }
 });
 
-addEventListener("DOMFormHasPassword", function(event) {
-  InsecurePasswordUtils.checkForInsecurePasswords(event.target);
-  LoginManagerContent.onFormPassword(event);
-});
-addEventListener("DOMAutoComplete", function(event) {
-  LoginManagerContent.onUsernameInput(event);
-});
-addEventListener("blur", function(event) {
-  LoginManagerContent.onUsernameInput(event);
-});
-
 if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
   addEventListener("contextmenu", function (event) {
     sendAsyncMessage("contextmenu", {}, { event: event });
   }, false);
 } else {
+  addEventListener("DOMFormHasPassword", function(event) {
+    InsecurePasswordUtils.checkForInsecurePasswords(event.target);
+    LoginManagerContent.onFormPassword(event);
+  });
+  addEventListener("DOMAutoComplete", function(event) {
+    LoginManagerContent.onUsernameInput(event);
+  });
+  addEventListener("blur", function(event) {
+    LoginManagerContent.onUsernameInput(event);
+  });
+
   addEventListener("mozUITour", function(event) {
     if (!Services.prefs.getBoolPref("browser.uitour.enabled"))
       return;
 
     let handled = UITour.onPageEvent(event);
     if (handled)
       addEventListener("pagehide", UITour);
   }, false, true);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -88,19 +88,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/sessionstore/SessionStore.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
                                   "resource:///modules/BrowserUITelemetry.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
                                   "resource://gre/modules/AsyncShutdown.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
-                                  "resource://gre/modules/LoginManagerParent.jsm");
-
 #ifdef NIGHTLY_BUILD
 XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
                                   "resource:///modules/SignInToWebsite.jsm");
 #endif
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 
@@ -505,18 +502,16 @@ BrowserGlue.prototype = {
     BrowserUITelemetry.init();
     ContentSearch.init();
 
     if (Services.appinfo.browserTabsRemote) {
       ContentClick.init();
       RemotePrompt.init();
     }
 
-    LoginManagerParent.init();
-
     Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
   },
 
   _checkForOldBuildUpdates: function () {
     // check for update if our build is old
     if (Services.prefs.getBoolPref("app.update.enabled") &&
         Services.prefs.getBoolPref("app.update.checkInstallTime")) {
 
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -2,19 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm")
 Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
-                                  "resource://gre/modules/LoginManagerParent.jsm");
-
 /**
  * Constants
  */
 
 // Devtools Messages
 const debugServerStateChanged = "devtools.debugger.remote-enabled";
 const debugServerPortChanged = "devtools.debugger.remote-port";
 
@@ -165,17 +162,16 @@ var BrowserUI = {
 
       messageManager.addMessageListener("Browser:MozApplicationManifest", OfflineApps);
 
       try {
         MetroDownloadsView.init();
         DialogUI.init();
         FormHelperUI.init();
         FindHelperUI.init();
-        LoginManagerParent.init();
 #ifdef NIGHTLY_BUILD
         PdfJs.init();
 #endif
       } catch(ex) {
         Util.dumpLn("Exception in delay load module:", ex.message);
       }
 
       BrowserUI._initFirstRunContent();
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -34,19 +34,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/devtools/dbg-server.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "UserAgentOverrides",
                                   "resource://gre/modules/UserAgentOverrides.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
                                   "resource://gre/modules/LoginManagerContent.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
-                                  "resource://gre/modules/LoginManagerParent.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
                                   "resource://gre/modules/SafeBrowsing.jsm");
 #endif
 
@@ -5392,18 +5389,16 @@ var FormAssistant = {
     Services.obs.addObserver(this, "invalidformsubmit", false);
     Services.obs.addObserver(this, "PanZoom:StateChange", false);
 
     // We need to use a capturing listener for focus events
     BrowserApp.deck.addEventListener("focus", this, true);
     BrowserApp.deck.addEventListener("click", this, true);
     BrowserApp.deck.addEventListener("input", this, false);
     BrowserApp.deck.addEventListener("pageshow", this, false);
-
-    LoginManagerParent.init();
   },
 
   uninit: function() {
     Services.obs.removeObserver(this, "FormAssist:AutoComplete");
     Services.obs.removeObserver(this, "FormAssist:Blocklisted");
     Services.obs.removeObserver(this, "FormAssist:Hidden");
     Services.obs.removeObserver(this, "invalidformsubmit");
     Services.obs.removeObserver(this, "PanZoom:StateChange");
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1,27 +1,22 @@
-/* vim: set ts=4 sts=4 sw=4 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-"use strict";
-
-this.EXPORTED_SYMBOLS = [ "LoginManagerContent",
-                          "UserAutoCompleteResult" ];
+this.EXPORTED_SYMBOLS = ["LoginManagerContent"];
 
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
 
 // These mirror signon.* prefs.
 var gEnabled, gDebug, gAutofillForms, gStoreWhenAutocompleteOff;
 
 function log(...pieces) {
     function generateLogMessage(args) {
         let strings = ['Login Manager (content):'];
 
@@ -62,17 +57,17 @@ var observer = {
         log("observer notified for form submission.");
 
         // We're invoked before the content's |onsubmit| handlers, so we
         // can grab form data before it might be modified (see bug 257781).
 
         try {
             LoginManagerContent._onFormSubmit(formElement);
         } catch (e) {
-            log("Caught error in onFormSubmit(", e.lineNumber, "):", e.message);
+            log("Caught error in onFormSubmit:", e);
         }
 
         return true; // Always return true, or form submit will be canceled.
     },
 
     onPrefChange : function() {
         gDebug = Services.prefs.getBoolPref("signon.debug");
         gEnabled = Services.prefs.getBoolPref("signon.rememberSignons");
@@ -83,180 +78,85 @@ var observer = {
 
 Services.obs.addObserver(observer, "earlyformsubmit", false);
 var prefBranch = Services.prefs.getBranch("signon.");
 prefBranch.addObserver("", observer.onPrefChange, false);
 
 observer.onPrefChange(); // read initial values
 
 
-function messageManagerFromWindow(win) {
-    return win.QueryInterface(Ci.nsIInterfaceRequestor)
-              .getInterface(Ci.nsIWebNavigation)
-              .QueryInterface(Ci.nsIDocShell)
-              .QueryInterface(Ci.nsIInterfaceRequestor)
-              .getInterface(Ci.nsIContentFrameMessageManager)
-}
-
-// This object maps to the "child" process (even in the single-process case).
 var LoginManagerContent = {
 
     __formFillService : null, // FormFillController, for username autocompleting
     get _formFillService() {
         if (!this.__formFillService)
             this.__formFillService =
                             Cc["@mozilla.org/satchel/form-fill-controller;1"].
                             getService(Ci.nsIFormFillController);
         return this.__formFillService;
     },
 
-    _getRandomId: function() {
-        return Cc["@mozilla.org/uuid-generator;1"]
-                 .getService(Ci.nsIUUIDGenerator).generateUUID().toString();
-    },
-
-    _messages: [ "RemoteLogins:loginsFound",
-                 "RemoteLogins:loginsAutoCompleted" ],
-
-    // Map from form login requests to information about that request.
-    _requests: new Map(),
-
-    // Number of outstanding requests to each manager.
-    _managers: new Map(),
-
-    _takeRequest: function(msg) {
-        let data = msg.data;
-        let request = this._requests.get(data.requestId);
-
-        this._requests.delete(data.requestId);
-
-        let count = this._managers.get(msg.target);
-        if (--count === 0) {
-            this._managers.delete(msg.target);
-
-            for (let message of this._messages)
-                msg.target.removeMessageListener(message, this);
-        } else {
-            this._managers.set(msg.target, count);
-        }
-
-        return request;
-    },
-
-    _sendRequest: function(messageManager, requestData,
-                           name, messageData) {
-        let count;
-        if (!(count = this._managers.get(messageManager))) {
-            this._managers.set(messageManager, 1);
-
-            for (let message of this._messages)
-                messageManager.addMessageListener(message, this);
-        } else {
-            this._managers.set(messageManager, ++count);
-        }
-
-        let requestId = this._getRandomId();
-        messageData.requestId = requestId;
-
-        messageManager.sendAsyncMessage(name, messageData);
-
-        let deferred = Promise.defer();
-        requestData.promise = deferred;
-        this._requests.set(requestId, requestData);
-        return deferred.promise;
-    },
-
-    receiveMessage: function (msg) {
-        let request = this._takeRequest(msg);
-        switch (msg.name) {
-            case "RemoteLogins:loginsFound": {
-                request.promise.resolve({ form: request.form,
-                                          loginsFound: msg.data.logins });
-                break;
-            }
-
-            case "RemoteLogins:loginsAutoCompleted": {
-                request.promise.resolve(msg.data.logins);
-                break;
-            }
-        }
-    },
-
-    _asyncFindLogins: function(form, options) {
-      let doc = form.ownerDocument;
-      let win = doc.defaultView;
-
-      let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
-      let actionOrigin = LoginUtils._getActionOrigin(form);
-
-      let messageManager = messageManagerFromWindow(win);
-
-      // XXX Weak??
-      let requestData = { form: form };
-      let messageData = { formOrigin: formOrigin,
-                          actionOrigin: actionOrigin,
-                          options: options };
-
-      return this._sendRequest(messageManager, requestData,
-                               "RemoteLogins:findLogins",
-                               messageData);
-    },
-
-    _autoCompleteSearchAsync: function(aSearchString, aPreviousResult,
-                                       aElement, aRect) {
-        let doc = aElement.ownerDocument;
-        let form = aElement.form;
-        let win = doc.defaultView;
-
-        let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
-        let actionOrigin = LoginUtils._getActionOrigin(form);
-
-        let messageManager = messageManagerFromWindow(win);
-
-        let remote = (Services.appinfo.processType ===
-                      Services.appinfo.PROCESS_TYPE_CONTENT);
-
-        let requestData = {};
-        let messageData = { formOrigin: formOrigin,
-                            actionOrigin: actionOrigin,
-                            searchString: aSearchString,
-                            previousResult: aPreviousResult,
-                            rect: aRect,
-                            remote: remote };
-
-        return this._sendRequest(messageManager, requestData,
-                                 "RemoteLogins:autoCompleteLogins",
-                                 messageData);
-    },
-
     /*
      * onFormPassword
      *
      * Called when an <input type="password"> element is added to the page
      */
     onFormPassword: function (event) {
       if (!event.isTrusted)
           return;
 
       if (!gEnabled)
           return;
 
       let form = event.target;
-      log("onFormPassword for", form.ownerDocument.documentURI);
-      this._asyncFindLogins(form, { showMasterPassword: true })
-          .then(this.loginsFound.bind(this))
-          .then(null, Cu.reportError);
+      let doc = form.ownerDocument;
+
+      log("onFormPassword for", doc.documentURI);
+
+      // If there are no logins for this site, bail out now.
+      let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+      if (!Services.logins.countLogins(formOrigin, "", null))
+          return;
+
+      // If we're currently displaying a master password prompt, defer
+      // processing this form until the user handles the prompt.
+      if (Services.logins.uiBusy) {
+        log("deferring onFormPassword for", doc.documentURI);
+        let self = this;
+        let observer = {
+            QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
+
+            observe: function (subject, topic, data) {
+                log("Got deferred onFormPassword notification:", topic);
+                // Only run observer once.
+                Services.obs.removeObserver(this, "passwordmgr-crypto-login");
+                Services.obs.removeObserver(this, "passwordmgr-crypto-loginCanceled");
+                if (topic == "passwordmgr-crypto-loginCanceled")
+                    return;
+                self.onFormPassword(event);
+            },
+            handleEvent : function (event) {
+                // Not expected to be called
+            }
+        };
+        // Trickyness follows: We want an observer, but don't want it to
+        // cause leaks. So add the observer with a weak reference, and use
+        // a dummy event listener (a strong reference) to keep it alive
+        // until the form is destroyed.
+        Services.obs.addObserver(observer, "passwordmgr-crypto-login", true);
+        Services.obs.addObserver(observer, "passwordmgr-crypto-loginCanceled", true);
+        form.addEventListener("mozCleverClosureHack", observer);
+        return;
+      }
+
+      let autofillForm = gAutofillForms && !PrivateBrowsingUtils.isWindowPrivate(doc.defaultView);
+
+      this._fillForm(form, autofillForm, false, false, false, null);
     },
 
-    loginsFound: function({ form, loginsFound }) {
-        let doc = form.ownerDocument;
-        let autofillForm = gAutofillForms && !PrivateBrowsingUtils.isWindowPrivate(doc.defaultView);
-
-        this._fillForm(form, autofillForm, false, false, false, loginsFound);
-    },
 
     /*
      * onUsernameInput
      *
      * Listens for DOMAutoComplete and blur events on an input field.
      */
     onUsernameInput : function(event) {
         if (!event.isTrusted)
@@ -286,21 +186,22 @@ var LoginManagerContent = {
 
         log("onUsernameInput from", event.type);
 
         // Make sure the username field fillForm will use is the
         // same field as the autocomplete was activated on.
         var [usernameField, passwordField, ignored] =
             this._getFormFields(acForm, false);
         if (usernameField == acInputField && passwordField) {
-            this._asyncFindLogins(acForm, { showMasterPassword: false })
-                .then(({ form, loginsFound }) => {
-                    this._fillForm(form, true, true, true, true, loginsFound);
-                })
-                .then(null, Cu.reportError);
+            // If the user has a master password but itsn't logged in, bail
+            // out now to prevent annoying prompts.
+            if (!Services.logins.isLoggedIn)
+                return;
+
+            this._fillForm(acForm, true, true, true, true, null);
         } else {
             // Ignore the event, it's for some input we don't care about.
         }
     },
 
 
     /*
      * _getPasswordFields
@@ -473,16 +374,25 @@ var LoginManagerContent = {
      * _onFormSubmit
      *
      * Called by the our observer when notified of a form submission.
      * [Note that this happens before any DOM onsubmit handlers are invoked.]
      * Looks for a password change in the submitted form, so we can update
      * our stored password.
      */
     _onFormSubmit : function (form) {
+
+        // For E10S this will need to move.
+        function getPrompter(aWindow) {
+            var prompterSvc = Cc["@mozilla.org/login-manager/prompter;1"].
+                              createInstance(Ci.nsILoginManagerPrompter);
+            prompterSvc.init(aWindow);
+            return prompterSvc;
+        }
+
         var doc = form.ownerDocument;
         var win = doc.defaultView;
 
         if (PrivateBrowsingUtils.isWindowPrivate(win)) {
             // We won't do anything in private browsing mode anyway,
             // so there's no need to perform further checks.
             log("(form submission ignored in private browsing mode)");
             return;
@@ -502,59 +412,140 @@ var LoginManagerContent = {
         // notification on about:accounts for Firefox.
         let topWin = win.top;
         if (/^about:accounts($|\?)/i.test(topWin.document.documentURI)) {
             log("(form submission ignored -- about:accounts)");
             return;
         }
 
         var formSubmitURL = LoginUtils._getActionOrigin(form)
+        if (!Services.logins.getLoginSavingEnabled(hostname)) {
+            log("(form submission ignored -- saving is disabled for:", hostname, ")");
+            return;
+        }
+
 
         // Get the appropriate fields from the form.
         var [usernameField, newPasswordField, oldPasswordField] =
             this._getFormFields(form, true);
 
         // Need at least 1 valid password field to do anything.
         if (newPasswordField == null)
-            return;
+                return;
 
         // Check for autocomplete=off attribute. We don't use it to prevent
         // autofilling (for existing logins), but won't save logins when it's
         // present and the storeWhenAutocompleteOff pref is false.
         // XXX spin out a bug that we don't update timeLastUsed in this case?
         if ((this._isAutocompleteDisabled(form) ||
              this._isAutocompleteDisabled(usernameField) ||
              this._isAutocompleteDisabled(newPasswordField) ||
              this._isAutocompleteDisabled(oldPasswordField)) &&
             !gStoreWhenAutocompleteOff) {
                 log("(form submission ignored -- autocomplete=off found)");
                 return;
         }
 
-        // Don't try to send DOM nodes over IPC.
-        let mockUsername = usernameField ?
-                             { name: usernameField.name,
-                               value: usernameField.value } :
-                             null;
-        let mockPassword = { name: newPasswordField.name,
-                             value: newPasswordField.value };
-        let mockOldPassword = oldPasswordField ?
-                                { name: oldPasswordField.name,
-                                  value: oldPasswordField.value } :
-                                null;
+
+        var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                        createInstance(Ci.nsILoginInfo);
+        formLogin.init(hostname, formSubmitURL, null,
+                    (usernameField ? usernameField.value : ""),
+                    newPasswordField.value,
+                    (usernameField ? usernameField.name  : ""),
+                    newPasswordField.name);
+
+        // If we didn't find a username field, but seem to be changing a
+        // password, allow the user to select from a list of applicable
+        // logins to update the password for.
+        if (!usernameField && oldPasswordField) {
+
+            var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
+
+            if (logins.length == 0) {
+                // Could prompt to save this as a new password-only login.
+                // This seems uncommon, and might be wrong, so ignore.
+                log("(no logins for this host -- pwchange ignored)");
+                return;
+            }
+
+            var prompter = getPrompter(win);
+
+            if (logins.length == 1) {
+                var oldLogin = logins[0];
+                formLogin.username      = oldLogin.username;
+                formLogin.usernameField = oldLogin.usernameField;
+
+                prompter.promptToChangePassword(oldLogin, formLogin);
+            } else {
+                prompter.promptToChangePasswordWithUsernames(
+                                    logins, logins.length, formLogin);
+            }
+
+            return;
+        }
+
+
+        // Look for an existing login that matches the form login.
+        var existingLogin = null;
+        var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
+
+        for (var i = 0; i < logins.length; i++) {
+            var same, login = logins[i];
 
-        let messageManager = messageManagerFromWindow(win);
-        messageManager.sendAsyncMessage("RemoteLogins:onFormSubmit",
-                                        { hostname: hostname,
-                                          formSubmitURL: formSubmitURL,
-                                          usernameField: mockUsername,
-                                          newPasswordField: mockPassword,
-                                          oldPasswordField: mockOldPassword });
+            // If one login has a username but the other doesn't, ignore
+            // the username when comparing and only match if they have the
+            // same password. Otherwise, compare the logins and match even
+            // if the passwords differ.
+            if (!login.username && formLogin.username) {
+                var restoreMe = formLogin.username;
+                formLogin.username = "";
+                same = formLogin.matches(login, false);
+                formLogin.username = restoreMe;
+            } else if (!formLogin.username && login.username) {
+                formLogin.username = login.username;
+                same = formLogin.matches(login, false);
+                formLogin.username = ""; // we know it's always blank.
+            } else {
+                same = formLogin.matches(login, true);
+            }
+
+            if (same) {
+                existingLogin = login;
+                break;
+            }
+        }
+
+        if (existingLogin) {
+            log("Found an existing login matching this form submission");
+
+            // Change password if needed.
+            if (existingLogin.password != formLogin.password) {
+                log("...passwords differ, prompting to change.");
+                prompter = getPrompter(win);
+                prompter.promptToChangePassword(existingLogin, formLogin);
+            } else {
+                // Update the lastUsed timestamp.
+                var propBag = Cc["@mozilla.org/hash-property-bag;1"].
+                              createInstance(Ci.nsIWritablePropertyBag);
+                propBag.setProperty("timeLastUsed", Date.now());
+                propBag.setProperty("timesUsedIncrement", 1);
+                Services.logins.modifyLogin(existingLogin, propBag);
+            }
+
+            return;
+        }
+
+
+        // Prompt user to save login (via dialog or notification bar)
+        prompter = getPrompter(win);
+        prompter.promptToSavePassword(formLogin);
     },
 
+
     /*
      * _fillform
      *
      * Fill the form with login information if we can find it. This will find
      * an array of logins if not given any, otherwise it will use the logins
      * passed in. The logins are returned so they can be reused for
      * optimization. Success of action is also returned in format
      * [success, foundLogins].
@@ -580,38 +571,40 @@ var LoginManagerContent = {
             return [false, foundLogins];
 
         // If the password field is disabled or read-only, there's nothing to do.
         if (passwordField.disabled || passwordField.readOnly) {
             log("not filling form, password field disabled or read-only");
             return [false, foundLogins];
         }
 
+        // Need to get a list of logins if we weren't given them
+        if (foundLogins == null) {
+            var formOrigin =
+                LoginUtils._getPasswordOrigin(form.ownerDocument.documentURI);
+            var actionOrigin = LoginUtils._getActionOrigin(form);
+            foundLogins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
+            log("found", foundLogins.length, "matching logins.");
+        } else {
+            log("reusing logins from last form.");
+        }
+
         // Discard logins which have username/password values that don't
         // fit into the fields (as specified by the maxlength attribute).
         // The user couldn't enter these values anyway, and it helps
         // with sites that have an extra PIN to be entered (bug 391514)
         var maxUsernameLen = Number.MAX_VALUE;
         var maxPasswordLen = Number.MAX_VALUE;
 
         // If attribute wasn't set, default is -1.
         if (usernameField && usernameField.maxLength >= 0)
             maxUsernameLen = usernameField.maxLength;
         if (passwordField.maxLength >= 0)
             maxPasswordLen = passwordField.maxLength;
 
-        foundLogins = foundLogins.map(login => {
-            var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
-                            createInstance(Ci.nsILoginInfo);
-            formLogin.init(login.hostname, login.formSubmitURL,
-                           login.httpRealm, login.username,
-                           login.password, login.usernameField,
-                           login.passwordField);
-            return formLogin;
-        });
         var logins = foundLogins.filter(function (l) {
                 var fit = (l.username.length <= maxUsernameLen &&
                            l.password.length <= maxPasswordLen);
                 if (!fit)
                     log("Ignored", l.username, "login: won't fit");
 
                 return fit;
             }, this);
@@ -794,17 +787,20 @@ var LoginManagerContent = {
         formInfo.setProperty("foundLogins", foundLogins.concat());
         formInfo.setPropertyAsInterface("selectedLogin", selectedLogin);
 
         Services.obs.notifyObservers(formInfo, "passwordmgr-found-logins", null);
     },
 
 };
 
-var LoginUtils = {
+
+
+
+LoginUtils = {
     /*
      * _getPasswordOrigin
      *
      * Get the parts of the URL we want for identification.
      */
     _getPasswordOrigin : function (uriString, allowJS) {
         var realm = "";
         try {
@@ -840,98 +836,8 @@ var LoginUtils = {
         // A blank or missing action submits to where it came from.
         if (uriString == "")
             uriString = form.baseURI; // ala bug 297761
 
         return this._getPasswordOrigin(uriString, true);
     },
 
 };
-
-// nsIAutoCompleteResult implementation
-function UserAutoCompleteResult (aSearchString, matchingLogins) {
-    function loginSort(a,b) {
-        var userA = a.username.toLowerCase();
-        var userB = b.username.toLowerCase();
-
-        if (userA < userB)
-            return -1;
-
-        if (userB > userA)
-            return  1;
-
-        return 0;
-    };
-
-    this.searchString = aSearchString;
-    this.logins = matchingLogins.sort(loginSort);
-    this.matchCount = matchingLogins.length;
-
-    if (this.matchCount > 0) {
-        this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
-        this.defaultIndex = 0;
-    }
-}
-
-UserAutoCompleteResult.prototype = {
-    QueryInterface : XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult,
-                                            Ci.nsISupportsWeakReference]),
-
-    // private
-    logins : null,
-
-    // Allow autoCompleteSearch to get at the JS object so it can
-    // modify some readonly properties for internal use.
-    get wrappedJSObject() {
-        return this;
-    },
-
-    // Interfaces from idl...
-    searchString : null,
-    searchResult : Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
-    defaultIndex : -1,
-    errorDescription : "",
-    matchCount : 0,
-
-    getValueAt : function (index) {
-        if (index < 0 || index >= this.logins.length)
-            throw "Index out of range.";
-
-        return this.logins[index].username;
-    },
-
-    getLabelAt: function(index) {
-        return this.getValueAt(index);
-    },
-
-    getCommentAt : function (index) {
-        return "";
-    },
-
-    getStyleAt : function (index) {
-        return "";
-    },
-
-    getImageAt : function (index) {
-        return "";
-    },
-
-    getFinalCompleteValueAt : function (index) {
-        return this.getValueAt(index);
-    },
-
-    removeValueAt : function (index, removeFromDB) {
-        if (index < 0 || index >= this.logins.length)
-            throw "Index out of range.";
-
-        var [removedLogin] = this.logins.splice(index, 1);
-
-        this.matchCount--;
-        if (this.defaultIndex > this.logins.length)
-            this.defaultIndex--;
-
-        if (removeFromDB) {
-            var pwmgr = Cc["@mozilla.org/login-manager;1"].
-                        getService(Ci.nsILoginManager);
-            pwmgr.removeLogin(removedLogin);
-        }
-    }
-};
deleted file mode 100644
--- a/toolkit/components/passwordmgr/LoginManagerParent.jsm
+++ /dev/null
@@ -1,321 +0,0 @@
-/* vim: set ts=4 sts=4 sw=4 et tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "UserAutoCompleteResult",
-                                  "resource://gre/modules/LoginManagerContent.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AutoCompleteE10S",
-                                  "resource://gre/modules/AutoCompleteE10S.jsm");
-
-this.EXPORTED_SYMBOLS = [ "LoginManagerParent" ];
-
-var gDebug;
-
-function log(...pieces) {
-    function generateLogMessage(args) {
-        let strings = ['Login Manager (parent):'];
-
-        args.forEach(function(arg) {
-            if (typeof arg === 'string') {
-                strings.push(arg);
-            } else if (typeof arg === 'undefined') {
-                strings.push('undefined');
-            } else if (arg === null) {
-                strings.push('null');
-            } else {
-                try {
-                  strings.push(JSON.stringify(arg, null, 2));
-                } catch(err) {
-                  strings.push("<<something>>");
-                }
-            }
-        });
-        return strings.join(' ');
-    }
-
-    if (!gDebug)
-        return;
-
-    let message = generateLogMessage(pieces);
-    dump(message + "\n");
-    Services.console.logStringMessage(message);
-}
-
-function prefChanged() {
-    gDebug = Services.prefs.getBoolPref("signon.debug");
-}
-
-Services.prefs.addObserver("signon.debug", prefChanged, false);
-prefChanged();
-
-var LoginManagerParent = {
-    init: function() {
-        let mm = Cc["@mozilla.org/globalmessagemanager;1"]
-                   .getService(Ci.nsIMessageListenerManager);
-        mm.addMessageListener("RemoteLogins:findLogins", this);
-        mm.addMessageListener("RemoteLogins:onFormSubmit", this);
-        mm.addMessageListener("RemoteLogins:autoCompleteLogins", this);
-    },
-
-    receiveMessage: function (msg) {
-        let data = msg.data;
-
-        switch (msg.name) {
-            case "RemoteLogins:findLogins": {
-                // TODO Verify msg.target's principals against the formOrigin?
-                this.findLogins(data.options.showMasterPassword,
-                                data.formOrigin,
-                                data.actionOrigin,
-                                data.requestId,
-                                msg.target.messageManager);
-                break;
-            }
-
-            case "RemoteLogins:onFormSubmit": {
-                // TODO Verify msg.target's principals against the formOrigin?
-                this.onFormSubmit(data.hostname,
-                                  data.formSubmitURL,
-                                  data.usernameField,
-                                  data.newPasswordField,
-                                  data.oldPasswordField,
-                                  msg.target);
-                break;
-            }
-
-            case "RemoteLogins:autoCompleteLogins": {
-                this.doAutocompleteSearch(data, msg.target);
-                break;
-            }
-        }
-    },
-
-    findLogins: function(showMasterPassword, formOrigin, actionOrigin,
-                         requestId, target) {
-        if (!showMasterPassword && !Services.logins.isLoggedIn) {
-            target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                    { requestId: requestId, logins: [] });
-            return;
-        }
-
-        // If there are no logins for this site, bail out now.
-        if (!Services.logins.countLogins(formOrigin, "", null)) {
-            target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                    { requestId: requestId, logins: [] });
-            return;
-        }
-
-        // If we're currently displaying a master password prompt, defer
-        // processing this form until the user handles the prompt.
-        if (Services.logins.uiBusy) {
-            log("deferring onFormPassword for", formOrigin);
-            let self = this;
-            let observer = {
-                QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                                       Ci.nsISupportsWeakReference]),
-
-                observe: function (subject, topic, data) {
-                    log("Got deferred onFormPassword notification:", topic);
-                    // Only run observer once.
-                    Services.obs.removeObserver(this, "passwordmgr-crypto-login");
-                    Services.obs.removeObserver(this, "passwordmgr-crypto-loginCanceled");
-                    if (topic == "passwordmgr-crypto-loginCanceled") {
-                        target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                                { requestId: requestId, logins: [] });
-                        return;
-                    }
-
-                    self.findLogins(showMasterPassword, formOrigin, actionOrigin,
-                                    requestId, target);
-                },
-            };
-
-            // Possible leak: it's possible that neither of these notifications
-            // will fire, and if that happens, we'll leak the observer (and
-            // never return). We should guarantee that at least one of these
-            // will fire.
-            // See bug XXX.
-            Services.obs.addObserver(observer, "passwordmgr-crypto-login", false);
-            Services.obs.addObserver(observer, "passwordmgr-crypto-loginCanceled", false);
-            return;
-        }
-
-        var logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
-        target.sendAsyncMessage("RemoteLogins:loginsFound",
-                                { requestId: requestId, logins: logins });
-    },
-
-    doAutocompleteSearch: function({ formOrigin, actionOrigin,
-                                     searchString, previousResult,
-                                     rect, requestId, remote }, target) {
-        // Note: previousResult is a regular object, not an
-        // nsIAutoCompleteResult.
-        var result;
-        var matchingLogins;
-
-        let searchStringLower = searchString.toLowerCase();
-        let logins;
-        if (previousResult &&
-            searchStringLower.startsWith(previousResult.searchString.toLowerCase())) {
-            log("Using previous autocomplete result");
-
-            // We have a list of results for a shorter search string, so just
-            // filter them further based on the new search string.
-            logins = previousResult.logins;
-        } else {
-            log("Creating new autocomplete search result.");
-
-            // Grab the logins from the database.
-            logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
-        }
-
-        let matchingLogins = logins.filter(function(fullMatch) {
-            let match = fullMatch.username;
-
-            // Remove results that are too short, or have different prefix.
-            // Also don't offer empty usernames as possible results.
-            return match && match.toLowerCase().startsWith(searchStringLower);
-        });
-
-        // XXX In the E10S case, we're responsible for showing our own
-        // autocomplete popup here because the autocomplete protocol hasn't
-        // been e10s-ized yet. In the non-e10s case, our caller is responsible
-        // for showing the autocomplete popup (via the regular
-        // nsAutoCompleteController).
-        if (remote) {
-            result = new UserAutoCompleteResult(searchString, matchingLogins);
-            AutoCompleteE10S.showPopupWithResults(target.ownerDocument.defaultView, rect, result);
-        }
-
-        target.messageManager.sendAsyncMessage("RemoteLogins:loginsAutoCompleted",
-                                               { requestId: requestId,
-                                                 logins: matchingLogins });
-    },
-
-    onFormSubmit: function(hostname, formSubmitURL,
-                           usernameField, newPasswordField,
-                           oldPasswordField,
-                           target) {
-        function getPrompter() {
-            var prompterSvc = Cc["@mozilla.org/login-manager/prompter;1"].
-                              createInstance(Ci.nsILoginManagerPrompter);
-            // XXX For E10S, we don't want to use the browser's contentWindow
-            // because it's in another process, so we use our chrome window as
-            // the window parent (the content process is responsible for
-            // making sure that its window is not in private browsing mode).
-            // In the same-process case, we can simply use the content window.
-            prompterSvc.init(target.isRemoteBrowser ?
-                                target.ownerDocument.defaultView :
-                                target.contentWindow);
-            return prompterSvc;
-        }
-
-        if (!Services.logins.getLoginSavingEnabled(hostname)) {
-            log("(form submission ignored -- saving is disabled for:", hostname, ")");
-            return;
-        }
-
-        var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
-                        createInstance(Ci.nsILoginInfo);
-        formLogin.init(hostname, formSubmitURL, null,
-                    (usernameField ? usernameField.value : ""),
-                    newPasswordField.value,
-                    (usernameField ? usernameField.name  : ""),
-                    newPasswordField.name);
-
-        // If we didn't find a username field, but seem to be changing a
-        // password, allow the user to select from a list of applicable
-        // logins to update the password for.
-        if (!usernameField && oldPasswordField) {
-
-            var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
-
-            if (logins.length == 0) {
-                // Could prompt to save this as a new password-only login.
-                // This seems uncommon, and might be wrong, so ignore.
-                log("(no logins for this host -- pwchange ignored)");
-                return;
-            }
-
-            var prompter = getPrompter();
-
-            if (logins.length == 1) {
-                var oldLogin = logins[0];
-                formLogin.username      = oldLogin.username;
-                formLogin.usernameField = oldLogin.usernameField;
-
-                prompter.promptToChangePassword(oldLogin, formLogin);
-            } else {
-                prompter.promptToChangePasswordWithUsernames(
-                                    logins, logins.length, formLogin);
-            }
-
-            return;
-        }
-
-
-        // Look for an existing login that matches the form login.
-        var existingLogin = null;
-        var logins = Services.logins.findLogins({}, hostname, formSubmitURL, null);
-
-        for (var i = 0; i < logins.length; i++) {
-            var same, login = logins[i];
-
-            // If one login has a username but the other doesn't, ignore
-            // the username when comparing and only match if they have the
-            // same password. Otherwise, compare the logins and match even
-            // if the passwords differ.
-            if (!login.username && formLogin.username) {
-                var restoreMe = formLogin.username;
-                formLogin.username = "";
-                same = formLogin.matches(login, false);
-                formLogin.username = restoreMe;
-            } else if (!formLogin.username && login.username) {
-                formLogin.username = login.username;
-                same = formLogin.matches(login, false);
-                formLogin.username = ""; // we know it's always blank.
-            } else {
-                same = formLogin.matches(login, true);
-            }
-
-            if (same) {
-                existingLogin = login;
-                break;
-            }
-        }
-
-        if (existingLogin) {
-            log("Found an existing login matching this form submission");
-
-            // Change password if needed.
-            if (existingLogin.password != formLogin.password) {
-                log("...passwords differ, prompting to change.");
-                prompter = getPrompter();
-                prompter.promptToChangePassword(existingLogin, formLogin);
-            } else {
-                // Update the lastUsed timestamp.
-                var propBag = Cc["@mozilla.org/hash-property-bag;1"].
-                              createInstance(Ci.nsIWritablePropertyBag);
-                propBag.setProperty("timeLastUsed", Date.now());
-                propBag.setProperty("timesUsedIncrement", 1);
-                Services.logins.modifyLogin(existingLogin, propBag);
-            }
-
-            return;
-        }
-
-
-        // Prompt user to save login (via dialog or notification bar)
-        prompter = getPrompter();
-        prompter.promptToSavePassword(formLogin);
-    }
-};
--- a/toolkit/components/passwordmgr/moz.build
+++ b/toolkit/components/passwordmgr/moz.build
@@ -30,17 +30,16 @@ EXTRA_PP_COMPONENTS += [
     'nsLoginManager.js',
     'passwordmgr.manifest',
 ]
 
 EXTRA_JS_MODULES += [
     'InsecurePasswordUtils.jsm',
     'LoginHelper.jsm',
     'LoginManagerContent.jsm',
-    'LoginManagerParent.jsm',
 ]
 
 if CONFIG['OS_TARGET'] == 'Android':
     EXTRA_COMPONENTS += [
         'storage-mozStorage.js',
     ]
 else:
     EXTRA_COMPONENTS += [
--- a/toolkit/components/passwordmgr/nsILoginManager.idl
+++ b/toolkit/components/passwordmgr/nsILoginManager.idl
@@ -8,17 +8,17 @@
 interface nsIURI;
 interface nsILoginInfo;
 interface nsIAutoCompleteResult;
 interface nsIFormAutoCompleteObserver;
 interface nsIDOMHTMLInputElement;
 interface nsIDOMHTMLFormElement;
 interface nsIPropertyBag;
 
-[scriptable, uuid(f0c5ca21-db71-4b32-993e-ab63054cc6f5)]
+[scriptable, uuid(f441b0a3-6588-455e-baa8-2e2dbba84655)]
 interface nsILoginManager : nsISupports {
     /**
      * This promise is resolved when initialization is complete, and is rejected
      * in case initialization failed.  This includes the initial loading of the
      * login data as well as any migration from previous versions.
      *
      * Calling any method of nsILoginManager before this promise is resolved
      * might trigger the synchronous initialization fallback.
@@ -216,19 +216,19 @@ interface nsILoginManager : nsISupports 
                                  in nsIFormAutoCompleteObserver aListener);
 
     /**
      * Fill a form with login information if we have it. This method will fill
      * aForm regardless of the signon.autofillForms preference.
      *
      * @param aForm
      *        The form to fill
-     * @return Promise that is resolved with whether or not the form was filled.
+     * @return Success of attempt fill form
      */
-    jsval fillForm(in nsIDOMHTMLFormElement aForm);
+    boolean fillForm(in nsIDOMHTMLFormElement aForm);
 
     /**
      * Search for logins in the login manager. An array is always returned;
      * if there are no logins the array is empty.
      *
      * @param count
      *        The number of elements in the array. JS callers can simply use
      *        the array's .length property, and supply an dummy object for
--- a/toolkit/components/passwordmgr/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/nsLoginManager.js
@@ -1,29 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
-const Cu = Components.utils;
 
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
-Cu.import("resource://gre/modules/LoginManagerContent.jsm");
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/Timer.jsm");
+Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
+                                  "resource://gre/modules/LoginManagerContent.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
-                                  "resource://gre/modules/BrowserUtils.jsm");
 
 var debug = false;
 function log(...pieces) {
     function generateLogMessage(args) {
         let strings = ['Login Manager:'];
 
         args.forEach(function(arg) {
             if (typeof arg === 'string') {
@@ -114,27 +112,21 @@ LoginManager.prototype = {
 
         // Get current preference values.
         debug = this._prefBranch.getBoolPref("debug");
 
         this._remember = this._prefBranch.getBoolPref("rememberSignons");
 
         // Form submit observer checks forms for new logins and pw changes.
         Services.obs.addObserver(this._observer, "xpcom-shutdown", false);
+        Services.obs.addObserver(this._observer, "passwordmgr-storage-replace",
+                                 false);
 
-        // TODO: Make this class useful in the child process (in addition to
-        // autoCompleteSearchAsync and fillForm).
-        if (Services.appinfo.processType ===
-            Services.appinfo.PROCESS_TYPE_DEFAULT) {
-            Services.obs.addObserver(this._observer, "passwordmgr-storage-replace",
-                                     false);
-
-            // Initialize storage so that asynchronous data loading can start.
-            this._initStorage();
-        }
+        // Initialize storage so that asynchronous data loading can start.
+        this._initStorage();
     },
 
 
     _initStorage : function () {
 #ifdef ANDROID
         var contractID = "@mozilla.org/login-manager/storage/mozStorage;1";
 #else
         var contractID = "@mozilla.org/login-manager/storage/json;1";
@@ -424,45 +416,85 @@ LoginManager.prototype = {
      * nsFormFillController::StartSearch()
      * [toolkit/components/satchel/nsFormFillController.cpp]
      *
      * We really ought to have a simple way for code to register an
      * auto-complete provider, and not have satchel calling pwmgr directly.
      */
     autoCompleteSearchAsync : function (aSearchString, aPreviousResult,
                                         aElement, aCallback) {
-        // aPreviousResult is an nsIAutoCompleteResult, aElement is
-        // nsIDOMHTMLInputElement
+        // aPreviousResult & aResult are nsIAutoCompleteResult,
+        // aElement is nsIDOMHTMLInputElement
 
         if (!this._remember) {
             setTimeout(function() {
                 aCallback.onSearchCompletion(new UserAutoCompleteResult(aSearchString, []));
             }, 0);
             return;
         }
 
         log("AutoCompleteSearch invoked. Search is:", aSearchString);
 
-        var previousResult;
-        if (aPreviousResult) {
-            previousResult = { searchString: aPreviousResult.searchString,
-                               logins: aPreviousResult.wrappedJSObject.logins };
+        if (aPreviousResult &&
+                aSearchString.substr(0, aPreviousResult.searchString.length) == aPreviousResult.searchString) {
+            log("Using previous autocomplete result");
+            let result = aPreviousResult;
+            result.wrappedJSObject.searchString = aSearchString;
+
+            // We have a list of results for a shorter search string, so just
+            // filter them further based on the new search string.
+            // Count backwards, because result.matchCount is decremented
+            // when we remove an entry.
+            for (var i = result.matchCount - 1; i >= 0; i--) {
+                var match = result.getValueAt(i);
+
+                // Remove results that are too short, or have different prefix.
+                if (aSearchString.length > match.length ||
+                    aSearchString.toLowerCase() !=
+                        match.substr(0, aSearchString.length).toLowerCase())
+                {
+                    log("Removing autocomplete entry:", match);
+                    result.removeValueAt(i, false);
+                }
+            }
+
+            setTimeout(function() { aCallback.onSearchCompletion(result); }, 0);
         } else {
-            previousResult = null;
-        }
+            log("Creating new autocomplete search result.");
 
-        let rect = BrowserUtils.getElementBoundingScreenRect(aElement);
-        LoginManagerContent._autoCompleteSearchAsync(aSearchString, previousResult,
-                                                     aElement, rect)
-                           .then(function(logins) {
-                               let results =
-                                   new UserAutoCompleteResult(aSearchString, logins);
-                               aCallback.onSearchCompletion(results);
-                           })
-                           .then(null, Cu.reportError);
+            setTimeout(function() {
+                var doc = aElement.ownerDocument;
+                var origin = this._getPasswordOrigin(doc.documentURI);
+                var actionOrigin = this._getActionOrigin(aElement.form);
+
+                // This shouldn't trigger a master password prompt, because we
+                // don't attach to the input until after we successfully obtain
+                // logins for the form.
+                var logins = this.findLogins({}, origin, actionOrigin, null);
+                var matchingLogins = [];
+
+                // Filter out logins that don't match the search prefix. Also
+                // filter logins without a username, since that's confusing to see
+                // in the dropdown and we can't autocomplete them anyway.
+                for (let i = 0; i < logins.length; i++) {
+                    var username = logins[i].username.toLowerCase();
+                    log(username);
+                    if (username &&
+                        aSearchString.length <= username.length &&
+                        aSearchString.toLowerCase() ==
+                            username.substr(0, aSearchString.length))
+                    {
+                        matchingLogins.push(logins[i]);
+                    }
+                }
+                log(matchingLogins.length, "autocomplete logins avail.");
+                aCallback.onSearchCompletion(new UserAutoCompleteResult(aSearchString,
+                                                                        matchingLogins));
+            }.bind(this), 0);
+        }
     },
 
 
     /* ------- Internal methods / callbacks for document integration ------- */
 
 
     /*
      * _getPasswordOrigin
@@ -511,18 +543,107 @@ LoginManager.prototype = {
 
     /*
      * fillForm
      *
      * Fill the form with login information if we can find it.
      */
     fillForm : function (form) {
         log("fillForm processing form[ id:", form.id, "]");
-        return LoginManagerContent._asyncFindLogins(form, { showMasterPassword: true })
-                                  .then(function({ form, loginsFound }) {
-                   return LoginManagerContent._fillForm(form, true, true,
-                                                        false, false, loginsFound)[0];
-               });
+        return LoginManagerContent._fillForm(form, true, true, false, false, null)[0];
     },
 
 }; // end of LoginManager implementation
 
+
+
+
+// nsIAutoCompleteResult implementation
+function UserAutoCompleteResult (aSearchString, matchingLogins) {
+    function loginSort(a,b) {
+        var userA = a.username.toLowerCase();
+        var userB = b.username.toLowerCase();
+
+        if (userA < userB)
+            return -1;
+
+        if (userB > userA)
+            return  1;
+
+        return 0;
+    };
+
+    this.searchString = aSearchString;
+    this.logins = matchingLogins.sort(loginSort);
+    this.matchCount = matchingLogins.length;
+
+    if (this.matchCount > 0) {
+        this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
+        this.defaultIndex = 0;
+    }
+}
+
+UserAutoCompleteResult.prototype = {
+    QueryInterface : XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult,
+                                            Ci.nsISupportsWeakReference]),
+
+    // private
+    logins : null,
+
+    // Allow autoCompleteSearch to get at the JS object so it can
+    // modify some readonly properties for internal use.
+    get wrappedJSObject() {
+        return this;
+    },
+
+    // Interfaces from idl...
+    searchString : null,
+    searchResult : Ci.nsIAutoCompleteResult.RESULT_NOMATCH,
+    defaultIndex : -1,
+    errorDescription : "",
+    matchCount : 0,
+
+    getValueAt : function (index) {
+        if (index < 0 || index >= this.logins.length)
+            throw "Index out of range.";
+
+        return this.logins[index].username;
+    },
+
+    getLabelAt: function(index) {
+        return this.getValueAt(index);
+    },
+
+    getCommentAt : function (index) {
+        return "";
+    },
+
+    getStyleAt : function (index) {
+        return "";
+    },
+
+    getImageAt : function (index) {
+        return "";
+    },
+
+    getFinalCompleteValueAt : function (index) {
+        return this.getValueAt(index);
+    },
+
+    removeValueAt : function (index, removeFromDB) {
+        if (index < 0 || index >= this.logins.length)
+            throw "Index out of range.";
+
+        var [removedLogin] = this.logins.splice(index, 1);
+
+        this.matchCount--;
+        if (this.defaultIndex > this.logins.length)
+            this.defaultIndex--;
+
+        if (removeFromDB) {
+            var pwmgr = Cc["@mozilla.org/login-manager;1"].
+                        getService(Ci.nsILoginManager);
+            pwmgr.removeLogin(removedLogin);
+        }
+    }
+};
+
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([LoginManager]);
--- a/toolkit/components/passwordmgr/test/pwmgr_common.js
+++ b/toolkit/components/passwordmgr/test/pwmgr_common.js
@@ -123,20 +123,17 @@ function doKey(aKey, modifier) {
 
     if (wutils.sendKeyEvent("keydown",  key, 0, modifier)) {
       wutils.sendKeyEvent("keypress", key, 0, modifier);
     }
     wutils.sendKeyEvent("keyup",    key, 0, modifier);
 }
 
 // Init with a common login
-// If selfFilling is true or non-undefined, fires an event at the page so that
-// the test can start checking filled-in values. Tests that check observer
-// notifications might be confused by this.
-function commonInit(selfFilling) {
+function commonInit() {
     var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"].
                 getService(SpecialPowers.Ci.nsILoginManager);
     ok(pwmgr != null, "Access LoginManager");
 
 
     // Check that initial state has no logins
     var logins = pwmgr.getAllLogins();
     if (logins.length) {
@@ -157,51 +154,16 @@ function commonInit(selfFilling) {
                "testuser", "testpass", "uname", "pword");
     pwmgr.addLogin(login);
 
     // Last sanity check
     logins = pwmgr.getAllLogins();
     is(logins.length, 1, "Checking for successful init login");
     disabledHosts = pwmgr.getAllDisabledHosts();
     is(disabledHosts.length, 0, "Checking for no disabled hosts");
-
-    if (selfFilling)
-        return;
-
-    // We provide a general mechanism for our tests to know when they can
-    // safely run: we add a final form that we know will be filled in, wait
-    // for the login manager to tell us that it's filled in and then continue
-    // with the rest of the tests.
-    window.addEventListener("DOMContentLoaded", (event) => {
-        var form = document.createElement('form');
-        form.id = 'observerforcer';
-        var username = document.createElement('input');
-        username.name = 'testuser';
-        form.appendChild(username);
-        var password = document.createElement('input');
-        password.name = 'testpass';
-        password.type = 'password';
-        form.appendChild(password);
-
-        var observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
-            var bag = subject.QueryInterface(SpecialPowers.Ci.nsIPropertyBag2);
-            var username = bag.get("usernameField");
-            if (!username || username.form.id !== 'observerforcer')
-                return;
-            SpecialPowers.removeObserver(observer, "passwordmgr-found-logins");
-            form.parentNode.removeChild(form);
-            SimpleTest.executeSoon(() => {
-                var event = new Event("runTests");
-                window.dispatchEvent(event);
-            });
-        });
-        SpecialPowers.addObserver(observer, "passwordmgr-found-logins", false);
-
-        document.body.appendChild(form);
-    });
 }
 
 const masterPassword = "omgsecret!";
 
 function enableMasterPassword() {
     setMasterPassword(true);
 }
 
--- a/toolkit/components/passwordmgr/test/subtst_privbrowsing_3.html
+++ b/toolkit/components/passwordmgr/test/subtst_privbrowsing_3.html
@@ -14,14 +14,14 @@
   <button type='submit'>Submit</button>
 </form>
 
 <script>
 function submitForm() {
   form.submit();
 }
 
+window.onload = submitForm;
 var form      = document.getElementById("form");
-window.addEventListener('message', () => { submitForm(); });
 
 </script>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/subtst_privbrowsing_4.html
+++ b/toolkit/components/passwordmgr/test/subtst_privbrowsing_4.html
@@ -23,16 +23,15 @@ function startAutocomplete() {
 }
 
 function submitForm() {
   doKey("down");
   doKey("return");
   setTimeout(function(){ form.submit(); }, 100);
 }
 
+window.onload = startAutocomplete;
 var form      = document.getElementById("form");
 var userField = document.getElementById("user");
 
-window.addEventListener('message', () => { startAutocomplete(); });
-
 </script>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form.html
@@ -17,17 +17,17 @@ SimpleTest.waitForExplicitFinish();
 
 function startTest() {
   is($_(1, "uname").value, "testuser", "Checking for filled username");
   is($_(1, "pword").value, "testpass", "Checking for filled password");
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 
 <p id="display"></p>
 
 <div id="content" style="display: none">
 
   <form id="form1" action="formtest.js">
     <p>This is form 1.</p>
--- a/toolkit/components/passwordmgr/test/test_basic_form_0pw.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_0pw.html
@@ -60,16 +60,16 @@ commonInit();
 function startTest() {
   is($_(3, "uname").value, "", "Checking for unfilled checkbox (form 3)");
   is($_(4, "yyyyy").value, "", "Checking for unfilled text field (form 4)");
   is($_(5, "uname").value, "", "Checking for unfilled text field (form 5)");
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_basic_form_1pw.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_1pw.html
@@ -156,15 +156,15 @@ function startTest() {
     checkForm(f++, "testpass", "xxxxxxxx");
     checkForm(f++, "xxxxxxxx", "testuser", "testpass");
     checkForm(f++, "testuser", "testpass", "xxxxxxxx");
 
     SimpleTest.finish();
 }
 
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_1pw_2.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_1pw_2.html
@@ -97,16 +97,16 @@ function startTest() {
     checkForm(9, "testuser", "testpass");
     checkForm(10, "TESTUSER", "testpass");
     checkForm(11, "TESTUSER", "testpass");
 
     SimpleTest.finish();
 }
 
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_basic_form_2.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_2.html
@@ -39,28 +39,26 @@ SpecialPowers.setBoolPref("signon.autofi
 /** Test for Login Manager: simple form fill with autofillForms disabled **/
 
 function startTest(){
   // Ensure the form is empty at start
   is($_(1, "uname").value, "", "Checking for blank username");
   is($_(1, "pword").value, "", "Checking for blank password");
 
   // Call the public method, check return value
-  pwmgr.fillForm(document.getElementById("form1"))
-       .then(function(result) {
-         is(result, true, "Checking return value of fillForm");
+  is(pwmgr.fillForm(document.getElementById("form1")), true,
+     "Checking return value of fillForm");
 
-         // Check that the form was filled
-         is($_(1, "uname").value, "testuser", "Checking for filled username");
-         is($_(1, "pword").value, "testpass", "Checking for filled password");
+  // Check that the form was filled
+  is($_(1, "uname").value, "testuser", "Checking for filled username");
+  is($_(1, "pword").value, "testpass", "Checking for filled password");
 
-         // Reset pref (since we assumed it was true to start)
-         SpecialPowers.setBoolPref("signon.autofillForms", true);
+  // Reset pref (since we assumed it was true to start)
+  SpecialPowers.setBoolPref("signon.autofillForms", true);
 
-         SimpleTest.finish();
-       });
+  SimpleTest.finish();
 }
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_2pw_1.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_2pw_1.html
@@ -177,16 +177,16 @@ function startTest() {
     checkForm(f++, "",         "xxxxxxxx", "testpass");
     checkForm(f++, "testpass", "",         "");
     checkForm(f++, "xxxxxxxx", "",         "");
 
     SimpleTest.finish();
 }
 
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_basic_form_2pw_2.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_2pw_2.html
@@ -5,16 +5,28 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
   <script type="text/javascript" src="pwmgr_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Login Manager test: (placeholder)
 <p id="display"></p>
 
+<div id="content" style="display: none">
+  <form id="form1" onsubmit="return checkSubmit(1)" action="http://newuser.com">
+    <input  type="text"     name="uname">
+    <input  type="password" name="pword">
+    <input  type="password" name="qword">
+
+    <button type="submit">Submit</button>
+    <button type="reset"> Reset </button>
+  </form>
+
+</div>
+
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: form fill, 2 password fields **/
 
 /*
  * If a form has two password fields, other things may be going on....
  *
@@ -101,28 +113,16 @@ ok(Cc_pwmgr != null, "Access Cc[@mozilla
 
 var Ci_pwmgr = SpecialPowers.Ci.nsILoginManager;
 ok(Ci_pwmgr != null, "Access Ci.nsILoginManager");
 
 var pwmgr = Cc_pwmgr.getService(Ci_pwmgr);
 ok(pwmgr != null, "pwmgr getService()");
 
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
-<div id="content" style="display: none">
-  <form id="form1" onsubmit="return checkSubmit(1)" action="http://newuser.com">
-    <input  type="text"     name="uname">
-    <input  type="password" name="pword">
-    <input  type="password" name="qword">
-
-    <button type="submit">Submit</button>
-    <button type="reset"> Reset </button>
-  </form>
-
-</div>
-
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_basic_form_3pw_1.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_3pw_1.html
@@ -164,16 +164,16 @@ function startTest() {
   is($_(9, "rword").value, "",         "Checking password 9 (r)");
   is($_(9, "pword").value, "testpass", "Checking password 9");
 
   // TODO: as with the 2-password cases, add tests to check for creating new
   // logins and changing passwords.
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
@@ -159,17 +159,16 @@ try {
   </form>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: multiple login autocomplete. **/
 
-var tester;
 
 var uname = $_(1, "uname");
 var pword = $_(1, "pword");
 const shiftModifier = SpecialPowers.Ci.nsIDOMEvent.SHIFT_MASK;
 
 // Restore the form to the default state.
 function restoreForm() {
     uname.value = "";
@@ -195,588 +194,583 @@ function sendFakeAutocompleteEvent(eleme
 function hitEventLoop(func, times) {
   if (times > 0) {
     setTimeout(hitEventLoop, 0, func, times - 1);
   } else {
     setTimeout(func, 0);
   }
 }
 
+var gNextTestWillOpenPopup = true;
+var gLastTest = 704;
+
 function addPopupListener(eventName, func, capture) {
   autocompletePopup.addEventListener(eventName, func, capture);
 }
 
 function removePopupListener(eventName, func, capture) {
   autocompletePopup.removeEventListener(eventName, func, capture);
 }
 
 /*
  * Main section of test...
  *
- * This test is, to a first approximation, event driven. Each time we need to
- * wait for an event, runTest sets an event listener (or timeout for a couple
- * of rare cases) and yields. The event listener then resumes the generator by
- * calling its |next| method.
+ * This is a bit hacky, because the events are either being sent or
+ * processes asynchronously, so we need to interrupt our flow with lots of
+ * setTimeout() calls. The case statements are executed in order, one per
+ * timeout.
  */
-function* runTest() {
-  var testNum = 1;
+function runTest(testNum) {
   ok(true, "Starting test #" + testNum);
 
-  function waitForPopup() {
-    addPopupListener("popupshown", function popupshown() {
-      removePopupListener("popupshown", popupshown, false);
-
-      window.setTimeout(tester.next.bind(tester), 0);
-    }, false);
-  }
+  if (gNextTestWillOpenPopup) {
+    addPopupListener("popupshown", function() {
+      removePopupListener("popupshown", arguments.callee, false);
 
-  function runNextTest(expectPopup) {
-    var save = testNum++;
-    if (expectPopup === "expect popup")
-      return waitForPopup();
+      if (testNum != gLastTest) {
+        window.setTimeout(runTest, 0, testNum + 1);
+      }
+    }, false);
+  } else {
+    var unexpectedPopup = function() {
+      removePopupListener("popupshown", arguments.callee, false);
 
-    var unexpectedPopup = function() {
-      removePopupListener("popupshown", unexpectedPopup, false);
-      ok(false, "Test " + save + " should not show a popup");
+      ok(false, "Test " + testNum + " should not show a popup");
     };
     addPopupListener("popupshown", unexpectedPopup, false);
-
-    hitEventLoop(function() {
+    if (testNum == gLastTest) {
       removePopupListener("popupshown", unexpectedPopup, false);
-      tester.next();
-    }, 100);
-  }
-
-  // We use this function when we're trying to prove that something doesn't
-  // happen, but where if it did it would do so asynchronously. It isn't
-  // perfect, but it's better than nothing.
-  function spinEventLoop() {
-    setTimeout(function() { tester.next(); }, 0);
-  }
-
-  function waitForCompletion() {
-    var observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
-      SpecialPowers.removeObserver(observer, "passwordmgr-found-logins");
-      tester.next();
-    });
-    SpecialPowers.addObserver(observer, "passwordmgr-found-logins", false);
+    } else {
+      hitEventLoop(function() {
+        removePopupListener("popupshown", unexpectedPopup, false);
+        runTest(testNum + 1);
+      }, 100);
+    }
   }
 
-  /* test 1 */
-  // Make sure initial form is empty.
-  checkACForm("", "");
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+  switch(testNum) {
+    case 1:
+        // Make sure initial form is empty.
+        checkACForm("", "");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 2 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("tempuser1", "temppass1");
-
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+    case 2:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        checkACForm("tempuser1", "temppass1");
 
-  /* test 3 */
-  // Check second entry
-  doKey("down");
-  doKey("down");
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("testuser2", "testpass2");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
+
+    case 3:
+        // Check second entry
+        doKey("down");
+        doKey("down");
+        doKey("return"); // not "enter"!
+        checkACForm("testuser2", "testpass2");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 4 */
-  // Check third entry
-  doKey("down");
-  doKey("down");
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("testuser3", "testpass3");
+    case 4:
+        // Check third entry
+        doKey("down");
+        doKey("down");
+        doKey("down");
+        doKey("return");
+        checkACForm("testuser3", "testpass3");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 5 */
-  // Check fourth entry
-  doKey("down");
-  doKey("down");
-  doKey("down");
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("zzzuser4", "zzzpass4");
+    case 5:
+        // Check fourth entry
+        doKey("down");
+        doKey("down");
+        doKey("down");
+        doKey("down");
+        doKey("return");
+        checkACForm("zzzuser4", "zzzpass4");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 6 */
-  // Check first entry (wraparound)
-  doKey("down");
-  doKey("down");
-  doKey("down");
-  doKey("down");
-  doKey("down"); // deselects
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("tempuser1", "temppass1");
+    case 6:
+        // Check first entry (wraparound)
+        doKey("down");
+        doKey("down");
+        doKey("down");
+        doKey("down");
+        doKey("down"); // deselects
+        doKey("down");
+        doKey("return");
+        checkACForm("tempuser1", "temppass1");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 7 */
-  // Check the last entry via arrow-up
-  doKey("up");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("zzzuser4", "zzzpass4");
+    case 7:
+        // Check the last entry via arrow-up
+        doKey("up");
+        doKey("return");
+        checkACForm("zzzuser4", "zzzpass4");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 8 */
-  // Check the last entry via arrow-up
-  doKey("down"); // select first entry
-  doKey("up");   // selects nothing!
-  doKey("up");   // select last entry
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("zzzuser4", "zzzpass4");
+    case 8:
+        // Check the last entry via arrow-up
+        doKey("down"); // select first entry
+        doKey("up");   // selects nothing!
+        doKey("up");   // select last entry
+        doKey("return");
+        checkACForm("zzzuser4", "zzzpass4");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 9 */
-  // Check the last entry via arrow-up (wraparound)
-  doKey("down");
-  doKey("up"); // deselects
-  doKey("up"); // last entry
-  doKey("up");
-  doKey("up");
-  doKey("up"); // first entry
-  doKey("up"); // deselects
-  doKey("up"); // last entry
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("zzzuser4", "zzzpass4");
+    case 9:
+        // Check the last entry via arrow-up (wraparound)
+        doKey("down");
+        doKey("up"); // deselects
+        doKey("up"); // last entry
+        doKey("up");
+        doKey("up");
+        doKey("up"); // first entry
+        doKey("up"); // deselects
+        doKey("up"); // last entry
+        doKey("return");
+        checkACForm("zzzuser4", "zzzpass4");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
+
+    case 10:
+        // Set first entry w/o triggering autocomplete
+        doKey("down");
+        doKey("right");
+        checkACForm("tempuser1", ""); // empty password
 
-  /* test 10 */
-  // Set first entry w/o triggering autocomplete
-  doKey("down");
-  doKey("right");
-  yield spinEventLoop();
-  checkACForm("tempuser1", ""); // empty password
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+    case 11:
+        // Set first entry w/o triggering autocomplete
+        doKey("down");
+        doKey("left");
+        checkACForm("tempuser1", ""); // empty password
 
-  /* test 11 */
-  // Set first entry w/o triggering autocomplete
-  doKey("down");
-  doKey("left");
-  checkACForm("tempuser1", ""); // empty password
-
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 12 */
-  // Check first entry (page up)
-  doKey("down");
-  doKey("down");
-  doKey("page_up");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("tempuser1", "temppass1");
+    case 12:
+        // Check first entry (page up)
+        doKey("down");
+        doKey("down");
+        doKey("page_up");
+        doKey("return");
+        checkACForm("tempuser1", "temppass1");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 13 */
-  // Check last entry (page down)
-  doKey("down");
-  doKey("page_down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("zzzuser4", "zzzpass4");
-  restoreForm();
-  yield runNextTest();
+    case 13:
+        // Check last entry (page down)
+        doKey("down");
+        doKey("page_down");
+        doKey("return");
+        checkACForm("zzzuser4", "zzzpass4");
+        restoreForm();
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 14 */
-  // Send a fake (untrusted) event.
-  checkACForm("", "");
-  uname.value = "zzzuser4";
-  sendFakeAutocompleteEvent(uname);
-  yield spinEventLoop();
-  checkACForm("zzzuser4", "");
+    case 14:
+        // Send a fake (untrusted) event.
+        checkACForm("", "");
+        uname.value = "zzzuser4";
+        sendFakeAutocompleteEvent(uname);
+        checkACForm("zzzuser4", "");
+        gNextTestWillOpenPopup = true;
+        break;
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  testNum = 49;
-  yield runNextTest("expect popup");
+    case 15:
+        //checkACForm("zzzuser4", "");
 
-  // XXX tried sending character "t" before/during dropdown to test
-  // filtering, but had no luck. Seemed like the character was getting lost.
-  // Setting uname.value didn't seem to work either. This works with a human
-  // driver, so I'm not sure what's up.
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        testNum = 49;
+        break;
+
+    // XXX tried sending character "t" before/during dropdown to test
+    // filtering, but had no luck. Seemed like the character was getting lost.
+    // Setting uname.value didn't seem to work either. This works with a human
+    // driver, so I'm not sure what's up.
 
 
-  /* test 50 */
-  // Delete the first entry (of 4), "tempuser1"
-  doKey("down");
-  var numLogins;
-  numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
-  is(numLogins, 5, "Correct number of logins before deleting one");
+    case 50:
+        // Delete the first entry (of 4), "tempuser1"
+        doKey("down");
+        var numLogins;
+        numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
+        is(numLogins, 5, "Correct number of logins before deleting one");
 
-  // On OS X, shift-backspace and shift-delete work, just delete does not.
-  // On Win/Linux, shift-backspace does not work, delete and shift-delete do.
-  doKey("delete", shiftModifier);
+        // On OS X, shift-backspace and shift-delete work, just delete does not.
+        // On Win/Linux, shift-backspace does not work, delete and shift-delete do.
+        doKey("delete", shiftModifier);
 
-  checkACForm("", "");
-  numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
-  is(numLogins, 4, "Correct number of logins after deleting one");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("testuser2", "testpass2");
+        checkACForm("", "");
+        numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
+        is(numLogins, 4, "Correct number of logins after deleting one");
+        doKey("return");
+        checkACForm("testuser2", "testpass2");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 51 */
-  // Check the new first entry (of 3)
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("testuser2", "testpass2");
+    case 51:
+        // Check the new first entry (of 3)
+        doKey("down");
+        doKey("return");
+        checkACForm("testuser2", "testpass2");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 52 */
-  // Delete the second entry (of 3), "testuser3"
-  doKey("down");
-  doKey("down");
-  doKey("delete", shiftModifier);
-  checkACForm("", "");
-  numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
-  is(numLogins, 3, "Correct number of logins after deleting one");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("zzzuser4", "zzzpass4");
+    case 52:
+        // Delete the second entry (of 3), "testuser3"
+        doKey("down");
+        doKey("down");
+        doKey("delete", shiftModifier);
+        checkACForm("", "");
+        numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
+        is(numLogins, 3, "Correct number of logins after deleting one");
+        doKey("return");
+        checkACForm("zzzuser4", "zzzpass4");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 53 */
-  // Check the new second entry (of 2)
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("testuser2", "testpass2");
+    case 53:
+        // Check the new second entry (of 2)
+        doKey("down");
+        doKey("return");
+        checkACForm("testuser2", "testpass2");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 54 */
-  // Delete the last entry (of 2), "zzzuser4"
-  doKey("down");
-  doKey("down");
-  doKey("delete", shiftModifier);
-  checkACForm("", "");
-  numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
-  is(numLogins, 2, "Correct number of logins after deleting one");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("testuser2", "testpass2");
+    case 54:
+        // Delete the last entry (of 2), "zzzuser4"
+        doKey("down");
+        doKey("down");
+        doKey("delete", shiftModifier);
+        checkACForm("", "");
+        numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
+        is(numLogins, 2, "Correct number of logins after deleting one");
+        doKey("return");
+        checkACForm("testuser2", "testpass2");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 55 */
-  // Check the new second entry (of 2)
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("testuser2", "testpass2");
+    case 55:
+        // Check the new second entry (of 2)
+        doKey("down");
+        doKey("return");
+        checkACForm("testuser2", "testpass2");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 56 */
-  // Delete the only remaining entry, "testuser2"
-  doKey("down");
-  doKey("delete", shiftModifier);
-  //doKey("return");
-  checkACForm("", "");
-  numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
-  is(numLogins, 1, "Correct number of logins after deleting one");
-  pwmgr.removeLogin(login0); // remove the login that's not shown in the list.
-  testNum = 99;
-  yield runNextTest();
+    case 56:
+        // Delete the only remaining entry, "testuser2"
+        doKey("down");
+        doKey("delete", shiftModifier);
+        //doKey("return");
+        checkACForm("", "");
+        numLogins = pwmgr.countLogins("http://mochi.test:8888", "http://autocomplete:8888", null);
+        is(numLogins, 1, "Correct number of logins after deleting one");
+        pwmgr.removeLogin(login0); // remove the login that's not shown in the list.
+        testNum = 99;
+        gNextTestWillOpenPopup = true;
+        break;
 
 
-  /* Tests for single-user forms with autocomplete=off */
+    /* Tests for single-user forms with autocomplete=off */
 
-  /* test 100 */
-  // Turn our attention to form2
-  uname = $_(2, "uname");
-  pword = $_(2, "pword");
-  checkACForm("", "");
+    case 100:
+        // Turn our attention to form2
+        uname = $_(2, "uname");
+        pword = $_(2, "pword");
+        checkACForm("", "");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 101 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("singleuser5", "singlepass5");
-  restoreForm(); // clear field, so reloading test doesn't fail
-  yield runNextTest();
+    case 101:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        checkACForm("singleuser5", "singlepass5");
+        restoreForm(); // clear field, so reloading test doesn't fail
+        gNextTestWillOpenPopup = true;
+        break;
 
-  /* test 102 */
-  // Turn our attention to form3
-  uname = $_(3, "uname");
-  pword = $_(3, "pword");
-  checkACForm("", "");
+    case 102:
+        // Turn our attention to form3
+        uname = $_(3, "uname");
+        pword = $_(3, "pword");
+        checkACForm("", "");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 103 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("singleuser5", "singlepass5");
-  yield runNextTest();
+    case 103:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        checkACForm("singleuser5", "singlepass5");
+        gNextTestWillOpenPopup = true;
+        break;
 
-  /* test 104 */
-  // Turn our attention to form4
-  uname = $_(4, "uname");
-  pword = $_(4, "pword");
-  checkACForm("", "");
+    case 104:
+        // Turn our attention to form4
+        uname = $_(4, "uname");
+        pword = $_(4, "pword");
+        checkACForm("", "");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 105 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("singleuser5", "singlepass5");
-  yield runNextTest();
+    case 105:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        checkACForm("singleuser5", "singlepass5");
+        gNextTestWillOpenPopup = true;
+        break;
 
-  /* test 106 */
-  // Turn our attention to form5
-  uname = $_(5, "uname");
-  pword = $_(5, "pword");
-  checkACForm("", "");
+    case 106:
+        // Turn our attention to form5
+        uname = $_(5, "uname");
+        pword = $_(5, "pword");
+        checkACForm("", "");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 107 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("singleuser5", "singlepass5");
-  yield runNextTest();
+    case 107:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        checkACForm("singleuser5", "singlepass5");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 108 */
-  // Turn our attention to form6
-  // (this is a control, w/o autocomplete=off, to ensure the login
-  // that was being suppressed would have been filled in otherwise)
-  uname = $_(6, "uname");
-  pword = $_(6, "pword");
-  checkACForm("singleuser5", "singlepass5");
-  yield runNextTest();
+    case 108:
+        // Turn our attention to form6
+        // (this is a control, w/o autocomplete=off, to ensure the login
+        // that was being suppressed would have been filled in otherwise)
+        uname = $_(6, "uname");
+        pword = $_(6, "pword");
+        checkACForm("singleuser5", "singlepass5");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 109 */
-  // Test that the password field remains filled in after changing
-  // the username.
-  uname.focus();
-  doKey("right");
-  sendChar("X");
-  // Trigger the 'blur' event on uname
-  pword.focus();
-  yield spinEventLoop();
-  checkACForm("sXingleuser5", "singlepass5");
+    case 109:
+        // Test that the password field remains filled in after changing
+        // the username.
+        uname.focus();
+        doKey("right");
+        sendChar("X");
+        // Trigger the 'blur' event on uname
+        pword.focus();
+        checkACForm("sXingleuser5", "singlepass5");
 
-  pwmgr.removeLogin(login5);
-  testNum = 499;
-  yield runNextTest();
+        pwmgr.removeLogin(login5);
+        testNum = 499;
+        gNextTestWillOpenPopup = true;
+        break;
 
-  /* test 500 */
-  // Turn our attention to form7
-  uname = $_(7, "uname");
-  pword = $_(7, "pword");
-  checkACForm("", "");
+    case 500:
+        // Turn our attention to form7
+        uname = $_(7, "uname");
+        pword = $_(7, "pword");
+        checkACForm("", "");
 
-  // Insert a new username field into the form. We'll then make sure
-  // that invoking the autocomplete doesn't try to fill the form.
-  var newField = document.createElement("input");
-  newField.setAttribute("type", "text");
-  newField.setAttribute("name", "uname2");
-  pword.parentNode.insertBefore(newField, pword);
-  is($_(7, "uname2").value, "", "Verifying empty uname2");;
+        // Insert a new username field into the form. We'll then make sure
+        // that invoking the autocomplete doesn't try to fill the form.
+        var newField = document.createElement("input");
+        newField.setAttribute("type", "text");
+        newField.setAttribute("name", "uname2");
+        pword.parentNode.insertBefore(newField, pword);
+        is($_(7, "uname2").value, "", "Verifying empty uname2");;
 
-  // Delete login6B. It was created just to prevent filling in a login
-  // automatically, removing it makes it more likely that we'll catch a
-  // future regression with form filling here.
-  pwmgr.removeLogin(login6B);
+        // Delete login6B. It was created just to prevent filling in a login
+        // automatically, removing it makes it more likely that we'll catch a
+        // future regression with form filling here.
+        pwmgr.removeLogin(login6B);
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest("expect popup");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 501 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  // The form changes, so we expect the old username field to get the
-  // selected autocomplete value, but neither the new username field nor
-  // the password field should have any values filled in.
-  yield spinEventLoop();
-  checkACForm("form7user1", "");
-  is($_(7, "uname2").value, "", "Verifying empty uname2");;
-  restoreForm(); // clear field, so reloading test doesn't fail
+    case 501:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        // The form changes, so we expect the old username field to get the
+        // selected autocomplete value, but neither the new username field nor
+        // the password field should have any values filled in.
+        checkACForm("form7user1", "");
+        is($_(7, "uname2").value, "", "Verifying empty uname2");;
+        restoreForm(); // clear field, so reloading test doesn't fail
 
-  pwmgr.removeLogin(login6A);
-  testNum = 599;
-  yield runNextTest();
+        pwmgr.removeLogin(login6A);
+        testNum = 599;
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 600 */
-  // Turn our attention to form8
-  uname = $_(8, "uname");
-  pword = $_(8, "pword");
-  checkACForm("form8user", "form8pass");
-  restoreForm();
-  yield runNextTest();
+    case 600:
+        // Turn our attention to form8
+        uname = $_(8, "uname");
+        pword = $_(8, "pword");
+        checkACForm("form8user", "form8pass");
+        restoreForm();
+        gNextTestWillOpenPopup = false;
+        break;
+
+    case 601:
+        checkACForm("", "");
+        // Focus the previous form to trigger a blur.
+        $_(7, "uname").focus();
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 601 */
-  checkACForm("", "");
-  // Focus the previous form to trigger a blur.
-  $_(7, "uname").focus();
-  yield runNextTest();
+    case 602:
+        checkACForm("", "");
+        restoreForm();
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 602 */
-  checkACForm("", "");
-  restoreForm();
-  yield runNextTest();
+    case 603:
+        checkACForm("", "");
+        pwmgr.removeLogin(login7);
 
-  /* test 603 */
-  checkACForm("", "");
-  pwmgr.removeLogin(login7);
-
-  testNum = 699;
-  yield runNextTest();
+        testNum = 699;
+        gNextTestWillOpenPopup = true;
+        break;
 
-  /* test 700 */
-  // Turn our attention to form9 to test the dropdown - bug 497541
-  uname = $_(9, "uname");
-  pword = $_(9, "pword");
-  uname.focus();
-  sendString("form9userAB");
-  yield runNextTest("expect popup");
+    case 700:
+        // Turn our attention to form9 to test the dropdown - bug 497541
+        uname = $_(9, "uname");
+        pword = $_(9, "pword");
+        uname.focus();
+        sendString("form9userAB");
+        gNextTestWillOpenPopup = true;
+        break;
 
-  /* test 701 */
-  checkACForm("form9userAB", "");
-  uname.focus();
-  doKey("left");
-  sendChar("A");
-  yield runNextTest("expect popup");
+    case 701:
+        checkACForm("form9userAB", "");
+        uname.focus();
+        doKey("left");
+        sendChar("A");
+        gNextTestWillOpenPopup = false;
+        break;
+
+    case 702:
+        // check dropdown is updated after inserting "A"
+        checkACForm("form9userAAB", "");
+        checkMenuEntries(["form9userAAB"]);
+        doKey("down");
+        doKey("return");
+        checkACForm("form9userAAB", "form9pass");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 702 */
-  // check dropdown is updated after inserting "A"
-  checkACForm("form9userAAB", "");
-  checkMenuEntries(["form9userAAB"]);
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("form9userAAB", "form9pass");
-  yield runNextTest();
+    case 703:
+        pwmgr.addLogin(login8C);
+        uname.focus();
+        sendChar("z");
+        gNextTestWillOpenPopup = false;
+        break;
 
-  /* test 703 */
-  // Note that this addLogin call will only be seen by the autocomplete
-  // attempt for the sendChar if we do not successfully cache the
-  // autocomplete results.
-  pwmgr.addLogin(login8C);
-  uname.focus();
-  sendChar("z");
-  yield runNextTest();
+    case 704:
+        // check that empty results are cached - bug 496466
+        checkMenuEntries([]);
 
-  /* test 704 */
-  // check that empty results are cached - bug 496466
-  checkMenuEntries([]);
+        SimpleTest.finish();
+        return;
 
-  SimpleTest.finish();
-  return;
+    default:
+        ok(false, "Unexpected invocation of test #" + testNum);
+        SimpleTest.finish();
+        return;
+  }
 }
 
 
 function checkMenuEntries(expectedValues) {
     var actualValues = getMenuEntries();
     is(actualValues.length, expectedValues.length, "Checking length of expected menu");
     for (var i = 0; i < expectedValues.length; i++)
         is(actualValues[i], expectedValues[i], "Checking menu entry #"+i);
@@ -805,18 +799,17 @@ function startTest() {
                     .rootTreeItem
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindow)
                     .QueryInterface(Ci.nsIDOMChromeWindow);
     // shouldn't reach into browser internals like this and
     // shouldn't assume ID is consistent across products
     autocompletePopup = chromeWin.document.getElementById("PopupAutoComplete");
     ok(autocompletePopup, "Got autocomplete popup");
-    tester = runTest();
-    tester.next();
+    runTest(1);
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_basic_form_html5.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_html5.html
@@ -159,13 +159,13 @@ function startTest() {
   pwmgr.removeLogin(login1);
   pwmgr.removeLogin(login2);
   pwmgr.removeLogin(login3);
   pwmgr.removeLogin(login4);
  
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_observer_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_observer_autocomplete.html
@@ -55,20 +55,18 @@ var TestObserver = {
     if (topic == "passwordmgr-found-form") {
       if (subject.id == "form1") {
         this.receivedNotification1 = true;
         this.data1 = data;
       } else if (subject.id == "form2") {
         this.receivedNotification2 = true;
         this.data2 = data;
       }
-
       // Now fill the form
-      pwmgr.fillForm(subject)
-           .then(startTest);
+      pwmgr.fillForm(subject);
     }
   }
 };
 
 // Add the observer
 SpecialPowers.addObserver(TestObserver, "passwordmgr-found-form", false);
 
 function startTest(){
@@ -92,12 +90,14 @@ function startTest(){
   try {
     SpecialPowers.removeObserver(TestObserver, "passwordmgr-found-form");
   } catch (e) {
     ok(false, SpecialPowers.wrap(e));
   }
 
   SimpleTest.finish();
 }
+
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_observer_autofillForms.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_observer_autofillForms.html
@@ -4,17 +4,17 @@
   <title>Test for Login Manager</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
   <script type="text/javascript" src="pwmgr_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Login Manager test: simple form with autofillForms disabled and notifying observers
 <script>
-commonInit(true);
+commonInit();
 SimpleTest.waitForExplicitFinish();
 
 const Cc = SpecialPowers.Cc;
 const Ci = SpecialPowers.Ci;
 
 // Assume that the pref starts out true, so set to false
 SpecialPowers.setBoolPref("signon.autofillForms", false);
 
@@ -26,26 +26,19 @@ var TestObserver = {
   observe : function (subject, topic, data) {
     var pwmgr = Cc["@mozilla.org/login-manager;1"].
                 getService(Ci.nsILoginManager);
     if (topic == "passwordmgr-found-form") {
       info("got passwordmgr-found-form");
       this.receivedNotificationFoundForm = true;
       this.dataFoundForm = data;
       // Now fill the form
-      pwmgr.fillForm(subject)
-           .then(window.startTest)
-           .then(null, function(e) { alert(e); });
+      pwmgr.fillForm(subject);
     } else if (topic == "passwordmgr-found-logins") {
       info("got passwordmgr-found-logins");
-
-      // We only care about the first notification (the second comes from our
-      // own call to pwmgr.fillForm.
-      if (this.receivedNotificationFoundLogins)
-        return;
       this.receivedNotificationFoundLogins = true;
       this.dataFoundLogins = subject.QueryInterface(Ci.nsIPropertyBag2);
     }
   }
 };
 
 // Add the observer
 SpecialPowers.addObserver(TestObserver, "passwordmgr-found-form", false);
@@ -66,17 +59,17 @@ SpecialPowers.addObserver(TestObserver, 
   </form>
 
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: simple form with autofillForms disabled and notifying observers **/
-function startTest() {
+function startTest(){
   // Test that found-form observer is notified & got correct data
   is(TestObserver.receivedNotificationFoundForm, true, "Checking found-form observer was notified");
   is(TestObserver.dataFoundForm, "noAutofillForms", "Checking found-form observer got correct data");
 
   // Check that form1 was filled
   is($_(1, "uname").value, "testuser", "Checking for filled username");
   is($_(1, "pword").value, "testpass", "Checking for filled password");
 
@@ -96,13 +89,13 @@ function startTest() {
 
   // Remove the observer
   SpecialPowers.removeObserver(TestObserver, "passwordmgr-found-form");
   SpecialPowers.removeObserver(TestObserver, "passwordmgr-found-logins");
 
   SimpleTest.finish();
 }
 
-
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_observer_foundLogins.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_observer_foundLogins.html
@@ -169,13 +169,13 @@ function startTest(){
 
   // Remove the logins added for the multiple logins test.
   pwmgr.removeLogin(login1);
   pwmgr.removeLogin(login2);
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_basic_form_pwevent.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_pwevent.html
@@ -9,46 +9,44 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="pwmgr_common.js"></script>
   <script type="application/javascript">
   /** Test for Bug 355063 **/
 
   function startTest() {
     info("startTest");
-    // Password Manager's own listener should always have been added first, so
-    // the test's listener should be called after the pwmgr's listener fills in
-    // a login.
-    //
-    SpecialPowers.addChromeEventListener("DOMFormHasPassword", function eventFired() {
-      SpecialPowers.removeChromeEventListener("DOMFormHasPassword", eventFired);
-      setTimeout(checkForm, 300);
-    });
     addForm();
   }
 
   function addForm() {
     info("addForm");
     var c = document.getElementById("content");
     c.innerHTML = "<form id=form1>form1: <input id=u1><input type=password id=p1></form><br>";
   }
 
   function checkForm() {
     info("checkForm");
     var userField = document.getElementById("u1");
     var passField = document.getElementById("p1");
     is(userField.value, "testuser", "checking filled username");
     is(passField.value, "testpass", "checking filled password");
 
+    SpecialPowers.removeChromeEventListener("DOMFormHasPassword", checkForm);
     SimpleTest.finish();
   }
 
   commonInit();
 
-  window.addEventListener("runTests", startTest);
+  // Password Manager's own listener should always have been added first, so
+  // the test's listener should be called after the pwmgr's listener fills in
+  // a login.
+  //
+  SpecialPowers.addChromeEventListener("DOMFormHasPassword", checkForm);
+  window.addEventListener("load", startTest);
   SimpleTest.waitForExplicitFinish();
 </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=355063">Mozilla Bug 355063</a>
 <p id="display"></p>
 <div id="content">
 forms go here!
--- a/toolkit/components/passwordmgr/test/test_basic_form_pwonly.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_pwonly.html
@@ -206,14 +206,14 @@ function startTest() {
 
     checkUnmodifiedForm(12);
     checkUnmodifiedForm(13);
 
     pwmgr.removeLogin(pwlogin2);
     SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_bug_227640.html
+++ b/toolkit/components/passwordmgr/test/test_bug_227640.html
@@ -230,14 +230,14 @@ function getFormSubmitButton(formNum) {
 }
 
 // Counts the number of logins currently stored by password manager.
 function countLogins() {
   var logins = pwmgr.getAllLogins();
 
   return logins.length;
 }
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_bug_242956.html
+++ b/toolkit/components/passwordmgr/test/test_bug_242956.html
@@ -113,16 +113,16 @@ function startTest() {
   is($_(7, "uname").value, "testuser", "Checking for unmodified username 7");
   is($_(7, "pword").value, "",         "Checking for unfilled password 7");
 
 
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_bug_360493_1.html
+++ b/toolkit/components/passwordmgr/test/test_bug_360493_1.html
@@ -124,17 +124,17 @@ function startTest() {
 
   // The login's formSubmitURL isn't "javascript:", so don't fill it in.
   isnot($_(10, "uname"), "testuser", "Checking username w/ JS action URL");
   isnot($_(10, "pword"), "testpass", "Checking password w/ JS action URL");
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_bug_360493_2.html
+++ b/toolkit/components/passwordmgr/test/test_bug_360493_2.html
@@ -161,17 +161,17 @@ function startTest() {
   // there may be a security issue.
   is(document.forms.length,  11,  "Checking for unexpected forms");
   $("neutered_submit10").click();
   $("neutered_submit11").click();
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_bug_391514.html
+++ b/toolkit/components/passwordmgr/test/test_bug_391514.html
@@ -125,16 +125,16 @@ function startTest() {
 
   // Note that tests 11-13 are limited to exactly the expected value.
   // Assert this lest someone change the login we're testing with.
   is($_(11, "uname").value.length, 8, "asserting test assumption is valid.");
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_bug_427033.html
+++ b/toolkit/components/passwordmgr/test/test_bug_427033.html
@@ -5,20 +5,16 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
   <script type="text/javascript" src="pwmgr_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Login Manager test: form with JS submit action
 <script>
 SimpleTest.waitForExplicitFinish();
-
-// Note: Call this first so it doesn't override our login.
-commonInit();
-
 var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
                          .getService(SpecialPowers.Ci.nsILoginManager);
 var jslogin = SpecialPowers.Cc["@mozilla.org/login-manager/loginInfo;1"]
                            .createInstance(SpecialPowers.Ci.nsILoginInfo);
 jslogin.init("http://mochi.test:8888", "javascript:", null,
               "jsuser", "jspass123", "uname", "pword");
 pwmgr.addLogin(jslogin);
 
@@ -26,18 +22,17 @@ pwmgr.addLogin(jslogin);
 
 function startTest() {
     checkForm(1, "jsuser", "jspass123");
 
     pwmgr.removeLogin(jslogin);
     SimpleTest.finish();
 }
 
-// XXX
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 
 <p id="display"></p>
 
 <div id="content" style="display: none">
 
 
 <form id='form1' action='javascript:alert("never shows")'> 1
--- a/toolkit/components/passwordmgr/test/test_bug_444968.html
+++ b/toolkit/components/passwordmgr/test/test_bug_444968.html
@@ -122,13 +122,13 @@ function startTest() {
   pwmgr.removeLogin(login1B);
   pwmgr.removeLogin(login2A);
   pwmgr.removeLogin(login2B);
   pwmgr.removeLogin(login2C);
 
   SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/test_case_differences.html
+++ b/toolkit/components/passwordmgr/test/test_case_differences.html
@@ -61,17 +61,16 @@ try {
 
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: multiple login autocomplete. **/
 
-var tester;
 
 var uname = $_(1, "uname");
 var pword = $_(1, "pword");
 
 // Restore the form to the default state.
 function restoreForm() {
     uname.value = "";
     pword.value = "";
@@ -88,107 +87,111 @@ function checkACForm(expectedUsername, e
 
 
 function sendFakeAutocompleteEvent(element) {
     var acEvent = document.createEvent("HTMLEvents");
     acEvent.initEvent("DOMAutoComplete", true, false);
     element.dispatchEvent(acEvent);
 }
 
+var gLastTest = 6;
+
 function addPopupListener(eventName, func, capture) {
   autocompletePopup.addEventListener(eventName, func, capture);
 }
 
 function removePopupListener(eventName, func, capture) {
   autocompletePopup.removeEventListener(eventName, func, capture);
 }
 
 /*
  * Main section of test...
  *
  * This is a bit hacky, because the events are either being sent or
  * processes asynchronously, so we need to interrupt our flow with lots of
  * setTimeout() calls. The case statements are executed in order, one per
  * timeout.
  */
-function* runTest() {
-  function runNextTest() {
-    addPopupListener("popupshown", function() {
-      removePopupListener("popupshown", arguments.callee, false);
+function runTest(testNum) {
+  ok(true, "Starting test #" + testNum);
 
-      window.setTimeout(tester.next.bind(tester), 0);
-    }, false);
-  }
+  addPopupListener("popupshown", function() {
+    removePopupListener("popupshown", arguments.callee, false);
 
-  function waitForCompletion() {
-    var observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
-      SpecialPowers.removeObserver(observer, "passwordmgr-found-logins");
-      tester.next();
-    });
-    SpecialPowers.addObserver(observer, "passwordmgr-found-logins", false);
-  }
+    if (testNum != gLastTest) {
+      window.setTimeout(runTest, 0, testNum + 1);
+    }
+  }, false);
 
-  /* test 1 */
-  // Make sure initial form is empty.
-  checkACForm("", "");
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest();
+  switch(testNum) {
+    case 1:
+        // Make sure initial form is empty.
+        checkACForm("", "");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  /* test 2 */
-  // Check first entry
-  doKey("down");
-  checkACForm("", ""); // value shouldn't update
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("name", "pass");
+    case 2:
+        // Check first entry
+        doKey("down");
+        checkACForm("", ""); // value shouldn't update
+        doKey("return"); // not "enter"!
+        checkACForm("name", "pass");
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest();
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
+
+    case 3:
+        // Check second entry
+        doKey("down");
+        doKey("down");
+        doKey("return"); // not "enter"!
+        checkACForm("Name", "Pass");
 
-  /* test 3 */
-  // Check second entry
-  doKey("down");
-  doKey("down");
-  doKey("return"); // not "enter"!
-  yield waitForCompletion();
-  checkACForm("Name", "Pass");
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  // Trigger autocomplete popup
-  restoreForm();
-  doKey("down");
-  yield runNextTest();
+    case 4:
+        // Check third entry
+        doKey("down");
+        doKey("down");
+        doKey("down");
+        doKey("return");
+        checkACForm("USER", "PASS");
+
+        // Trigger autocomplete popup
+        restoreForm();
+        uname.value = "user";
+        doKey("down");
+        break;
 
-  /* test 4 */
-  // Check third entry
-  doKey("down");
-  doKey("down");
-  doKey("down");
-  doKey("return");
-  yield waitForCompletion();
-  checkACForm("USER", "PASS");
+    case 5:
+        // Check that we don't clobber user-entered text when tabbing away
+        doKey("tab");
+        checkACForm("user", "PASS");
+
+        // Trigger autocomplete popup
+        restoreForm();
+        doKey("down");
+        break;
 
-  // Trigger autocomplete popup
-  restoreForm();
-  uname.value = "user";
-  doKey("down");
-  yield runNextTest();
+    case 6:
+        SimpleTest.finish();
+        return;
 
-  /* test 5 */
-  // Check that we don't clobber user-entered text when tabbing away
-  doKey("tab");
-  yield waitForCompletion();
-  checkACForm("user", "PASS");
-
-  // Trigger autocomplete popup
-  restoreForm();
-  SimpleTest.finish();
+    default:
+        ok(false, "Unexpected invocation of test #" + testNum);
+        SimpleTest.finish();
+        return;
+  }
 }
 
 
 var autocompletePopup;
 
 function startTest() {
     var Ci = SpecialPowers.Ci;
     chromeWin = SpecialPowers.wrap(window)
@@ -198,18 +201,17 @@ function startTest() {
                     .rootTreeItem
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindow)
                     .QueryInterface(Ci.nsIDOMChromeWindow);
     // shouldn't reach into browser internals like this and
     // shouldn't assume ID is consistent across products
     autocompletePopup = chromeWin.document.getElementById("PopupAutoComplete");
     ok(autocompletePopup, "Got autocomplete popup");
-    tester = runTest();
-    tester.next();
+    runTest(1);
 }
 
-window.addEventListener("runTests", startTest);
+window.onload = startTest;
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_master_password.html
+++ b/toolkit/components/passwordmgr/test/test_master_password.html
@@ -110,27 +110,24 @@ function handleDialog(doc, testNum) {
 
     if (testNum == 4)
         checkTest4A();
 }
 
 var outerWindowObserver = {
   observe: function(id) {
     SpecialPowers.removeObserver(outerWindowObserver, "outer-window-destroyed");
-    var func;
     if (testNum == 1)
-        func = startTest2;
+        startTest2();
     else if (testNum == 2)
-        func = startTest3;
+        startTest3();
     else if (testNum == 3)
-        func = checkTest3;
+        checkTest3();
     else if (testNum == 5)
-        func = checkTest4C;
-
-    setTimeout(func, 300);
+        checkTest4C();
   }
 };
 
 
 function startTest1() {
     ok(pwcrypt.isLoggedIn, "should be initially logged in (no MP)");
     enableMasterPassword();
     ok(!pwcrypt.isLoggedIn, "should be logged out after setting MP");
@@ -267,14 +264,14 @@ function finishTest() {
     disableMasterPassword();
     ok(pwcrypt.isLoggedIn, "should be logged in");
 
     pwmgr.removeLogin(login1);
     pwmgr.removeLogin(login2);
     SimpleTest.finish();
 }
 
-window.addEventListener("runTests", startTest1);
+window.onload = startTest1;
 </script>
 </pre>
 </body>
 </html>
 
--- a/toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html
+++ b/toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html
@@ -35,17 +35,16 @@ var subtests = [
                    "subtst_privbrowsing_2.html", // 4
                    "subtst_privbrowsing_2.html", // 5
                    "subtst_privbrowsing_2.html", // 6
                    "subtst_privbrowsing_3.html", // 7
                    "subtst_privbrowsing_3.html", // 8
                    "subtst_privbrowsing_4.html", // 9
                    "subtst_privbrowsing_3.html" // 10
                ];
-var observer;
 
 var testNum = 0;
 function loadNextTest() {
   // run the initialization code for each test
   switch (++ testNum) {
     case 1:
       popupNotifications = normalWindowPopupNotifications;
       iframe = normalWindowIframe;
@@ -91,27 +90,21 @@ function loadNextTest() {
       popupNotifications = normalWindowPopupNotifications;
       iframe = normalWindowIframe;
       break;
 
     default:
       ok(false, "Unexpected call to loadNextTest for test #" + testNum);
   }
 
-  if (testNum === 7) {
-    observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
-      SimpleTest.executeSoon(() => { iframe.contentWindow.postMessage("go", "*"); });
-    });
-    SpecialPowers.addObserver(observer, "passwordmgr-found-logins", false);
-  }
-
   ok(true, "Starting test #" + testNum);
   iframe.src = prefix + subtests[testNum-1];
 }
 
+
 function checkTest() {
   var popup;
 
   switch (testNum) {
     case 1:
       // run outside of private mode, popup notification should appear
       popup = getPopup(popupNotifications, "password-save");
       ok(popup, "got popup notification");
@@ -250,17 +243,16 @@ function handleLoad(aEvent) {
     loadNextTest();
   } else {
     ok(true, "private browsing notification tests finished.");
 
     testWindows.forEach(function(aWin) {
       aWin.close();
     });
 
-    SpecialPowers.removeObserver(observer, "passwordmgr-found-logins");
     SimpleTest.finish();
   }
 }
 
 var pwmgr = Cc["@mozilla.org/login-manager;1"].
             getService(Ci.nsILoginManager);
 ok(pwmgr != null, "Access pwmgr");