Bug 758777 - Account Provisioner tab should still act normally if persisted and restored. r=bwinton, a=Standard8.
authorMike Conley <mconley@mozilla.com>
Tue, 29 May 2012 13:00:34 -0400
changeset 11359 8b55eb00518123c0098e92d31f950338ae64b933
parent 11358 99054008c3828b89d59f154da5e4d154228d6da0
child 11360 5869020d2976e06b3e48b515235eb69fcc882dd6
push idunknown
push userunknown
push dateunknown
reviewersbwinton, Standard8
bugs758777
Bug 758777 - Account Provisioner tab should still act normally if persisted and restored. r=bwinton, a=Standard8.
mail/components/newmailaccount/content/accountProvisionerTab.js
mail/test/mozmill/newmailaccount/test-newmailaccount.js
mail/test/mozmill/shared-modules/test-newmailaccount-helpers.js
--- a/mail/components/newmailaccount/content/accountProvisionerTab.js
+++ b/mail/components/newmailaccount/content/accountProvisionerTab.js
@@ -8,16 +8,18 @@ let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/gloda/log4moz.js");
 
 /**
  * A content tab for the account provisioner.  We use Javascript-y magic to
  * "subclass" specialTabs.contentTabType, and then override the appropriate
  * members.
+ *
+ * Also note that accountProvisionerTab is a singleton (hence the maxTabs: 1).
  */
 let accountProvisionerTabType = Object.create(specialTabs.contentTabType, {
   name: {value: "accountProvisionerTab"},
   modes: {value: {
     accountProvisionerTab: {
       type: "accountProvisionerTab",
       maxTabs: 1,
     }
@@ -30,34 +32,66 @@ let accountProvisionerTabType = Object.c
  * (for the context of this accountProvisionerTab "aTab") and then passing
  * special arguments "realName", "email" and "searchEngine" from the caller
  * of openTab, and passing those to our _setMonitoring function.
  */
 accountProvisionerTabType.openTab = function(aTab, aArgs) {
   aArgs.clickHandler = "accountProvisionerTabType.clickHandler(event);";
   specialTabs.contentTabType.openTab.call(this, aTab, aArgs);
 
+  // Since there's only one tab of this type ever (see the mode definition),
+  // we're OK to stash this stuff here.
+  this._realName = aArgs.realName;
+  this._email = aArgs.email;
+  this._searchEngine = aArgs.searchEngine || "";
+
   this._setMonitoring(aTab.browser, aArgs.realName, aArgs.email,
                       aArgs.searchEngine);
 }
 
 /**
  * We're overriding closeTab - first, we call the closeTab of contentTab,
  * (for the context of this accountProvisionerTab "aTab"), and then we
  * unregister our observer that was registered in _setMonitoring.
  */
 accountProvisionerTabType.closeTab = function(aTab) {
   specialTabs.contentTabType.closeTab.call(this, aTab);
   this._log.info("Performing account provisioner cleanup");
   this._log.info("Removing httpRequestObserver");
   Services.obs.removeObserver(this._observer, "http-on-examine-response");
+  delete this._observer;
   this._log.info("Account provisioner cleanup is done.");
 }
 
 /**
+ * Serialize our tab into something we can restore later.
+ */
+accountProvisionerTabType.persistTab = function(aTab) {
+  return {
+    tabURI: aTab.browser.currentURI.spec,
+    realName: this._realName,
+    email: this._email,
+    searchEngine: this._searchEngine
+  };
+}
+
+/**
+ * Re-open the accountProvisionerTab with all of the stuff we stashed in
+ * persistTab. This will automatically hook up our monitoring again.
+ */
+accountProvisionerTabType.restoreTab = function(aTabmail, aPersistedState) {
+  aTabmail.openTab("accountProvisionerTab",
+                   { contentPage: aPersistedState.tabURI,
+                     realName: aPersistedState.realName,
+                     email: aPersistedState.email,
+                     searchEngine: aPersistedState.searchEngine,
+                     background: true } );
+}
+
+/**
  * This function registers an observer to watch for HTTP requests where the
  * contentType contains text/xml.
  */
 accountProvisionerTabType._setMonitoring = function(aBrowser, aRealName,
                                                     aEmail, aSearchEngine) {
   let mail3Pane = Cc["@mozilla.org/appshell/window-mediator;1"]
         .getService(Ci.nsIWindowMediator)
         .getMostRecentWindow("mail:3pane");
--- a/mail/test/mozmill/newmailaccount/test-newmailaccount.js
+++ b/mail/test/mozmill/newmailaccount/test-newmailaccount.js
@@ -138,33 +138,49 @@ function nAccounts() {
  * on an address, completes a dummy form in a new tab for getting the account,
  * and then sets the provider as the default search engine.
  *
  * It gets a little complicated, since the modal dialog for the provisioner
  * spins it's own event loop, so we have to have subtest functions.  Therefore,
  * this test is split over 3 functions, and uses a global gNumAccounts.  The
  * three functions are "test_get_an_account", "subtest_get_an_account",
  * and "subtest_get_an_account_part_2".
+ *
+ * @param aCloseAndRestore a boolean for whether or not we should close and
+ *                         restore the Account Provisioner tab before filling
+ *                         in the form. Defaults to false.
  */
-function test_get_an_account() {
+function test_get_an_account(aCloseAndRestore) {
+  let originalEngine = Services.search.currentEngine;
   // Open the provisioner - once opened, let subtest_get_an_account run.
   plan_for_modal_dialog("AccountCreation", subtest_get_an_account);
   open_provisioner_window();
   wait_for_modal_dialog("AccountCreation");
 
   // Once we're here, subtest_get_an_account has completed, and we're waiting
   // for a content tab to load for the account order form.
 
   // Make sure the page is loaded.
   wait_for_content_tab_load(undefined, function (aURL) {
     return aURL.host == "localhost";
   });
 
   let tab = mc.tabmail.currentTabInfo;
 
+  if (aCloseAndRestore) {
+    // Close the account provisioner tab, and then restore it...
+    mc.tabmail.closeTab(mc.tabmail.currentTabInfo);
+    mc.tabmail.undoCloseTab();
+    // Wait for the page to be loaded again...
+    wait_for_content_tab_load(undefined, function (aURL) {
+      return aURL.host == "localhost";
+    });
+    tab = mc.tabmail.currentTabInfo;
+  }
+
   // Record how many accounts we start with.
   gNumAccounts = nAccounts();
 
   // Plan for the account provisioner window to re-open, and then run the
   // controller through subtest_get_an_account_part_2. Since the Account
   // Provisioner dialog is non-modal in the event of success, we use our
   // normal window handlers.
   plan_for_new_window("AccountCreation");
@@ -177,16 +193,20 @@ function test_get_an_account() {
 
   plan_for_window_close(ac);
   subtest_get_an_account_part_2(ac);
   wait_for_window_close();
 
   // Make sure we set the default search engine
   let engine = Services.search.getEngineByName("bar");
   assert_equals(engine, Services.search.currentEngine);
+
+  // Restore the original search engine.
+  Services.search.currentEngine = originalEngine;
+  remove_email_account("green@example.com");
 }
 
 /**
  * This is a subtest for test_get_an_account, and runs the first time the
  * account provisioner window is opened.
  */
 function subtest_get_an_account(w) {
   // Make sure we don't have bar as the default engine yet.
@@ -231,16 +251,24 @@ function subtest_get_an_account_part_2(w
   // Make sure the search engine is checked
   assert_true($("#search_engine_check").is(":checked"));
 
   // Then click "Finish"
   mc.click(w.eid("closeWindow"));
 }
 
 /**
+ * Runs test_get_an_account again, but this time, closes and restores the
+ * order form tab before submitting it.
+ */
+function test_restored_ap_tab_works() {
+  test_get_an_account(true);
+}
+
+/**
  * Test that clicking on the "I think I'll configure my account later"
  * button dismisses the Account Provisioner window.
  */
 function test_can_dismiss_account_provisioner() {
   plan_for_modal_dialog("AccountCreation", subtest_can_dismiss_account_provisioner);
   open_provisioner_window();
   wait_for_modal_dialog("AccountCreation");
 }
--- a/mail/test/mozmill/shared-modules/test-newmailaccount-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-newmailaccount-helpers.js
@@ -68,16 +68,17 @@ function installInto(module) {
   module.wait_for_element_invisible = wait_for_element_invisible;
   module.open_provisioner_window = open_provisioner_window;
   module.wait_for_the_wizard_to_be_closed = wait_for_the_wizard_to_be_closed;
   module.assert_links_shown = assert_links_shown;
   module.assert_links_not_shown = assert_links_not_shown;
   module.wait_for_search_results = wait_for_search_results;
   module.gConsoleListener = gConsoleListener;
   module.wait_to_be_offline = wait_to_be_offline;
+  module.remove_email_account = remove_email_account;
 }
 
 /* Wait until the list of providers is loaded and displayed.
  */
 function wait_for_provider_list_loaded(aController) {
   mc.waitFor(function() {
     return aController.window.EmailAccountProvisioner.loadedProviders;
   },
@@ -182,16 +183,31 @@ function wait_for_search_results(w) {
  */
 function wait_to_be_offline(w) {
   mc.waitFor(function() {
     return w.window.$("#cannotConnectMessage").is(":visible");
   }, "Timed out waiting for the account provisioner to be in "
     + "offline mode.");
 }
 
+/**
+ * Remove an account with address aAddress from the current profile.
+ *
+ * @param aAddress the email address to try to remove.
+ */
+function remove_email_account(aAddress) {
+  for each (let account in fixIterator(MailServices.accounts.accounts,
+                                       Ci.nsIMsgAccount)) {
+    if (account.defaultIdentity.email == aAddress) {
+      MailServices.accounts.removeAccount(account);
+      break;
+    }
+  }
+}
+
 /* A listener for the Error Console, which allows us to ensure that certain
  * messages appear in the console.
  */
 var gConsoleListener = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
   _msg: null,
   _sawMsg: false,