diff --git a/resources/static/dialog/test/qunit/mocks/mocks.js b/resources/static/dialog/test/qunit/mocks/mocks.js
new file mode 100644
index 0000000000000000000000000000000000000000..70a00e1ffc8e09b63fc58f6d70ea3fe1d21e82b4
--- /dev/null
+++ b/resources/static/dialog/test/qunit/mocks/mocks.js
@@ -0,0 +1,39 @@
+
+/*jshint browsers:true, forin: true, laxbreak: true */
+/*global BrowserID: true */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+BrowserID.Mocks = {};
+
diff --git a/resources/static/dialog/test/qunit/mocks/xhr.js b/resources/static/dialog/test/qunit/mocks/xhr.js
new file mode 100644
index 0000000000000000000000000000000000000000..3c09c8cabc78adfae74fb6c98dd6106dd98ab1fd
--- /dev/null
+++ b/resources/static/dialog/test/qunit/mocks/xhr.js
@@ -0,0 +1,162 @@
+/*jshint browsers:true, forin: true, laxbreak: true */
+/*global wrappedAsyncTest: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID: true */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+BrowserID.Mocks.xhr = (function() {
+  var  contextInfo = {
+      server_time: new Date().getTime(),
+      csrf_token: "csrf",
+      authenticated: false
+    };
+
+  // this cert is meaningless, but it has the right format
+  var random_cert = "eyJhbGciOiJSUzEyOCJ9.eyJpc3MiOiJpc3N1ZXIuY29tIiwiZXhwIjoxMzE2Njk1MzY3NzA3LCJwdWJsaWMta2V5Ijp7ImFsZ29yaXRobSI6IlJTIiwibiI6IjU2MDYzMDI4MDcwNDMyOTgyMzIyMDg3NDE4MTc2ODc2NzQ4MDcyMDM1NDgyODk4MzM0ODExMzY4NDA4NTI1NTk2MTk4MjUyNTE5MjY3MTA4MTMyNjA0MTk4MDA0NzkyODQ5MDc3ODY4OTUxOTA2MTcwODEyNTQwNzEzOTgyOTU0NjUzODEwNTM5OTQ5Mzg0NzEyNzczMzkwMjAwNzkxOTQ5NTY1OTAzNDM5NTIxNDI0OTA5NTc2ODMyNDE4ODkwODE5MjA0MzU0NzI5MjE3MjA3MzYwMTA1OTA2MDM5MDIzMjk5NTYxMzc0MDk4OTQyNzg5OTk2NzgwMTAyMDczMDcxNzYwODUyODQxMDY4OTg5ODYwNDAzNDMxNzM3NDgwMTgyNzI1ODUzODk5NzMzNzA2MDY5IiwiZSI6IjY1NTM3In0sInByaW5jaXBhbCI6eyJlbWFpbCI6InRlc3R1c2VyQHRlc3R1c2VyLmNvbSJ9fQ.aVIO470S_DkcaddQgFUXciGwq2F_MTdYOJtVnEYShni7I6mqBwK3fkdWShPEgLFWUSlVUtcy61FkDnq2G-6ikSx1fUZY7iBeSCOKYlh6Kj9v43JX-uhctRSB2pI17g09EUtvmb845EHUJuoowdBLmLa4DSTdZE-h4xUQ9MsY7Ik";
+
+  /**
+   * This is the results table, the keys are the request type, url, and 
+   * a "selector" for testing.  The right is the expected return value, already 
+   * decoded.  If a result is "undefined", the request's error handler will be 
+   * called.
+   */
+  var xhr = {
+    results: {
+      "get /wsapi/session_context valid": contextInfo,   
+      "get /wsapi/session_context invalid": contextInfo,
+      // We are going to test for XHR failures for session_context using 
+      // call to serverTime.  We are going to use the flag contextAjaxError
+      "get /wsapi/session_context ajaxError": contextInfo, 
+      "get /wsapi/session_context throttle": contextInfo, 
+      "get /wsapi/session_context contextAjaxError": undefined,  
+      "get /wsapi/email_for_token?token=token valid": { email: "testuser@testuser.com" },  
+      "get /wsapi/email_for_token?token=token invalid": { success: false },  
+      "post /wsapi/authenticate_user valid": { success: true },
+      "post /wsapi/authenticate_user invalid": { success: false },
+      "post /wsapi/authenticate_user ajaxError": undefined,
+      "post /wsapi/cert_key valid": random_cert,
+      "post /wsapi/cert_key invalid": undefined,
+      "post /wsapi/cert_key ajaxError": undefined,
+      "post /wsapi/complete_email_addition valid": { success: true },
+      "post /wsapi/complete_email_addition invalid": { success: false },
+      "post /wsapi/complete_email_addition ajaxError": undefined,
+      "post /wsapi/stage_user valid": { success: true },
+      "post /wsapi/stage_user invalid": { success: false },
+      "post /wsapi/stage_user throttle": 403,
+      "post /wsapi/stage_user ajaxError": undefined,
+      "get /wsapi/user_creation_status?email=registered%40testuser.com pending": { status: "pending" },
+      "get /wsapi/user_creation_status?email=registered%40testuser.com complete": { status: "complete" },
+      "get /wsapi/user_creation_status?email=registered%40testuser.com mustAuth": { status: "mustAuth" },
+      "get /wsapi/user_creation_status?email=registered%40testuser.com noRegistration": { status: "noRegistration" },
+      "get /wsapi/user_creation_status?email=registered%40testuser.com ajaxError": undefined,
+      "post /wsapi/complete_user_creation valid": { success: true },
+      "post /wsapi/complete_user_creation invalid": { success: false },
+      "post /wsapi/complete_user_creation ajaxError": undefined,
+      "post /wsapi/logout valid": { success: true },
+      "post /wsapi/logout ajaxError": undefined,
+      "get /wsapi/have_email?email=registered%40testuser.com valid": { email_known: true },
+      "get /wsapi/have_email?email=registered%40testuser.com throttle": { email_known: true },
+      "get /wsapi/have_email?email=registered%40testuser.com ajaxError": undefined,
+      "get /wsapi/have_email?email=unregistered%40testuser.com valid": { email_known: false },
+      "post /wsapi/remove_email valid": { success: true },
+      "post /wsapi/remove_email invalid": { success: false },
+      "post /wsapi/remove_email ajaxError": undefined,
+      "post /wsapi/account_cancel valid": { success: true },
+      "post /wsapi/account_cancel invalid": { success: false },
+      "post /wsapi/account_cancel ajaxError": undefined,
+      "post /wsapi/stage_email valid": { success: true },
+      "post /wsapi/stage_email invalid": { success: false },
+      "post /wsapi/stage_email throttle": 403,
+      "post /wsapi/stage_email ajaxError": undefined,
+      "post /wsapi/cert_key ajaxError": undefined,
+      "get /wsapi/email_addition_status?email=registered%40testuser.com pending": { status: "pending" },
+      "get /wsapi/email_addition_status?email=registered%40testuser.com complete": { status: "complete" },
+      "get /wsapi/email_addition_status?email=registered%40testuser.com mustAuth": { status: "mustAuth" },
+      "get /wsapi/email_addition_status?email=registered%40testuser.com noRegistration": { status: "noRegistration" },
+      "get /wsapi/email_addition_status?email=registered%40testuser.com ajaxError": undefined,
+      "get /wsapi/list_emails valid": {"testuser@testuser.com":{}},
+      "get /wsapi/list_emails multiple": {"testuser@testuser.com":{}, "testuser2@testuser.com":{}},
+      "get /wsapi/list_emails no_identities": [],
+      "get /wsapi/list_emails ajaxError": undefined
+    },
+
+    setContextInfo: function(field, value) {
+      contextInfo[field] = value;
+    },
+
+    useResult: function(result) {
+      xhr.resultType = result;
+    },
+
+    getLastRequest: function() {
+      return this.req;
+    },
+
+    ajax: function(obj) {
+      //console.log("ajax request");
+      var type = obj.type ? obj.type.toLowerCase() : "get";
+
+      var req = this.req = {
+        type: type,
+        url: obj.url,
+        data: obj.data
+      };
+
+
+      if(type === "post" && !obj.data.csrf) {
+        ok(false, "missing csrf token on POST request");
+      }
+
+      var resName = req.type + " " + req.url + " " + xhr.resultType;
+      var result = xhr.results[resName];
+
+      var type = typeof result;
+      if(!(type == "number" || type == "undefined")) {
+        if(obj.success) {
+          obj.success(result);
+        }
+      }
+      else if (obj.error) {
+        // Invalid result - either invalid URL, invalid GET/POST or 
+        // invalid resultType
+        obj.error({ status: result || 400 }, "errorStatus", "errorThrown");
+      }
+    }
+  };
+
+
+  return xhr;
+}());
+
+
diff --git a/resources/static/dialog/test/qunit/pages/add_email_address_test.js b/resources/static/dialog/test/qunit/pages/add_email_address_test.js
index 1d0d0a016d7f9b44515d643b18d6f6f0c53672d5..d353a848f9b27f4357411ab19c8dd400339453ae 100644
--- a/resources/static/dialog/test/qunit/pages/add_email_address_test.js
+++ b/resources/static/dialog/test/qunit/pages/add_email_address_test.js
@@ -34,36 +34,24 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
-steal.plugins("jquery").then("/js/pages/add_email_address", function() {
+steal.plugins("jquery").then("/dialog/test/qunit/mocks/xhr", "/dialog/resources/network", "/js/pages/add_email_address", function() {
   "use strict";
 
   var bid = BrowserID,
       network = bid.Network,
       storage = bid.Storage,
-      emailForVerificationTokenFailure = false,
-      completeEmailRegistrationFailure = false,
+      xhr = bid.Mocks.xhr,
       validToken = true;
   
-  var netMock = {
-    emailForVerificationToken: function(token, onSuccess, onFailure) {
-      emailForVerificationTokenFailure ? onFailure() : onSuccess("testuser@testuser.com");
-    },
-
-    completeEmailRegistration: function(token, onSuccess, onFailure) {
-      completeEmailRegistrationFailure ? onFailure() : onSuccess(validToken);
-    }
-  };
-
   module("pages/add_email_address", {
     setup: function() {
-      BrowserID.User.setNetwork(netMock);  
-      emailForVerificationTokenFailure = completeEmailRegistrationFailure = false;
-      validToken = true;
+      network.setXHR(xhr);  
+      xhr.useResult("valid");
       $(".error").stop().hide();
       $(".website").text("");
     },
     teardown: function() {
-      BrowserID.User.setNetwork(network);  
+      network.setXHR($);  
       $(".error").stop().hide();
       $(".website").text("");
     }
@@ -74,39 +62,57 @@ steal.plugins("jquery").then("/js/pages/add_email_address", function() {
 
     bid.addEmailAddress("token");
     
-    equal($("#email").text(), "testuser@testuser.com", "email set");
-    ok($("#siteinfo").is(":visible"), "siteinfo is visible when we say what it is");
-    equal($("#siteinfo .website").text(), "browserid.org", "origin is updated");
+    setTimeout(function() {
+      equal($("#email").text(), "testuser@testuser.com", "email set");
+      ok($("#siteinfo").is(":visible"), "siteinfo is visible when we say what it is");
+      equal($("#siteinfo .website").text(), "browserid.org", "origin is updated");
+      start();
+    }, 500);
+    stop();
   });
 
   test("addEmailAddress with good token and nosite", function() {
     bid.addEmailAddress("token");
     
-    equal($("#email").text(), "testuser@testuser.com", "email set");
-    equal($("#siteinfo").is(":visible"), false, "siteinfo is not visible without having it");
-    equal($("#siteinfo .website").text(), "", "origin is not updated");
+    setTimeout(function() {
+      equal($("#email").text(), "testuser@testuser.com", "email set");
+      equal($("#siteinfo").is(":visible"), false, "siteinfo is not visible without having it");
+      equal($("#siteinfo .website").text(), "", "origin is not updated");
+      start();
+    }, 500);
+    stop();
   });
 
   test("addEmailAddress with bad token", function() {
-    validToken = false;
+    xhr.useResult("invalid");
 
     bid.addEmailAddress("token");
-    ok($("#cannotconfirm").is(":visible"), "cannot confirm box is visible");
+    setTimeout(function() {
+      ok($("#cannotconfirm").is(":visible"), "cannot confirm box is visible");
+      start();
+    }, 500);
+    stop();
   });
 
   test("addEmailAddress with emailForVerficationToken XHR failure", function() {
-    validToken = true;
-    emailForVerificationTokenFailure = true;
+    xhr.useResult("ajaxError");
     bid.addEmailAddress("token");
 
-    ok($("#cannotcommunicate").is(":visible"), "cannot communicate box is visible");
+    setTimeout(function() {
+      ok($("#cannotcommunicate").is(":visible"), "cannot communicate box is visible");
+      start();
+    }, 500);
+    stop();
   });
 
   test("addEmailAddress with completeEmailRegistration XHR failure", function() {
-    validToken = true;
-    completeEmailRegistrationFailure = true;
+    xhr.useResult("ajaxError");
     bid.addEmailAddress("token");
 
-    ok($("#cannotcommunicate").is(":visible"), "cannot communicate box is visible");
+    setTimeout(function() {
+      ok($("#cannotcommunicate").is(":visible"), "cannot communicate box is visible");
+      start();
+    }, 500);
+    stop();
   });
 });
diff --git a/resources/static/dialog/test/qunit/pages/forgot_unit_test.js b/resources/static/dialog/test/qunit/pages/forgot_unit_test.js
index d9afb17b14c42cb90173d963237cb5514646d51b..ea45fed4411b9c4f4e2bcf001bc2c1724ee4286e 100644
--- a/resources/static/dialog/test/qunit/pages/forgot_unit_test.js
+++ b/resources/static/dialog/test/qunit/pages/forgot_unit_test.js
@@ -34,34 +34,24 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
-steal.plugins("jquery").then("/dialog/resources/network", "/dialog/resources/user", "/js/pages/forgot", function() {
+steal.plugins("jquery").then("/dialog/test/qunit/mocks/xhr", "/dialog/resources/network", "/dialog/resources/user", "/js/pages/forgot", function() {
   "use strict";
 
   var bid = BrowserID,
       network = bid.Network,
       user = bid.User,
-      xhrError = false,
+      xhr = bid.Mocks.xhr,
       CHECK_DELAY = 500;
 
-  var netMock = {
-    requestPasswordReset: function(email, origin, onComplete, onFailure) {
-      xhrError ? onFailure() : onComplete(email === "registered@testuser.com");
-    },
-
-    emailRegistered: function(email, onComplete, onFailure) {
-      xhrError ? onFailure() : onComplete(email === "registered@testuser.com");
-    }
-  };
-
   module("pages/forgot", {
     setup: function() {
-      user.setNetwork(netMock);
+      network.setXHR(xhr);
       $(".error").stop().hide();
-      xhrError = false;
+      xhr.useResult("valid");
       bid.forgot();
     },
     teardown: function() {
-      user.setNetwork(network);  
+      network.setXHR($);
       $(".error").stop().hide();
       $(".website").text("");
       bid.forgot.reset();
@@ -70,6 +60,8 @@ steal.plugins("jquery").then("/dialog/resources/network", "/dialog/resources/use
 
   test("requestPasswordReset with invalid email", function() {
     $("#email").val("invalid");
+
+    xhr.useResult("invalid");
     bid.forgot.submit();
 
     setTimeout(function() {
@@ -105,6 +97,8 @@ steal.plugins("jquery").then("/dialog/resources/network", "/dialog/resources/use
   });
 
   test("requestPasswordReset with throttling", function() {
+    xhr.useResult("throttle");
+
     $("#email").val("throttled@testuser.com");
     bid.forgot.submit();
 
@@ -117,7 +111,7 @@ steal.plugins("jquery").then("/dialog/resources/network", "/dialog/resources/use
   });
 
   test("requestPasswordReset with XHR Error", function() {
-    xhrError = true;
+    xhr.useResult("ajaxError");
 
     $("#email").val("testuser@testuser.com");
     bid.forgot.submit();
diff --git a/resources/static/dialog/test/qunit/qunit.js b/resources/static/dialog/test/qunit/qunit.js
index a9c3269bcc65824a35015099d0f540069a3efef3..414860785aafa74b1a0bd39c40630e57ed9fb2d4 100644
--- a/resources/static/dialog/test/qunit/qunit.js
+++ b/resources/static/dialog/test/qunit/qunit.js
@@ -4,7 +4,9 @@ steal("/dialog/resources/browserid.js",
       "/dialog/resources/storage.js",
       "/dialog/resources/tooltip.js",
       "/dialog/resources/validation.js",
-      "/dialog/resources/underscore-min.js")
+      "/dialog/resources/underscore-min.js",
+      "/dialog/test/qunit/mocks/mocks.js",
+      "/dialog/test/qunit/mocks/xhr.js")
   .plugins(
     "jquery", 
     "jquery/controller",
diff --git a/resources/static/dialog/test/qunit/resources/network_unit_test.js b/resources/static/dialog/test/qunit/resources/network_unit_test.js
index 029e8d76cbe40e146a988cd19fed8f77ac8231fb..25b95e2fca5adb2dad7aed5a001dbda30d96779a 100644
--- a/resources/static/dialog/test/qunit/resources/network_unit_test.js
+++ b/resources/static/dialog/test/qunit/resources/network_unit_test.js
@@ -34,10 +34,11 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
-steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", function() {
+steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", "/dialog/test/qunit/mocks/xhr", function() {
   "use strict";
 
-  var testName;
+  var testName,
+  xhr = BrowserID.Mocks.xhr;
 
   function wrappedAsyncTest(name, test) {
     asyncTest(name, function() {
@@ -105,107 +106,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
     stop();
   }
 
-  var network = BrowserID.Network,
-      contextInfo = {
-        server_time: new Date().getTime(),
-        csrf_token: "csrf",
-        authenticated: false
-      };
-
-
-  /**
-   * This is the results table, the keys are the request type, url, and 
-   * a "selector" for testing.  The right is the expected return value, already 
-   * decoded.  If a result is "undefined", the request's error handler will be 
-   * called.
-   */
-  var xhr = {
-    results: {
-      "get /wsapi/session_context valid": contextInfo,   
-      "get /wsapi/session_context invalid": contextInfo,
-      // We are going to test for XHR failures for session_context using 
-      // call to serverTime.  We are going to use the flag contextAjaxError
-      "get /wsapi/session_context ajaxError": contextInfo, 
-      "get /wsapi/session_context throttle": contextInfo, 
-      "get /wsapi/session_context contextAjaxError": undefined,  
-      "post /wsapi/authenticate_user valid": { success: true },
-      "post /wsapi/authenticate_user invalid": { success: false },
-      "post /wsapi/authenticate_user ajaxError": undefined,
-      "post /wsapi/complete_email_addition valid": { success: true },
-      "post /wsapi/complete_email_addition invalid": { success: false },
-      "post /wsapi/complete_email_addition ajaxError": undefined,
-      "post /wsapi/stage_user valid": { success: true },
-      "post /wsapi/stage_user invalid": { success: false },
-      "post /wsapi/stage_user throttle": 403,
-      "post /wsapi/stage_user ajaxError": undefined,
-      "get /wsapi/user_creation_status?email=address notcreated": undefined, // undefined because server returns 400 error
-      "get /wsapi/user_creation_status?email=address pending": { status: "pending" },
-      "get /wsapi/user_creation_status?email=address complete": { status: "complete" },
-      "get /wsapi/user_creation_status?email=address ajaxError": undefined,
-      "post /wsapi/complete_user_creation valid": { success: true },
-      "post /wsapi/complete_user_creation invalid": { success: false },
-      "post /wsapi/complete_user_creation ajaxError": undefined,
-      "post /wsapi/logout valid": { success: true },
-      "post /wsapi/logout ajaxError": undefined,
-      "get /wsapi/have_email?email=address taken": { email_known: true },
-      "get /wsapi/have_email?email=address nottaken" : { email_known: false },
-      "get /wsapi/have_email?email=address ajaxError" : undefined,
-      "post /wsapi/remove_email valid": { success: true },
-      "post /wsapi/remove_email invalid": { success: false },
-      "post /wsapi/remove_email ajaxError": undefined,
-      "post /wsapi/account_cancel valid": { success: true },
-      "post /wsapi/account_cancel invalid": { success: false },
-      "post /wsapi/account_cancel ajaxError": undefined,
-      "post /wsapi/stage_email valid": { success: true },
-      "post /wsapi/stage_email invalid": { success: false },
-      "post /wsapi/stage_email throttle": 403,
-      "post /wsapi/stage_email ajaxError": undefined,
-      "get /wsapi/email_addition_status?email=address notcreated": undefined, // undefined because server returns 400 error
-      "get /wsapi/email_addition_status?email=address pending": { status: "pending" },
-      "get /wsapi/email_addition_status?email=address complete": { status: "complete" },
-      "get /wsapi/email_addition_status?email=address ajaxError": undefined
-    },
-
-    useResult: function(result) {
-      xhr.resultType = result;
-    },
-
-    getLastRequest: function() {
-      return this.req;
-    },
-
-    ajax: function(obj) {
-      //console.log("ajax request");
-      var type = obj.type ? obj.type.toLowerCase() : "get";
-
-      var req = this.req = {
-        type: type,
-        url: obj.url,
-        data: obj.data
-      };
-
-
-      if(type === "post" && !obj.data.csrf) {
-        ok(false, "missing csrf token on POST request");
-      }
-
-      var resName = req.type + " " + req.url + " " + xhr.resultType;
-      var result = xhr.results[resName];
-
-      var type = typeof result;
-      if(!(type == "number" || type == "undefined")) {
-        if(obj.success) {
-          obj.success(result);
-        }
-      }
-      else if (obj.error) {
-        // Invalid result - either invalid URL, invalid GET/POST or 
-        // invalid resultType
-        obj.error({ status: result || 400 }, "errorStatus", "errorThrown");
-      }
-    }
-  }
-
+  var network = BrowserID.Network;
 
   module("/resources/network", {
     setup: function() {
@@ -253,7 +154,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
 
 
   wrappedAsyncTest("checkAuth with valid authentication", function() {
-    contextInfo.authenticated = true;
+    xhr.setContextInfo("authenticated", true);
     network.checkAuth(function onSuccess(authenticated) {
       equal(authenticated, true, "we have an authentication");
       wrappedStart();
@@ -267,7 +168,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
 
   wrappedAsyncTest("checkAuth with invalid authentication", function() {
     xhr.useResult("invalid");
-    contextInfo.authenticated = false;
+    xhr.setContextInfo("authenticated", false);
 
     network.checkAuth(function onSuccess(authenticated) {
       equal(authenticated, false, "we are not authenticated");
@@ -284,7 +185,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
 
   wrappedAsyncTest("checkAuth with XHR failure", function() {
     xhr.useResult("ajaxError");
-    contextInfo.authenticated = false;
+    xhr.setContextInfo("authenticated", false);
 
     // Do not convert this to failureCheck, we do this manually because 
     // checkAuth does not make an XHR request.  Since it does not make an XHR 
@@ -402,7 +303,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   wrappedAsyncTest("checkUserRegistration with pending email", function() {
     xhr.useResult("pending");
 
-    network.checkUserRegistration("address", function(status) {
+    network.checkUserRegistration("registered@testuser.com", function(status) {
       equal(status, "pending");
       wrappedStart();
     }, function onFailure() {
@@ -416,7 +317,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   wrappedAsyncTest("checkUserRegistration with complete email", function() {
     xhr.useResult("complete");
 
-    network.checkUserRegistration("address", function(status) {
+    network.checkUserRegistration("registered@testuser.com", function(status) {
       equal(status, "complete");
       wrappedStart();
     }, function onFailure() {
@@ -428,11 +329,11 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   });
 
   wrappedAsyncTest("checkUserRegistration with XHR failure", function() {
-    notificationCheck(network.checkUserRegistration, "address");
+    notificationCheck(network.checkUserRegistration, "registered@testuser.com");
   });
 
   wrappedAsyncTest("checkUserRegistration with XHR failure", function() {
-    failureCheck(network.checkUserRegistration, "address");
+    failureCheck(network.checkUserRegistration, "registered@testuser.com");
   });
 
   wrappedAsyncTest("completeUserRegistration with valid token", function() {
@@ -505,9 +406,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   });
 
   wrappedAsyncTest("emailRegistered with taken email", function() {
-    xhr.useResult("taken");
-
-    network.emailRegistered("address", function(taken) {
+    network.emailRegistered("registered@testuser.com", function(taken) {
       equal(taken, true, "a taken email is marked taken");
       wrappedStart();
     }, function onFailure() {
@@ -519,9 +418,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   });
 
   wrappedAsyncTest("emailRegistered with nottaken email", function() {
-    xhr.useResult("nottaken");
-
-    network.emailRegistered("address", function(taken) {
+    network.emailRegistered("unregistered@testuser.com", function(taken) {
       equal(taken, false, "a not taken email is not marked taken");
       wrappedStart();
     }, function onFailure() {
@@ -533,11 +430,11 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   });
 
   wrappedAsyncTest("emailRegistered with XHR failure", function() {
-    notificationCheck(network.emailRegistered, "address");
+    notificationCheck(network.emailRegistered, "registered@testuser.com");
   });
 
   wrappedAsyncTest("emailRegistered with XHR failure", function() {
-    failureCheck(network.emailRegistered, "address");
+    failureCheck(network.emailRegistered, "registered@testuser.com");
   });
 
 
@@ -591,7 +488,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   wrappedAsyncTest("checkEmailRegistration pending", function() {
     xhr.useResult("pending");
 
-    network.checkEmailRegistration("address", function(status) {
+    network.checkEmailRegistration("registered@testuser.com", function(status) {
       equal(status, "pending");
       wrappedStart();
     }, function onFailure() {
@@ -605,7 +502,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
   wrappedAsyncTest("checkEmailRegistration complete", function() {
     xhr.useResult("complete");
 
-    network.checkEmailRegistration("address", function(status) {
+    network.checkEmailRegistration("registered@testuser.com", function(status) {
       equal(status, "complete");
       wrappedStart();
     }, function onFailure() {
@@ -746,7 +643,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/network", func
 
   wrappedAsyncTest("serverTime", function() {
     // I am forcing the server time to be 1.25 seconds off.
-    contextInfo.server_time = new Date().getTime() - 1250;
+    xhr.setContextInfo("server_time", new Date().getTime() - 1250);
     network.serverTime(function onSuccess(time) {
       var diff = Math.abs((new Date()) - time);
       equal(1245 < diff && diff < 1255, true, "server time and local time should be less than 100ms different (is " + diff + "ms different)");
diff --git a/resources/static/dialog/test/qunit/resources/user_unit_test.js b/resources/static/dialog/test/qunit/resources/user_unit_test.js
index 568d7d6aa73f93d9a23912d3a754d07c0970d293..387ea689d28d4e43806f2e30a354e8b65d39c021 100644
--- a/resources/static/dialog/test/qunit/resources/user_unit_test.js
+++ b/resources/static/dialog/test/qunit/resources/user_unit_test.js
@@ -40,138 +40,16 @@ var jwcert = require("./jwcert");
 
 steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", function() {
   var lib = BrowserID.User,
-      network = BrowserID.Network,
       storage = BrowserID.Storage,
+      xhr = BrowserID.Mocks.xhr,
       testOrigin = "testOrigin";
 
   // I generated these locally, they are used nowhere else.
   var pubkey = {"algorithm":"RS","n":"56063028070432982322087418176876748072035482898334811368408525596198252519267108132604198004792849077868951906170812540713982954653810539949384712773390200791949565903439521424909576832418890819204354729217207360105906039023299561374098942789996780102073071760852841068989860403431737480182725853899733706069","e":"65537"};
 
-  var privkey = {"algorithm":"RS","n":"56063028070432982322087418176876748072035482898334811368408525596198252519267108132604198004792849077868951906170812540713982954653810539949384712773390200791949565903439521424909576832418890819204354729217207360105906039023299561374098942789996780102073071760852841068989860403431737480182725853899733706069","e":"65537","d":"786150156350274055174913976906933968265264030754683486390396799104417261473770120296370873955240982995278496143719986037141619777024457729427415826765728988003471373990098269492312035966334999128083733012526716409629032119935282516842904344253703738413658199885458117908331858717294515041118355034573371553"};
-
   // this cert is meaningless, but it has the right format
   var random_cert = "eyJhbGciOiJSUzEyOCJ9.eyJpc3MiOiJpc3N1ZXIuY29tIiwiZXhwIjoxMzE2Njk1MzY3NzA3LCJwdWJsaWMta2V5Ijp7ImFsZ29yaXRobSI6IlJTIiwibiI6IjU2MDYzMDI4MDcwNDMyOTgyMzIyMDg3NDE4MTc2ODc2NzQ4MDcyMDM1NDgyODk4MzM0ODExMzY4NDA4NTI1NTk2MTk4MjUyNTE5MjY3MTA4MTMyNjA0MTk4MDA0NzkyODQ5MDc3ODY4OTUxOTA2MTcwODEyNTQwNzEzOTgyOTU0NjUzODEwNTM5OTQ5Mzg0NzEyNzczMzkwMjAwNzkxOTQ5NTY1OTAzNDM5NTIxNDI0OTA5NTc2ODMyNDE4ODkwODE5MjA0MzU0NzI5MjE3MjA3MzYwMTA1OTA2MDM5MDIzMjk5NTYxMzc0MDk4OTQyNzg5OTk2NzgwMTAyMDczMDcxNzYwODUyODQxMDY4OTg5ODYwNDAzNDMxNzM3NDgwMTgyNzI1ODUzODk5NzMzNzA2MDY5IiwiZSI6IjY1NTM3In0sInByaW5jaXBhbCI6eyJlbWFpbCI6InRlc3R1c2VyQHRlc3R1c2VyLmNvbSJ9fQ.aVIO470S_DkcaddQgFUXciGwq2F_MTdYOJtVnEYShni7I6mqBwK3fkdWShPEgLFWUSlVUtcy61FkDnq2G-6ikSx1fUZY7iBeSCOKYlh6Kj9v43JX-uhctRSB2pI17g09EUtvmb845EHUJuoowdBLmLa4DSTdZE-h4xUQ9MsY7Ik";
 
-  var credentialsValid, unknownEmails, keyRefresh, syncValid, userEmails, 
-      userCheckCount = 0,
-      emailCheckCount = 0,
-      registrationResponse,
-      xhrFailure = false,
-      throttle = false,
-      validToken = true; 
-
-  var netStub = {
-    reset: function() {
-      credentialsValid = emailAdded = userAdded = syncValid = true;
-      unknownEmails = [];
-      keyRefresh = [];
-      userEmails = {"testuser@testuser.com": {}};
-      registrationResponse = "complete";
-      xhrFailure = false;
-      throttle = false;
-    },
-
-    checkUserRegistration: function(email, onSuccess, onFailure) {
-      userCheckCount++;
-      var status = userCheckCount === 2 ? registrationResponse : "pending";
-
-      xhrFailure ? onFailure() : onSuccess(status);
-    },
-
-    completeUserRegistration: function(token, password, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(validToken);
-    },
-
-    authenticate: function(email, password, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(credentialsValid);
-    },
-
-    checkAuth: function(onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(credentialsValid);
-    },
-
-    emailRegistered: function(email, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(email === "registered");
-    },
-
-    addEmail: function(email, origin, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(emailAdded);
-    },
-
-    checkEmailRegistration: function(email, onSuccess, onFailure) {
-      emailCheckCount++;
-      var status = emailCheckCount === 2 ? registrationResponse : "pending";
-
-      xhrFailure ? onFailure() : onSuccess(status);
-    },
-
-    emailForVerificationToken: function(token, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess("testuser@testuser.com");
-    },
-
-    completeEmailRegistration: function(token, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(validToken);
-    },
-
-    removeEmail: function(email, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess();
-    },
-
-    listEmails: function(onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(userEmails);
-    },
-
-    certKey: function(email, pubkey, onSuccess, onFailure) {
-      if (syncValid) {
-        xhrFailure ? onFailure() : onSuccess(random_cert);
-      }
-      else {
-        onFailure();
-      }
-    },
-    
-    syncEmails: function(issued_identities, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess({
-        unknown_emails: unknownEmails,
-        key_refresh: keyRefresh
-      });
-    },
-
-    setKey: function(email, keypair, onSuccess, onFailure) {
-      if (syncValid) {
-        xhrFailure ? onFailure() : onSuccess();
-      }
-      else {
-        onFailure();
-      }
-    },
-
-    createUser: function(email, origin, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(userAdded);
-    },
-
-    setPassword: function(password, onSuccess) {
-      xhrFailure ? onFailure() : onSuccess();
-    },
-
-    requestPasswordReset: function(email, origin, onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(!throttle);
-    },
-
-    cancelUser: function(onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess();
-    },
-
-    serverTime: function(onSuccess, onFailure) {
-      xhrFailure ? onFailure() : onSuccess(new Date());
-    },
-
-    logout: function(onSuccess, onFailure) {
-      credentialsValid = false;
-      xhrFailure ? onFailure() : onSuccess();
-    }
-  };
-
 
   function testAssertion(assertion) {
     equal(typeof assertion, "string", "An assertion was correctly generated");
@@ -210,15 +88,12 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   module("resources/user", {
     setup: function() {
-      lib.setNetwork(netStub);
+      BrowserID.Network.setXHR(xhr);
+      xhr.useResult("valid");
       lib.clearStoredEmailKeypairs();
-      netStub.reset();
-      userCheckCount = 0;
-      emailCheckCount = 0;
-      validToken = true;
     },
     teardown: function() {
-      lib.setNetwork(BrowserID.Network);
+      BrowserID.Network.setXHR($);
     }
   });
 
@@ -287,7 +162,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("createUser with user creation refused", function() {
-    userAdded = false
+    xhr.useResult("throttle");
+
     lib.createUser("testuser@testuser.com", function(status) {
       equal(status, false, "user creation refused");
       start();
@@ -297,7 +173,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("createUser with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
     lib.createUser("testuser@testuser.com", function(status) {
       ok(false, "xhr failure should never succeed");
@@ -310,19 +186,12 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
     stop();
   });
 
-  /**
-   * The next three tests use the mock network harness.  The tests are testing 
-   * the polling action and whether `waitForUserValidation` reacts as expected
-   * to the various network responses.  The network harness simulates multiple 
-   * calls to `checkUserRegistration`, attempting to simulate real use 
-   * interaction to verify the email address, the first call to 
-   * `checkUserRegistration` returns `pending`, the second returns the value 
-   * stored in `registrationResponse`.
-   */
   test("waitForUserValidation with `complete` response", function() {
     storage.setStagedOnBehalfOf(testOrigin);
 
-    lib.waitForUserValidation("testuser@testuser.com", function(status) {
+    xhr.useResult("complete");
+
+    lib.waitForUserValidation("registered@testuser.com", function(status) {
       equal(status, "complete", "complete response expected");
 
       ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
@@ -333,11 +202,11 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("waitForUserValidation with `mustAuth` response", function() {
-    registrationResponse = "mustAuth";
-
     storage.setStagedOnBehalfOf(testOrigin);
 
-    lib.waitForUserValidation("testuser@testuser.com", function(status) {
+    xhr.useResult("mustAuth");
+
+    lib.waitForUserValidation("registered@testuser.com", function(status) {
       equal(status, "mustAuth", "mustAuth response expected");
 
       ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
@@ -348,10 +217,10 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("waitForUserValidation with `noRegistration` response", function() {
-    registrationResponse = "noRegistration";
+    xhr.useResult("noRegistration");
 
     storage.setStagedOnBehalfOf(testOrigin);
-    lib.waitForUserValidation("baduser@testuser.com", function(status) {
+    lib.waitForUserValidation("registered@testuser.com", function(status) {
       ok(false, "not expecting success")
 
       start();
@@ -365,10 +234,10 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("waitForUserValidation with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
     storage.setStagedOnBehalfOf(testOrigin);
-    lib.waitForUserValidation("baduser@testuser.com", function(status) {
+    lib.waitForUserValidation("registered@testuser.com", function(status) {
       ok(false, "xhr failure should never succeed");
       start();
     }, function() {
@@ -382,6 +251,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   test("verifyUser with a good token", function() {
     storage.setStagedOnBehalfOf(testOrigin);
+
     lib.verifyUser("token", "password", function onSuccess(info) {
       
       ok(info.valid, "token was valid");
@@ -396,7 +266,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("verifyUser with a bad token", function() {
-    validToken = false;
+    xhr.useResult("invalid");
 
     lib.verifyUser("token", "password", function onSuccess(info) {
       
@@ -410,7 +280,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("verifyUser with an XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
     lib.verifyUser("token", "password", function onSuccess(info) {
       ok(false, "xhr failure should never succeed");
@@ -423,6 +293,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
     stop();
   });
 
+  /*
   test("setPassword", function() {
     lib.setPassword("password", function() {
       // XXX fill this in.
@@ -432,9 +303,9 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
     stop();
   });
-
+*/
   test("requestPasswordReset with known email", function() {
-    lib.requestPasswordReset("registered", function(status) {
+    lib.requestPasswordReset("registered@testuser.com", function(status) {
       equal(status.success, true, "password reset for known user");
       start();
     }, function() {
@@ -446,7 +317,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("requestPasswordReset with unknown email", function() {
-    lib.requestPasswordReset("unregistered", function(status) {
+    lib.requestPasswordReset("unregistered@testuser.com", function(status) {
       equal(status.success, false, "password not reset for unknown user");
       equal(status.reason, "invalid_user", "invalid_user is the reason");
       start();
@@ -459,8 +330,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("requestPasswordReset with throttle", function() {
-    throttle = true;
-    lib.requestPasswordReset("registered", function(status) {
+    xhr.useResult("throttle");
+    lib.requestPasswordReset("registered@testuser.com", function(status) {
       equal(status.success, false, "password not reset for throttle");
       equal(status.reason, "throttle", "password reset was throttled");
       start();
@@ -473,8 +344,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("requestPasswordReset with XHR failure", function() {
-    xhrFailure = true;
-    lib.requestPasswordReset("address", function(status) {
+    xhr.useResult("ajaxError");
+    lib.requestPasswordReset("registered@testuser.com", function(status) {
       ok(false, "xhr failure should never succeed");
       start();
     }, function() {
@@ -498,7 +369,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("authenticate with invalid credentials", function() {
-    credentialsValid = false;
+    xhr.useResult("invalid");
     lib.authenticate("testuser@testuser.com", "testuser", function onComplete(authenticated) {
       equal(false, authenticated, "invalid authentication.");
       start();
@@ -510,7 +381,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("authenticate with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
     lib.authenticate("testuser@testuser.com", "testuser", function onComplete(authenticated) {
       ok(false, "xhr failure should never succeed");
       start();
@@ -525,7 +396,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("checkAuthentication with valid authentication", function() {
-    credentialsValid = true;
+    xhr.setContextInfo("authenticated", true);
     lib.checkAuthentication(function(authenticated) {
       equal(authenticated, true, "We are authenticated!");
       start();
@@ -537,7 +408,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("checkAuthentication with invalid authentication", function() {
-    credentialsValid = false;
+    xhr.setContextInfo("authenticated", false);
     lib.checkAuthentication(function(authenticated) {
       equal(authenticated, false, "We are not authenticated!");
       start();
@@ -549,7 +420,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("checkAuthentication with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("contextAjaxError");
     lib.checkAuthentication(function(authenticated) {
       ok(false, "xhr failure should never succeed");
       start();
@@ -564,7 +435,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("checkAuthenticationAndSync with valid authentication", function() {
-    credentialsValid = true;
+    xhr.setContextInfo("authenticated", true);
+
     lib.checkAuthenticationAndSync(function onSuccess() {},
     function onComplete(authenticated) {
       equal(authenticated, true, "We are authenticated!");
@@ -577,7 +449,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("checkAuthenticationAndSync with invalid authentication", function() {
-    credentialsValid = false;
+    xhr.setContextInfo("authenticated", false);
+
     lib.checkAuthenticationAndSync(function onSuccess() {
         ok(false, "We are not authenticated!");
         start();
@@ -591,9 +464,10 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("checkAuthenticationAndSync with XHR failure", function() {
-    xhrFailure = true;
+    xhr.setContextInfo("authenticated", true);
+    xhr.useResult("ajaxError");
+
     lib.checkAuthenticationAndSync(function onSuccess() {
-      ok(false, "xhr failure should never succeed");
     }, function onComplete() {
       ok(false, "xhr failure should never succeed");
       
@@ -608,7 +482,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("isEmailRegistered with registered email", function() {
-    lib.isEmailRegistered("registered", function(registered) {
+    lib.isEmailRegistered("registered@testuser.com", function(registered) {
       ok(registered);
       start();
     }, function onFailure() {
@@ -619,8 +493,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
     stop();
   });
 
-  test("isEmailRegistered with non-registered email", function() {
-    lib.isEmailRegistered("nonregistered", function(registered) {
+  test("isEmailRegistered with unregistered email", function() {
+    lib.isEmailRegistered("unregistered@testuser.com", function(registered) {
       equal(registered, false);
       start();
     }, function onFailure() {
@@ -632,7 +506,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("isEmailRegistered with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
     lib.isEmailRegistered("registered", function(registered) {
       ok(false, "xhr failure should never succeed");
       start();
@@ -660,7 +534,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("addEmail with addition refused", function() {
-    emailAdded = false;
+    xhr.useResult("throttle");
 
     lib.addEmail("testemail@testemail.com", function(added) {
       equal(added, false, "user addition was refused");
@@ -677,7 +551,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("addEmail with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
     lib.addEmail("testemail@testemail.com", function(added) {
       ok(false, "xhr failure should never succeed");
       start();
@@ -690,20 +564,11 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
 
-
-  /**
-   * The next three tests use the mock network harness.  The tests are testing 
-   * the polling action and whether `waitForEmailValidation` reacts as expected
-   * to the various network responses.  The network harness simulates multiple 
-   * calls to `checkEmailRegistration`, attempting to simulate real use 
-   * interaction to verify the email address, the first call to 
-   * `checkEmailRegistration` returns `pending`, the second returns the value 
-   * stored in `registrationResponse`.
-   */
  test("waitForEmailValidation `complete` response", function() {
     storage.setStagedOnBehalfOf(testOrigin);
 
-    lib.waitForEmailValidation("testemail@testemail.com", function(status) {
+    xhr.useResult("complete");
+    lib.waitForEmailValidation("registered@testuser.com", function(status) {
       ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
       equal(status, "complete", "complete response expected");
       start();
@@ -714,9 +579,9 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   test("waitForEmailValidation `mustAuth` response", function() {
     storage.setStagedOnBehalfOf(testOrigin);
-    registrationResponse = "mustAuth";
+    xhr.useResult("mustAuth");
 
-    lib.waitForEmailValidation("testemail@testemail.com", function(status) {
+    lib.waitForEmailValidation("registered@testuser.com", function(status) {
       ok(!storage.getStagedOnBehalfOf(), "staged on behalf of is cleared when validation completes");
       equal(status, "mustAuth", "mustAuth response expected");
       start();
@@ -727,9 +592,9 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   test("waitForEmailValidation with `noRegistration` response", function() {
     storage.setStagedOnBehalfOf(testOrigin);
-    registrationResponse = "noRegistration";
+    xhr.useResult("noRegistration");
 
-    lib.waitForEmailValidation("baduser@testuser.com", function(status) {
+    lib.waitForEmailValidation("registered@testuser.com", function(status) {
       ok(false, "not expecting success")
       start();
     }, function(status) {
@@ -744,9 +609,9 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
  test("waitForEmailValidation XHR failure", function() {
     storage.setStagedOnBehalfOf(testOrigin);
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
-    lib.waitForEmailValidation("testemail@testemail.com", function(status) {
+    lib.waitForEmailValidation("registered@testuser.com", function(status) {
       ok(false, "xhr failure should never succeed");
       start();
     }, function() {
@@ -775,7 +640,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("verifyEmail with a bad token", function() {
-    validToken = false;
+    xhr.useResult("invalid");
 
     lib.verifyEmail("token", function onSuccess(info) {
       
@@ -789,7 +654,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("verifyEmail with an XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
     lib.verifyEmail("token", function onSuccess(info) {
       ok(false, "xhr failure should never succeed");
@@ -803,7 +668,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("syncEmailKeypair with successful sync", function() {
-    syncValid = true;
     lib.syncEmailKeypair("testemail@testemail.com", function(keypair) {
       var identity = lib.getStoredEmailKeypair("testemail@testemail.com");
 
@@ -819,7 +683,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("syncEmailKeypair with invalid sync", function() {
-    syncValid = false;
+    xhr.useResult("invalid");
     lib.syncEmailKeypair("testemail@testemail.com", function(keypair) {
       ok(false, "sync was invalid, this should have failed");
       start();
@@ -834,7 +698,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("syncEmailKeypair with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
     lib.syncEmailKeypair("testemail@testemail.com", function(keypair) {
       ok(false, "xhr failure should never succeed");
       start();
@@ -874,7 +738,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   test("removeEmail with XHR failure", function() {
     storage.addEmail("testemail@testemail.com", {pub: "pub", priv: "priv"});
 
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
     lib.removeEmail("testemail@testemail.com", function() {
       ok(false, "xhr failure should never succeed");
       start();
@@ -890,8 +754,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("syncEmails with no pre-loaded identities and no identities to add", function() {
-    userEmails = {};
-
+    xhr.useResult("no_identities");
     lib.syncEmails(function onSuccess() {
       var identities = lib.getStoredEmailKeypairs();
       ok(true, "we have synced identities");
@@ -903,8 +766,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("syncEmails with no pre-loaded identities and identities to add", function() {
-    userEmails = {"testuser@testuser.com": {}};
-
     lib.syncEmails(function onSuccess() {
       var identities = lib.getStoredEmailKeypairs();
       ok("testuser@testuser.com" in identities, "Our new email is added");
@@ -916,7 +777,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("syncEmails with identities preloaded and none to add", function() {
-    userEmails = {"testuser@testuser.com": {}};
     storage.addEmail("testuser@testuser.com", {});
     lib.syncEmails(function onSuccess() {
       var identities = lib.getStoredEmailKeypairs();
@@ -931,8 +791,8 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   test("syncEmails with identities preloaded and one to add", function() {
     storage.addEmail("testuser@testuser.com", {pubkey: pubkey, cert: random_cert});
-    userEmails = {"testuser@testuser.com": {pubkey: pubkey, cert: random_cert},
-                  "testuser2@testuser.com": {pubkey: pubkey, cert: random_cert}};
+
+    xhr.useResult("multiple");
 
     lib.syncEmails(function onSuccess() {
       var identities = lib.getStoredEmailKeypairs();
@@ -949,7 +809,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   test("syncEmails with identities preloaded and one to remove", function() {
     storage.addEmail("testuser@testuser.com", {pub: pubkey, cert: random_cert});
     storage.addEmail("testuser2@testuser.com", {pub: pubkey, cert: random_cert});
-    userEmails = {"testuser@testuser.com":  { pub: pubkey, cert: random_cert}};
 
     lib.syncEmails(function onSuccess() {
       var identities = lib.getStoredEmailKeypairs();
@@ -964,7 +823,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   test("syncEmails with one to refresh", function() {
     storage.addEmail("testuser@testuser.com", {pub: pubkey, cert: random_cert});
-    keyRefresh = ["testuser@testuser.com"]; 
 
     lib.syncEmails(function onSuccess() {
       var identities = lib.getStoredEmailKeypairs();
@@ -976,7 +834,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("syncEmails with XHR failure", function() {
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
     lib.syncEmails(function onSuccess() {
       ok(false, "xhr failure should never succeed");
@@ -1027,7 +885,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
   test("getAssertion with XHR failure", function() {
     lib.setOrigin(testOrigin);
-    xhrFailure = true;
+    xhr.useResult("ajaxError");
 
     lib.syncEmailKeypair("testuser@testuser.com", function() {
       ok(false, "xhr failure should never succeed");
@@ -1042,9 +900,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
 
 
   test("logoutUser", function(onSuccess) {
-    credentialsValid = true;
-    keyRefresh = ["testuser@testuser.com"]; 
-
     lib.authenticate("testuser@testuser.com", "testuser", function(authenticated) {
       lib.syncEmails(function() {
         var storedIdentities = storage.getEmails();
@@ -1054,7 +909,6 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
           storedIdentities = storage.getEmails();
           equal(_.size(storedIdentities), 0, "All items have been removed on logout");
 
-          equal(credentialsValid, false, "credentials were invalidated in logout");
           start();
         }, failure("logoutUser failure"));
       }, failure("syncEmails failure"));
@@ -1064,12 +918,9 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("logoutUser with XHR failure", function(onSuccess) {
-    credentialsValid = true;
-    keyRefresh = ["testuser@testuser.com"]; 
-
     lib.authenticate("testuser@testuser.com", "testuser", function(authenticated) {
       lib.syncEmails(function() {
-         xhrFailure = true;
+         xhr.useResult("ajaxError");
 
         lib.logoutUser(function() {
           ok(false, "xhr failure should never succeed");
@@ -1097,7 +948,7 @@ steal.plugins("jquery", "funcunit/qunit").then("/dialog/resources/user", functio
   });
 
   test("cancelUser with XHR failure", function(onSuccess) {
-     xhrFailure = true;
+    xhr.useResult("ajaxError");
     lib.cancelUser(function() {
       ok(false, "xhr failure should never succeed");
       start();