Backout changeset 958669938c10 / bug 1225832 due to frequent mochitest failures on Mac
authorMark Banner <standard8@mozilla.com>
Fri, 27 Nov 2015 18:36:56 +0000
changeset 308610 f48352b311eb120a09347efce60ae9045401858c
parent 308609 0662e2b6175e7282c05af83bd1478209dc61dcf0
child 308611 894843a94668aafe3fb08b35b3dfb1085b96c0b7
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1225832
milestone45.0a1
backs out958669938c10f37112896f1f47e8ed8074c1495d
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout changeset 958669938c10 / bug 1225832 due to frequent mochitest failures on Mac
browser/components/loop/content/js/conversation.js
browser/components/loop/content/js/conversation.jsx
browser/components/loop/content/js/conversationAppStore.js
browser/components/loop/content/js/panel.js
browser/components/loop/content/js/panel.jsx
browser/components/loop/content/js/roomViews.js
browser/components/loop/content/js/roomViews.jsx
browser/components/loop/content/shared/js/loopapi-client.js
browser/components/loop/modules/MozLoopAPI.jsm
browser/components/loop/run-all-loop-tests.sh
browser/components/loop/test/desktop-local/conversationAppStore_test.js
browser/components/loop/test/desktop-local/conversation_test.js
browser/components/loop/test/desktop-local/panel_test.js
browser/components/loop/test/desktop-local/roomViews_test.js
browser/components/loop/test/shared/loopapi-client_test.js
browser/components/loop/ui/fake-mozLoop.js
browser/components/uitour/test/browser.ini
browser/components/uitour/test/browser_UITour_loop.js
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -86,77 +86,58 @@ loop.conversation = (function(mozL10n) {
       }
     }
   });
 
   /**
    * Conversation initialisation.
    */
   function init() {
-    // Obtain the windowId and pass it through
-    var locationHash = loop.shared.utils.locationData().hash;
-    var windowId;
-
-    var hash = locationHash.match(/#(.*)/);
-    if (hash) {
-      windowId = hash[1];
-    }
-
-    var requests = [
+    return loop.requestMulti(
       ["GetAllConstants"],
       ["GetAllStrings"],
       ["GetLocale"],
       ["GetLoopPref", "ot.guid"],
       ["GetLoopPref", "textChat.enabled"],
       ["GetLoopPref", "feedback.periodSec"],
       ["GetLoopPref", "feedback.dateLastSeenSec"]
-    ];
-    var prefetch = [
-      ["GetConversationWindowData", windowId]
-    ];
-
-    return loop.requestMulti.apply(null, requests.concat(prefetch)).then(function(results) {
-      // `requestIdx` is keyed off the order of the `requests` and `prefetch`
-      // arrays. Be careful to update both when making changes.
-      var requestIdx = 0;
-      var constants = results[requestIdx];
+    ).then(function(results) {
+      var constants = results[0];
       // Do the initial L10n setup, we do this before anything
       // else to ensure the L10n environment is setup correctly.
-      var stringBundle = results[++requestIdx];
-      var locale = results[++requestIdx];
+      var stringBundle = results[1];
+      var locale = results[2];
       mozL10n.initialize({
         locale: locale,
         getStrings: function(key) {
           if (!(key in stringBundle)) {
             console.error("No string found for key: ", key);
             return "{ textContent: '' }";
           }
 
           return JSON.stringify({ textContent: stringBundle[key] });
         }
       });
 
       // Plug in an alternate client ID mechanism, as localStorage and cookies
       // don't work in the conversation window
-      var currGuid = results[++requestIdx];
       window.OT.overrideGuidStorage({
         get: function(callback) {
-          callback(null, currGuid);
+          callback(null, results[3]);
         },
         set: function(guid, callback) {
           // See nsIPrefBranch
           var PREF_STRING = 32;
-          currGuid = guid;
           loop.request("SetLoopPref", "ot.guid", guid, PREF_STRING);
           callback(null);
         }
       });
 
       // We want data channels only if the text chat preference is enabled.
-      var useDataChannels = results[++requestIdx];
+      var useDataChannels = results[4];
 
       var dispatcher = new loop.Dispatcher();
       var sdkDriver = new loop.OTSdkDriver({
         constants: constants,
         isDesktop: true,
         useDataChannels: useDataChannels,
         dispatcher: dispatcher,
         sdk: OT
@@ -168,38 +149,41 @@ loop.conversation = (function(mozL10n) {
       // Create the stores.
       var activeRoomStore = new loop.store.ActiveRoomStore(dispatcher, {
         isDesktop: true,
         sdkDriver: sdkDriver
       });
       var conversationAppStore = new loop.store.ConversationAppStore({
         activeRoomStore: activeRoomStore,
         dispatcher: dispatcher,
-        feedbackPeriod: results[++requestIdx],
-        feedbackTimestamp: results[++requestIdx]
+        feedbackPeriod: results[5],
+        feedbackTimestamp: results[6]
       });
-
-      prefetch.forEach(function(req) {
-        req.shift();
-        loop.storeRequest(req, results[++requestIdx]);
-      });
-
       var roomStore = new loop.store.RoomStore(dispatcher, {
         activeRoomStore: activeRoomStore,
         constants: constants
       });
       var textChatStore = new loop.store.TextChatStore(dispatcher, {
         sdkDriver: sdkDriver
       });
 
       loop.store.StoreMixin.register({
         conversationAppStore: conversationAppStore,
         textChatStore: textChatStore
       });
 
+      // Obtain the windowId and pass it through
+      var locationHash = loop.shared.utils.locationData().hash;
+      var windowId;
+
+      var hash = locationHash.match(/#(.*)/);
+      if (hash) {
+        windowId = hash[1];
+      }
+
       React.render(
         React.createElement(AppControllerView, {
           dispatcher: dispatcher, 
           roomStore: roomStore}), document.querySelector("#main"));
 
       document.documentElement.setAttribute("lang", mozL10n.getLanguage());
       document.documentElement.setAttribute("dir", mozL10n.getDirection());
       document.body.setAttribute("platform", loop.shared.utils.getPlatform());
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -86,77 +86,58 @@ loop.conversation = (function(mozL10n) {
       }
     }
   });
 
   /**
    * Conversation initialisation.
    */
   function init() {
-    // Obtain the windowId and pass it through
-    var locationHash = loop.shared.utils.locationData().hash;
-    var windowId;
-
-    var hash = locationHash.match(/#(.*)/);
-    if (hash) {
-      windowId = hash[1];
-    }
-
-    var requests = [
+    return loop.requestMulti(
       ["GetAllConstants"],
       ["GetAllStrings"],
       ["GetLocale"],
       ["GetLoopPref", "ot.guid"],
       ["GetLoopPref", "textChat.enabled"],
       ["GetLoopPref", "feedback.periodSec"],
       ["GetLoopPref", "feedback.dateLastSeenSec"]
-    ];
-    var prefetch = [
-      ["GetConversationWindowData", windowId]
-    ];
-
-    return loop.requestMulti.apply(null, requests.concat(prefetch)).then(function(results) {
-      // `requestIdx` is keyed off the order of the `requests` and `prefetch`
-      // arrays. Be careful to update both when making changes.
-      var requestIdx = 0;
-      var constants = results[requestIdx];
+    ).then(function(results) {
+      var constants = results[0];
       // Do the initial L10n setup, we do this before anything
       // else to ensure the L10n environment is setup correctly.
-      var stringBundle = results[++requestIdx];
-      var locale = results[++requestIdx];
+      var stringBundle = results[1];
+      var locale = results[2];
       mozL10n.initialize({
         locale: locale,
         getStrings: function(key) {
           if (!(key in stringBundle)) {
             console.error("No string found for key: ", key);
             return "{ textContent: '' }";
           }
 
           return JSON.stringify({ textContent: stringBundle[key] });
         }
       });
 
       // Plug in an alternate client ID mechanism, as localStorage and cookies
       // don't work in the conversation window
-      var currGuid = results[++requestIdx];
       window.OT.overrideGuidStorage({
         get: function(callback) {
-          callback(null, currGuid);
+          callback(null, results[3]);
         },
         set: function(guid, callback) {
           // See nsIPrefBranch
           var PREF_STRING = 32;
-          currGuid = guid;
           loop.request("SetLoopPref", "ot.guid", guid, PREF_STRING);
           callback(null);
         }
       });
 
       // We want data channels only if the text chat preference is enabled.
-      var useDataChannels = results[++requestIdx];
+      var useDataChannels = results[4];
 
       var dispatcher = new loop.Dispatcher();
       var sdkDriver = new loop.OTSdkDriver({
         constants: constants,
         isDesktop: true,
         useDataChannels: useDataChannels,
         dispatcher: dispatcher,
         sdk: OT
@@ -168,38 +149,41 @@ loop.conversation = (function(mozL10n) {
       // Create the stores.
       var activeRoomStore = new loop.store.ActiveRoomStore(dispatcher, {
         isDesktop: true,
         sdkDriver: sdkDriver
       });
       var conversationAppStore = new loop.store.ConversationAppStore({
         activeRoomStore: activeRoomStore,
         dispatcher: dispatcher,
-        feedbackPeriod: results[++requestIdx],
-        feedbackTimestamp: results[++requestIdx]
+        feedbackPeriod: results[5],
+        feedbackTimestamp: results[6]
       });
-
-      prefetch.forEach(function(req) {
-        req.shift();
-        loop.storeRequest(req, results[++requestIdx]);
-      });
-
       var roomStore = new loop.store.RoomStore(dispatcher, {
         activeRoomStore: activeRoomStore,
         constants: constants
       });
       var textChatStore = new loop.store.TextChatStore(dispatcher, {
         sdkDriver: sdkDriver
       });
 
       loop.store.StoreMixin.register({
         conversationAppStore: conversationAppStore,
         textChatStore: textChatStore
       });
 
+      // Obtain the windowId and pass it through
+      var locationHash = loop.shared.utils.locationData().hash;
+      var windowId;
+
+      var hash = locationHash.match(/#(.*)/);
+      if (hash) {
+        windowId = hash[1];
+      }
+
       React.render(
         <AppControllerView
           dispatcher={dispatcher}
           roomStore={roomStore} />, document.querySelector("#main"));
 
       document.documentElement.setAttribute("lang", mozL10n.getLanguage());
       document.documentElement.setAttribute("dir", mozL10n.getDirection());
       document.body.setAttribute("platform", loop.shared.utils.getPlatform());
--- a/browser/components/loop/content/js/conversationAppStore.js
+++ b/browser/components/loop/content/js/conversationAppStore.js
@@ -101,29 +101,29 @@ loop.store.ConversationAppStore = (funct
 
     /**
      * Handles the get window data action - obtains the window data,
      * updates the store and notifies interested components.
      *
      * @param {sharedActions.GetWindowData} actionData The action data
      */
     getWindowData: function(actionData) {
-      var windowData = loop.getStoredRequest(["GetConversationWindowData",
-        actionData.windowId]);
+      loop.request("GetConversationWindowData", actionData.windowId)
+        .then(function(windowData) {
+          if (!windowData) {
+            console.error("Failed to get the window data");
+            this.setStoreState({ windowType: "failed" });
+            return;
+          }
 
-      if (!windowData) {
-        console.error("Failed to get the window data");
-        this.setStoreState({ windowType: "failed" });
-        return;
-      }
+          this.setStoreState({ windowType: windowData.type });
 
-      this.setStoreState({ windowType: windowData.type });
-
-      this._dispatcher.dispatch(new loop.shared.actions.SetupWindowData(_.extend({
-        windowId: actionData.windowId }, windowData)));
+          this._dispatcher.dispatch(new loop.shared.actions.SetupWindowData(_.extend({
+            windowId: actionData.windowId }, windowData)));
+        }.bind(this));
     },
 
     /**
      * Event handler; invoked when the 'unload' event is dispatched from the
      * window object.
      * It will dispatch a 'WindowUnload' action that other stores may listen to
      * and will remove all event handlers attached to the window object.
      */
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -15,17 +15,17 @@ loop.panel = (function(_, mozL10n) {
 
   var GettingStartedView = React.createClass({displayName: "GettingStartedView",
     mixins: [sharedMixins.WindowCloseMixin],
 
     handleButtonClick: function() {
       loop.requestMulti(
         ["OpenGettingStartedTour", "getting-started"],
         ["SetLoopPref", "gettingStarted.seen", true]);
-      var event = new CustomEvent("GettingStartedSeen", { detail: true });
+      var event = new CustomEvent("GettingStartedSeen");
       window.dispatchEvent(event);
       this.closeWindow();
     },
 
     render: function() {
       return (
         React.createElement("div", {className: "fte-get-started-content"}, 
           React.createElement("header", {className: "fte-title"}, 
@@ -89,21 +89,33 @@ loop.panel = (function(_, mozL10n) {
     }
   });
 
   var ToSView = React.createClass({displayName: "ToSView",
     mixins: [sharedMixins.WindowCloseMixin],
 
     getInitialState: function() {
       return {
-        terms_of_use_url: loop.getStoredRequest(["GetLoopPref", "legal.ToS_url"]),
-        privacy_notice_url: loop.getStoredRequest(["GetLoopPref", "legal.privacy_url"])
+        terms_of_use_url: null,
+        privacy_notice_url: null
       };
     },
 
+    componentWillMount: function() {
+      loop.requestMulti(
+        ["GetLoopPref", "legal.ToS_url"],
+        ["GetLoopPref", "legal.privacy_url"]
+      ).then(function(results) {
+        this.setState({
+          terms_of_use_url: results[0],
+          privacy_notice_url: results[1]
+        });
+      }.bind(this));
+    },
+
     handleLinkClick: function(event) {
       if (!event.target || !event.target.href) {
         return;
       }
 
       event.preventDefault();
       loop.request("OpenURL", event.target.href);
       this.closeWindow();
@@ -180,38 +192,46 @@ loop.panel = (function(_, mozL10n) {
   /**
    * Panel settings (gear) menu.
    */
   var SettingsDropdown = React.createClass({displayName: "SettingsDropdown",
     mixins: [sharedMixins.DropdownMenuMixin(), sharedMixins.WindowCloseMixin],
 
     getInitialState: function() {
       return {
-        signedIn: !!loop.getStoredRequest(["GetUserProfile"]),
-        fxAEnabled: loop.getStoredRequest(["GetFxAEnabled"]),
-        doNotDisturb: loop.getStoredRequest(["GetDoNotDisturb"])
+        doNotDisturb: false,
+        fxAEnabled: false,
+        signedIn: false
       };
     },
 
+    componentWillMount: function() {
+      this._updateState();
+    },
+
     componentWillUpdate: function(nextProps, nextState) {
       if (nextState.showMenu !== this.state.showMenu) {
-        loop.requestMulti(
-          ["GetUserProfile"],
-          ["GetFxAEnabled"],
-          ["GetDoNotDisturb"]
-        ).then(function(results) {
-          this.setState({
-            signedIn: !!results[0],
-            fxAEnabled: results[1],
-            doNotDisturb: results[2]
-          });
-        }.bind(this));
+        this._updateState();
       }
     },
 
+    _updateState: function() {
+      loop.requestMulti(
+        ["GetUserProfile"],
+        ["GetFxAEnabled"],
+        ["GetDoNotDisturb"]
+      ).then(function(results) {
+        this.setState({
+          signedIn: !!results[0],
+          fxAEnabled: results[1],
+          doNotDisturb: results[2]
+        });
+      }.bind(this));
+    },
+
     handleClickSettingsEntry: function() {
       // XXX to be implemented at the same time as unhiding the entry
     },
 
     handleClickAccountEntry: function() {
       loop.request("OpenFxASettings");
       this.closeWindow();
     },
@@ -897,21 +917,21 @@ loop.panel = (function(_, mozL10n) {
     getDefaultProps: function() {
       return {
         gettingStartedSeen: true
       };
     },
 
     getInitialState: function() {
       return {
-        fxAEnabled: loop.getStoredRequest(["GetFxAEnabled"]),
-        hasEncryptionKey: loop.getStoredRequest(["GetHasEncryptionKey"]),
-        userProfile: loop.getStoredRequest(["GetUserProfile"]),
-        gettingStartedSeen: loop.getStoredRequest(["GetLoopPref", "gettingStarted.seen"]),
-        multiProcessEnabled: loop.getStoredRequest(["IsMultiProcessEnabled"])
+        fxAEnabled: true,
+        hasEncryptionKey: false,
+        userProfile: null,
+        gettingStartedSeen: true,
+        multiProcessEnabled: false
       };
     },
 
     _serviceErrorToShow: function(callback) {
       return new Promise(function(resolve) {
         loop.request("GetErrors").then(function(errors) {
           if (!errors || !Object.keys(errors).length) {
             resolve(null);
@@ -958,22 +978,42 @@ loop.panel = (function(_, mozL10n) {
           this.setState({ hasEncryptionKey: hasEncryptionKey });
         } else {
           this.setState({ userProfile: profile });
         }
         this.updateServiceErrors();
       }.bind(this));
     },
 
-    _gettingStartedSeen: function(e) {
-      this.setState({ gettingStartedSeen: !!e.detail });
+    _gettingStartedSeen: function() {
+      loop.request("GetLoopPref", "gettingStarted.seen").then(function(result) {
+        this.setState({
+          gettingStartedSeen: result
+        });
+      }.bind(this));
     },
 
     componentWillMount: function() {
       this.updateServiceErrors();
+
+      loop.requestMulti(
+        ["GetFxAEnabled"],
+        ["GetHasEncryptionKey"],
+        ["GetUserProfile"],
+        ["GetLoopPref", "gettingStarted.seen"],
+        ["IsMultiProcessEnabled"]
+      ).then(function(results) {
+        this.setState({
+          fxAEnabled: results[0],
+          hasEncryptionKey: results[1],
+          userProfile: results[2],
+          gettingStartedSeen: results[3],
+          multiProcessEnabled: results[4]
+        });
+      }.bind(this));
     },
 
     componentDidMount: function() {
       loop.subscribe("LoopStatusChanged", this._onStatusChanged);
       window.addEventListener("GettingStartedSeen", this._gettingStartedSeen);
     },
 
     componentWillUnmount: function() {
@@ -1039,61 +1079,41 @@ loop.panel = (function(_, mozL10n) {
       );
     }
   });
 
   /**
    * Panel initialisation.
    */
   function init() {
-    var requests = [
+    return loop.requestMulti(
       ["GetAllConstants"],
       ["GetAllStrings"],
       ["GetLocale"],
       ["GetPluralRule"]
-    ];
-    var prefetch = [
-      ["GetLoopPref", "gettingStarted.seen"],
-      ["GetLoopPref", "legal.ToS_url"],
-      ["GetLoopPref", "legal.privacy_url"],
-      ["GetUserProfile"],
-      ["GetFxAEnabled"],
-      ["GetDoNotDisturb"],
-      ["GetHasEncryptionKey"],
-      ["IsMultiProcessEnabled"]
-    ];
-
-    return loop.requestMulti.apply(null, requests.concat(prefetch)).then(function(results) {
-      // `requestIdx` is keyed off the order of the `requests` and `prefetch`
-      // arrays. Be careful to update both when making changes.
-      var requestIdx = 0;
-      var constants = results[requestIdx];
+    ).then(function(results) {
+      var constants = results[0];
       // Do the initial L10n setup, we do this before anything
       // else to ensure the L10n environment is setup correctly.
-      var stringBundle = results[++requestIdx];
-      var locale = results[++requestIdx];
-      var pluralRule = results[++requestIdx];
+      var stringBundle = results[1];
+      var locale = results[2];
+      var pluralRule = results[3];
       mozL10n.initialize({
         locale: locale,
         pluralRule: pluralRule,
         getStrings: function(key) {
           if (!(key in stringBundle)) {
             console.error("No string found for key: ", key);
             return "{ textContent: '' }";
           }
 
           return JSON.stringify({ textContent: stringBundle[key] });
         }
       });
 
-      prefetch.forEach(function(req) {
-        req.shift();
-        loop.storeRequest(req, results[++requestIdx]);
-      });
-
       var notifications = new sharedModels.NotificationCollection();
       var dispatcher = new loop.Dispatcher();
       var roomStore = new loop.store.RoomStore(dispatcher, {
         notifications: notifications,
         constants: constants
       });
 
       React.render(React.createElement(PanelView, {
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -15,17 +15,17 @@ loop.panel = (function(_, mozL10n) {
 
   var GettingStartedView = React.createClass({
     mixins: [sharedMixins.WindowCloseMixin],
 
     handleButtonClick: function() {
       loop.requestMulti(
         ["OpenGettingStartedTour", "getting-started"],
         ["SetLoopPref", "gettingStarted.seen", true]);
-      var event = new CustomEvent("GettingStartedSeen", { detail: true });
+      var event = new CustomEvent("GettingStartedSeen");
       window.dispatchEvent(event);
       this.closeWindow();
     },
 
     render: function() {
       return (
         <div className="fte-get-started-content">
           <header className="fte-title">
@@ -89,21 +89,33 @@ loop.panel = (function(_, mozL10n) {
     }
   });
 
   var ToSView = React.createClass({
     mixins: [sharedMixins.WindowCloseMixin],
 
     getInitialState: function() {
       return {
-        terms_of_use_url: loop.getStoredRequest(["GetLoopPref", "legal.ToS_url"]),
-        privacy_notice_url: loop.getStoredRequest(["GetLoopPref", "legal.privacy_url"])
+        terms_of_use_url: null,
+        privacy_notice_url: null
       };
     },
 
+    componentWillMount: function() {
+      loop.requestMulti(
+        ["GetLoopPref", "legal.ToS_url"],
+        ["GetLoopPref", "legal.privacy_url"]
+      ).then(function(results) {
+        this.setState({
+          terms_of_use_url: results[0],
+          privacy_notice_url: results[1]
+        });
+      }.bind(this));
+    },
+
     handleLinkClick: function(event) {
       if (!event.target || !event.target.href) {
         return;
       }
 
       event.preventDefault();
       loop.request("OpenURL", event.target.href);
       this.closeWindow();
@@ -180,38 +192,46 @@ loop.panel = (function(_, mozL10n) {
   /**
    * Panel settings (gear) menu.
    */
   var SettingsDropdown = React.createClass({
     mixins: [sharedMixins.DropdownMenuMixin(), sharedMixins.WindowCloseMixin],
 
     getInitialState: function() {
       return {
-        signedIn: !!loop.getStoredRequest(["GetUserProfile"]),
-        fxAEnabled: loop.getStoredRequest(["GetFxAEnabled"]),
-        doNotDisturb: loop.getStoredRequest(["GetDoNotDisturb"])
+        doNotDisturb: false,
+        fxAEnabled: false,
+        signedIn: false
       };
     },
 
+    componentWillMount: function() {
+      this._updateState();
+    },
+
     componentWillUpdate: function(nextProps, nextState) {
       if (nextState.showMenu !== this.state.showMenu) {
-        loop.requestMulti(
-          ["GetUserProfile"],
-          ["GetFxAEnabled"],
-          ["GetDoNotDisturb"]
-        ).then(function(results) {
-          this.setState({
-            signedIn: !!results[0],
-            fxAEnabled: results[1],
-            doNotDisturb: results[2]
-          });
-        }.bind(this));
+        this._updateState();
       }
     },
 
+    _updateState: function() {
+      loop.requestMulti(
+        ["GetUserProfile"],
+        ["GetFxAEnabled"],
+        ["GetDoNotDisturb"]
+      ).then(function(results) {
+        this.setState({
+          signedIn: !!results[0],
+          fxAEnabled: results[1],
+          doNotDisturb: results[2]
+        });
+      }.bind(this));
+    },
+
     handleClickSettingsEntry: function() {
       // XXX to be implemented at the same time as unhiding the entry
     },
 
     handleClickAccountEntry: function() {
       loop.request("OpenFxASettings");
       this.closeWindow();
     },
@@ -897,21 +917,21 @@ loop.panel = (function(_, mozL10n) {
     getDefaultProps: function() {
       return {
         gettingStartedSeen: true
       };
     },
 
     getInitialState: function() {
       return {
-        fxAEnabled: loop.getStoredRequest(["GetFxAEnabled"]),
-        hasEncryptionKey: loop.getStoredRequest(["GetHasEncryptionKey"]),
-        userProfile: loop.getStoredRequest(["GetUserProfile"]),
-        gettingStartedSeen: loop.getStoredRequest(["GetLoopPref", "gettingStarted.seen"]),
-        multiProcessEnabled: loop.getStoredRequest(["IsMultiProcessEnabled"])
+        fxAEnabled: true,
+        hasEncryptionKey: false,
+        userProfile: null,
+        gettingStartedSeen: true,
+        multiProcessEnabled: false
       };
     },
 
     _serviceErrorToShow: function(callback) {
       return new Promise(function(resolve) {
         loop.request("GetErrors").then(function(errors) {
           if (!errors || !Object.keys(errors).length) {
             resolve(null);
@@ -958,22 +978,42 @@ loop.panel = (function(_, mozL10n) {
           this.setState({ hasEncryptionKey: hasEncryptionKey });
         } else {
           this.setState({ userProfile: profile });
         }
         this.updateServiceErrors();
       }.bind(this));
     },
 
-    _gettingStartedSeen: function(e) {
-      this.setState({ gettingStartedSeen: !!e.detail });
+    _gettingStartedSeen: function() {
+      loop.request("GetLoopPref", "gettingStarted.seen").then(function(result) {
+        this.setState({
+          gettingStartedSeen: result
+        });
+      }.bind(this));
     },
 
     componentWillMount: function() {
       this.updateServiceErrors();
+
+      loop.requestMulti(
+        ["GetFxAEnabled"],
+        ["GetHasEncryptionKey"],
+        ["GetUserProfile"],
+        ["GetLoopPref", "gettingStarted.seen"],
+        ["IsMultiProcessEnabled"]
+      ).then(function(results) {
+        this.setState({
+          fxAEnabled: results[0],
+          hasEncryptionKey: results[1],
+          userProfile: results[2],
+          gettingStartedSeen: results[3],
+          multiProcessEnabled: results[4]
+        });
+      }.bind(this));
     },
 
     componentDidMount: function() {
       loop.subscribe("LoopStatusChanged", this._onStatusChanged);
       window.addEventListener("GettingStartedSeen", this._gettingStartedSeen);
     },
 
     componentWillUnmount: function() {
@@ -1039,61 +1079,41 @@ loop.panel = (function(_, mozL10n) {
       );
     }
   });
 
   /**
    * Panel initialisation.
    */
   function init() {
-    var requests = [
+    return loop.requestMulti(
       ["GetAllConstants"],
       ["GetAllStrings"],
       ["GetLocale"],
       ["GetPluralRule"]
-    ];
-    var prefetch = [
-      ["GetLoopPref", "gettingStarted.seen"],
-      ["GetLoopPref", "legal.ToS_url"],
-      ["GetLoopPref", "legal.privacy_url"],
-      ["GetUserProfile"],
-      ["GetFxAEnabled"],
-      ["GetDoNotDisturb"],
-      ["GetHasEncryptionKey"],
-      ["IsMultiProcessEnabled"]
-    ];
-
-    return loop.requestMulti.apply(null, requests.concat(prefetch)).then(function(results) {
-      // `requestIdx` is keyed off the order of the `requests` and `prefetch`
-      // arrays. Be careful to update both when making changes.
-      var requestIdx = 0;
-      var constants = results[requestIdx];
+    ).then(function(results) {
+      var constants = results[0];
       // Do the initial L10n setup, we do this before anything
       // else to ensure the L10n environment is setup correctly.
-      var stringBundle = results[++requestIdx];
-      var locale = results[++requestIdx];
-      var pluralRule = results[++requestIdx];
+      var stringBundle = results[1];
+      var locale = results[2];
+      var pluralRule = results[3];
       mozL10n.initialize({
         locale: locale,
         pluralRule: pluralRule,
         getStrings: function(key) {
           if (!(key in stringBundle)) {
             console.error("No string found for key: ", key);
             return "{ textContent: '' }";
           }
 
           return JSON.stringify({ textContent: stringBundle[key] });
         }
       });
 
-      prefetch.forEach(function(req) {
-        req.shift();
-        loop.storeRequest(req, results[++requestIdx]);
-      });
-
       var notifications = new sharedModels.NotificationCollection();
       var dispatcher = new loop.Dispatcher();
       var roomStore = new loop.store.RoomStore(dispatcher, {
         notifications: notifications,
         constants: constants
       });
 
       React.render(<PanelView
--- a/browser/components/loop/content/js/roomViews.js
+++ b/browser/components/loop/content/js/roomViews.js
@@ -318,17 +318,17 @@ loop.roomViews = (function(mozL10n) {
 
     handleEditContextClose: function() {
       if (this.props.onEditContextClose) {
         this.props.onEditContextClose();
       }
     },
 
     render: function() {
-      if (!this.props.show || !this.props.roomData.roomUrl) {
+      if (!this.props.show) {
         return null;
       }
 
       var cx = classNames;
       return (
         React.createElement("div", {className: "room-invitation-overlay"}, 
           React.createElement("div", {className: "room-invitation-content"}, 
             React.createElement("p", {className: cx({ hide: this.props.showEditContext })}, 
--- a/browser/components/loop/content/js/roomViews.jsx
+++ b/browser/components/loop/content/js/roomViews.jsx
@@ -318,17 +318,17 @@ loop.roomViews = (function(mozL10n) {
 
     handleEditContextClose: function() {
       if (this.props.onEditContextClose) {
         this.props.onEditContextClose();
       }
     },
 
     render: function() {
-      if (!this.props.show || !this.props.roomData.roomUrl) {
+      if (!this.props.show) {
         return null;
       }
 
       var cx = classNames;
       return (
         <div className="room-invitation-overlay">
           <div className="room-invitation-content">
             <p className={cx({ hide: this.props.showEditContext })}>
--- a/browser/components/loop/content/shared/js/loopapi-client.js
+++ b/browser/components/loop/content/shared/js/loopapi-client.js
@@ -90,47 +90,16 @@ var loop = loop || {};
   // These functions should only be used in unit tests.
   loop.request.getReplyTimeoutMs = function() { return kReplyTimeoutMs; };
   loop.request.inspect = function() { return _.extend({}, gListenersMap); };
   loop.request.reset = function() {
     gListeningForMessages = false;
     gListenersMap = {};
   };
 
-  loop.storedRequests = {};
-
-  /**
-   * Store the result of a request for access at a later time.
-   *
-   * @param  {Array} request Set of request parameters
-   * @param  {mixed} result  Whatever the API returned as a result
-   */
-  loop.storeRequest = function(request, result) {
-    loop.storedRequests[request.join("|")] = result;
-  };
-
-  /**
-   * Retrieve the result of a request that was stored previously. If the result
-   * can not be found, |NULL| will be returned and an error will be logged to the
-   * console.
-   *
-   * @param  {Array} request Set of request parameters
-   * @return {mixed} Whatever the result of the API request was at the time it was
-   *                 stored.
-   */
-  loop.getStoredRequest = function(request) {
-    var key = request.join("|");
-    if (!(key in loop.storedRequests)) {
-      console.error("This request has not been stored!", request);
-      return null;
-    }
-
-    return loop.storedRequests[key];
-  };
-
   /**
    * Send multiple requests at once as a batch.
    *
    * @param {...Array} command An unlimited amount of Arrays may be passed as
    *                           individual arguments of this function. They are
    *                           bundled together and sent across.
    * @return {Promise} Gets resolved when all commands have finished with their
    *                   accumulated results.
--- a/browser/components/loop/modules/MozLoopAPI.jsm
+++ b/browser/components/loop/modules/MozLoopAPI.jsm
@@ -1072,21 +1072,17 @@ const LoopAPIInternal = {
     let actionParts = action.split(":");
 
     // The name that is supposed to match with a handler function is tucked inside
     // the second part of the message name. If all is well.
     let handlerName = actionParts.shift();
 
     if (!reply) {
       reply = result => {
-        try {
-          message.target.sendAsyncMessage(message.name, [seq, result]);
-        } catch (ex) {
-          MozLoopService.log.error("Failed to send reply back to content:", ex);
-        }
+        message.target.sendAsyncMessage(message.name, [seq, result]);
       }
     }
 
     // First, check if this is a batch call.
     if (handlerName == kBatchMessage) {
       this.handleBatchMessage(seq, message, reply);
       return;
     }
--- a/browser/components/loop/run-all-loop-tests.sh
+++ b/browser/components/loop/run-all-loop-tests.sh
@@ -39,26 +39,24 @@ fi
 # The browser_parsable_css.js can fail if we add some css that isn't parsable.
 #
 # The check to make sure that the media devices can be used in Loop without
 # prompting is in browser_devices_get_user_media_about_urls.js. It's possible
 # to mess this up with CSP handling, and probably other changes, too.
 
 TESTS="
   ${LOOPDIR}/test/mochitest
-  browser/components/uitour/test/browser_UITour_loop.js
   browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
   browser/base/content/test/general/browser_parsable_css.js
 "
 
 # Due to bug 1209463, we need to split these up and run them individually to
 # ensure we stop and report that there's an error.
 for test in $TESTS
 do
   ./mach mochitest $test
   # UITour & get user media aren't compatible with e10s currenly.
   if [ "$1" != "--skip-e10s" ] && \
-     [ "$test" != "browser/components/uitour/test/browser_UITour_loop.js" ] && \
      [ "$test" != "browser/base/content/test/general/browser_devices_get_user_media_about_urls.js" ];
   then
     ./mach mochitest --e10s $test
   fi
 done
--- a/browser/components/loop/test/desktop-local/conversationAppStore_test.js
+++ b/browser/components/loop/test/desktop-local/conversationAppStore_test.js
@@ -101,20 +101,23 @@ describe("loop.store.ConversationAppStor
 
       fakeGetWindowData = {
         windowId: "42"
       };
 
       getLoopPrefStub = sandbox.stub();
       setLoopPrefStub = sandbox.stub();
 
-      loop.storedRequests = {
-        "GetConversationWindowData|42": fakeWindowData
-      };
       LoopMochaUtils.stubLoopRequest({
+        GetConversationWindowData: function(windowId) {
+          if (windowId === "42") {
+            return fakeWindowData;
+          }
+          return null;
+        },
         GetLoopPref: getLoopPrefStub,
         SetLoopPref: setLoopPrefStub
       });
 
       store = new loop.store.ConversationAppStore({
         activeRoomStore: activeRoomStore,
         dispatcher: dispatcher,
         feedbackPeriod: 42,
--- a/browser/components/loop/test/desktop-local/conversation_test.js
+++ b/browser/components/loop/test/desktop-local/conversation_test.js
@@ -52,19 +52,16 @@ describe("loop.conversation", function()
           platform: "test"
         };
       },
       GetAudioBlob: sinon.spy(function(name) {
         return new Blob([new ArrayBuffer(10)], { type: "audio/ogg" });
       }),
       GetSelectedTabMetadata: function() {
         return {};
-      },
-      GetConversationWindowData: function() {
-        return {};
       }
     });
 
     fakeWindow = {
       close: sinon.stub(),
       document: {},
       addEventListener: function() {},
       removeEventListener: function() {}
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -72,27 +72,16 @@ describe("loop.panel", function() {
       LoginToFxA: sinon.stub(),
       LogoutFromFxA: sinon.stub(),
       NotifyUITour: sinon.stub(),
       OpenURL: sinon.stub(),
       GetSelectedTabMetadata: sinon.stub().returns({}),
       GetUserProfile: function() { return null; }
     });
 
-    loop.storedRequests = {
-      GetFxAEnabled: true,
-      GetHasEncryptionKey: true,
-      GetUserProfile: null,
-      GetDoNotDisturb: false,
-      "GetLoopPref|gettingStarted.seen": "unseen",
-      "GetLoopPref|legal.ToS_url": "",
-      "GetLoopPref|legal.privacy_url": "",
-      IsMultiProcessEnabled: false
-    };
-
     roomName = "First Room Name";
     roomData = {
       roomToken: "QzBbvGmIZWU",
       roomUrl: "http://sample/QzBbvGmIZWU",
       decryptedContext: {
         roomName: roomName,
         urls: [{
           location: "http://testurl.com"
@@ -261,17 +250,21 @@ describe("loop.panel", function() {
             fxAEnabled: false,
             userProfile: null
           }));
 
         expect(view.getDOMNode()).to.be.null;
       });
 
       it("should add ellipsis to text over 24chars", function() {
-        loop.storedRequests.GetUserProfile = { email: "reallyreallylongtext@example.com" };
+        LoopMochaUtils.stubLoopRequest({
+          GetUserProfile: function() {
+            return { email: "reallyreallylongtext@example.com" };
+          }
+        });
         var view = createTestPanelView();
         var node = view.getDOMNode().querySelector(".user-identity");
 
         expect(node.textContent).to.eql("reallyreallylongtext@exa…");
       });
 
       it("should warn when user profile is different from {} or null",
          function() {
@@ -351,17 +344,19 @@ describe("loop.panel", function() {
           TestUtils.Simulate.click(view.getDOMNode()
                                      .querySelector(".entry-settings-signin"));
 
           sinon.assert.calledOnce(requestStubs.LoginToFxA);
         });
       });
 
       it("should show a signout entry when user is authenticated", function() {
-        loop.storedRequests.GetUserProfile = { email: "test@example.com" };
+        LoopMochaUtils.stubLoopRequest({
+          GetUserProfile: function() { return { email: "test@example.com" }; }
+        });
 
         var view = mountTestComponent();
 
         sinon.assert.calledWithExactly(document.mozL10n.get,
                                        "settings_menu_item_signout");
         sinon.assert.neverCalledWith(document.mozL10n.get,
                                      "settings_menu_item_signin");
       });
@@ -374,28 +369,32 @@ describe("loop.panel", function() {
         var view = mountTestComponent();
 
         sinon.assert.calledWithExactly(document.mozL10n.get,
                                        "settings_menu_item_settings");
       });
 
       it("should open the FxA settings when the account entry is clicked",
          function() {
-           loop.storedRequests.GetUserProfile = { email: "test@example.com" };
+           LoopMochaUtils.stubLoopRequest({
+            GetUserProfile: function() { return { email: "test@example.com" }; }
+          });
 
            var view = mountTestComponent();
 
            TestUtils.Simulate.click(view.getDOMNode()
                                       .querySelector(".entry-settings-account"));
 
            sinon.assert.calledOnce(openFxASettingsStub);
          });
 
       it("should sign out the user on click when authenticated", function() {
-        loop.storedRequests.GetUserProfile = { email: "test@example.com" };
+        LoopMochaUtils.stubLoopRequest({
+          GetUserProfile: function() { return { email: "test@example.com" }; }
+        });
         var view = mountTestComponent();
 
         TestUtils.Simulate.click(view.getDOMNode()
                                    .querySelector(".entry-settings-signout"));
 
         sinon.assert.calledOnce(requestStubs.LogoutFromFxA);
       });
 
@@ -538,45 +537,53 @@ describe("loop.panel", function() {
         var view = createTestPanelView();
 
         expect(function() {
           TestUtils.findRenderedComponentWithType(view, loop.panel.ToSView);
         }).to.Throw(/not find/);
       });
 
       it("should not render a ToSView when gettingStarted.seen is false", function() {
-        loop.storedRequests["GetLoopPref|gettingStarted.seen"] = false;
+        LoopMochaUtils.stubLoopRequest({
+          GetLoopPref: function() { return false; }
+        });
         var view = createTestPanelView();
 
         expect(function() {
           TestUtils.findRenderedComponentWithType(view, loop.panel.ToSView);
         }).to.not.Throw();
       });
 
       it("should render a GettingStarted view", function() {
-        loop.storedRequests["GetLoopPref|gettingStarted.seen"] = false;
+        LoopMochaUtils.stubLoopRequest({
+          GetLoopPref: function() { return false; }
+        });
         var view = createTestPanelView();
 
         TestUtils.findRenderedComponentWithType(view, loop.panel.GettingStartedView);
       });
 
       it("should not render a GettingStartedView when the view has been seen", function() {
-        loop.storedRequests["GetLoopPref|gettingStarted.seen"] = true;
+        LoopMochaUtils.stubLoopRequest({
+          GetLoopPref: function() { return true; }
+        });
         var view = createTestPanelView();
 
         try {
           TestUtils.findRenderedComponentWithType(view, loop.panel.GettingStartedView);
           sinon.assert.fail("Should not find the GettingStartedView if it has been seen");
         } catch (ex) {
           // Do nothing
         }
       });
 
       it("should render a SignInRequestView when mozLoop.hasEncryptionKey is false", function() {
-        loop.storedRequests.GetHasEncryptionKey = false;
+        LoopMochaUtils.stubLoopRequest({
+          GetHasEncryptionKey: function() { return false; }
+        });
 
         var view = createTestPanelView();
 
         TestUtils.findRenderedComponentWithType(view, loop.panel.SignInRequestView);
       });
 
       it("should render a SignInRequestView when mozLoop.hasEncryptionKey is true", function() {
         var view = createTestPanelView();
@@ -585,17 +592,19 @@ describe("loop.panel", function() {
           TestUtils.findRenderedComponentWithType(view, loop.panel.SignInRequestView);
           sinon.assert.fail("Should not find the GettingStartedView if it has been seen");
         } catch (ex) {
           // Do nothing
         }
       });
 
       it("should render a E10sNotSupported when multiprocess is enabled", function() {
-        loop.storedRequests.IsMultiProcessEnabled = true;
+        LoopMochaUtils.stubLoopRequest({
+          IsMultiProcessEnabled: function() { return true; }
+        });
 
         var view = createTestPanelView();
 
         TestUtils.findRenderedComponentWithType(view, loop.panel.E10sNotSupported);
       });
 
     });
   });
--- a/browser/components/loop/test/desktop-local/roomViews_test.js
+++ b/browser/components/loop/test/desktop-local/roomViews_test.js
@@ -191,29 +191,31 @@ describe("loop.roomViews", function() {
       expect(fakeAudio.loop).to.equal(false);
     });
   });
 
   describe("DesktopRoomInvitationView", function() {
     function mountTestComponent(props) {
       props = _.extend({
         dispatcher: dispatcher,
-        roomData: { roomUrl: "http://invalid" },
+        roomData: {},
         savingContext: false,
         show: true,
         showEditContext: false
       }, props);
       return TestUtils.renderIntoDocument(
         React.createElement(loop.roomViews.DesktopRoomInvitationView, props));
     }
 
     it("should dispatch an EmailRoomUrl with no description" +
        " for rooms without context when the email button is pressed",
       function() {
-        view = mountTestComponent();
+        view = mountTestComponent({
+          roomData: { roomUrl: "http://invalid" }
+        });
 
         var emailBtn = view.getDOMNode().querySelector(".btn-email");
 
         React.addons.TestUtils.Simulate.click(emailBtn);
 
         sinon.assert.calledOnce(dispatcher.dispatch);
         sinon.assert.calledWith(dispatcher.dispatch,
           new sharedActions.EmailRoomUrl({
@@ -243,17 +245,19 @@ describe("loop.roomViews", function() {
             roomUrl: url,
             roomDescription: "www.mozilla.com",
             from: "conversation"
           }));
       });
 
     describe("Copy Button", function() {
       beforeEach(function() {
-        view = mountTestComponent();
+        view = mountTestComponent({
+          roomData: { roomUrl: "http://invalid" }
+        });
       });
 
       it("should dispatch a CopyRoomUrl action when the copy button is pressed", function() {
         var copyBtn = view.getDOMNode().querySelector(".btn-copy");
         React.addons.TestUtils.Simulate.click(copyBtn);
 
         sinon.assert.calledOnce(dispatcher.dispatch);
         sinon.assert.calledWith(dispatcher.dispatch, new sharedActions.CopyRoomUrl({
@@ -314,18 +318,16 @@ describe("loop.roomViews", function() {
         GetLoopPref: function(prefName) {
           if (prefName === "contextInConversations.enabled") {
             return true;
           }
           return "test";
         }
       });
       onCallTerminatedStub = sandbox.stub();
-
-      activeRoomStore.setStoreState({ roomUrl: "http://invalid " });
     });
 
     function mountTestComponent(props) {
       props = _.extend({
         chatWindowDetached: false,
         dispatcher: dispatcher,
         roomStore: roomStore,
         onCallTerminated: onCallTerminatedStub
--- a/browser/components/loop/test/shared/loopapi-client_test.js
+++ b/browser/components/loop/test/shared/loopapi-client_test.js
@@ -104,60 +104,16 @@ describe("loopapi-client", function() {
           clock.tick(replyTimeoutMs);
         });
 
         clock.tick(replyTimeoutMs);
       });
     });
   });
 
-  describe("loop.storeRequest", function() {
-    afterEach(function() {
-      loop.storedRequests = {};
-    });
-
-    it("should the result of a request", function() {
-      loop.storeRequest(["GetLoopPref"], true);
-
-      expect(loop.storedRequests).to.deep.equal({
-        "GetLoopPref": true
-      });
-    });
-
-    it("should the result of a request with multiple params", function() {
-      loop.storeRequest(["GetLoopPref", "enabled", "or", "not", "well",
-        "perhaps", true, 2], true);
-
-      expect(loop.storedRequests).to.deep.equal({
-        "GetLoopPref|enabled|or|not|well|perhaps|true|2": true
-      });
-    });
-  });
-
-  describe("loop.getStoredRequest", function() {
-    afterEach(function() {
-      loop.storedRequests = {};
-    });
-
-    it("should retrieve a result", function() {
-      loop.storedRequests["GetLoopPref"] = true;
-
-      expect(loop.getStoredRequest(["GetLoopPref"])).to.eql(true);
-    });
-
-    it("should return log and return null for invalid requests", function() {
-      sandbox.stub(console, "error");
-
-      expect(loop.getStoredRequest(["SomethingNeverStored"])).to.eql(null);
-      sinon.assert.calledOnce(console.error);
-      sinon.assert.calledWithExactly(console.error,
-        "This request has not been stored!", ["SomethingNeverStored"]);
-    });
-  });
-
   describe("loop.requestMulti", function() {
     it("should send a batch of messages", function() {
       var promise = loop.requestMulti(
         ["GetLoopPref", "enabled"],
         ["GetLoopPref", "e10s.enabled"]
       );
 
       expect(promise).to.be.an.instanceof(Promise);
--- a/browser/components/loop/ui/fake-mozLoop.js
+++ b/browser/components/loop/ui/fake-mozLoop.js
@@ -148,16 +148,17 @@ var fakeRooms = [
    */
   LoopMochaUtils.stubLoopRequest({
     EnsureRegistered: function() {},
     GetAudioBlob: function() {
       return new Blob([new ArrayBuffer(10)], { type: "audio/ogg" });
     },
     GetDoNotDisturb: function() { return true; },
     GetErrors: function() {},
+    GetHasEncryptionKey: function() { return true; },
     GetLoopPref: function(pref) {
       switch (pref) {
         // Ensure we skip FTE completely.
         case "gettingStarted.seen":
           return true;
       }
       return null;
     },
@@ -173,26 +174,15 @@ var fakeRooms = [
         previews: ["chrome://branding/content/about-logo.png"],
         description: "sample webpage description",
         url: "https://www.example.com"
       };
     },
     "Rooms:GetAll": function(version) {
       return [].concat(fakeRooms);
     },
+    GetFxAEnabled: function() { return true; },
     StartAlerting: function() {},
     StopAlerting: function() {},
     GetUserProfile: function() { return null; },
     "Rooms:PushSubscription": function() {}
   });
-
-  loop.storedRequests = {
-    GetFxAEnabled: true,
-    GetHasEncryptionKey: true,
-    GetUserProfile: null,
-    GetDoNotDisturb: true,
-    // Ensure we skip FTE completely.
-    "GetLoopPref|gettingStarted.seen": true,
-    "GetLoopPref|legal.ToS_url": null,
-    "GetLoopPref|legal.privacy_url": null,
-    IsMultiProcessEnabled: false
-  };
 })();
--- a/browser/components/uitour/test/browser.ini
+++ b/browser/components/uitour/test/browser.ini
@@ -37,17 +37,17 @@ skip-if = e10s # Bug 1073247 - UITour te
 skip-if = e10s # Bug 1073247 - UITour tests not e10s friendly
 [browser_UITour_detach_tab.js]
 skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly
 [browser_UITour_forceReaderMode.js]
 skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly.
 [browser_UITour_heartbeat.js]
 skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly.
 [browser_UITour_loop.js]
-skip-if = os == "linux" || e10s # Bug 1073247 - UITour.jsm not e10s friendly.
+skip-if = true # Bug 1225832 - New Loop architecture is not compatible with test.
 [browser_UITour_modalDialog.js]
 skip-if = os != "mac" || e10s # modal dialog disabling only working on OS X.Bug 1073247 - UITour.jsm not e10s friendly
 [browser_UITour_observe.js]
 skip-if = e10s # Bug 1073247 - UITour.jsm not e10s friendly.
 [browser_UITour_panel_close_annotation.js]
 skip-if = true # Disabled due to frequent failures, bugs 1026310 and 1032137
 [browser_UITour_pocket.js]
 skip-if = os == "linux" || e10s || debug # Bug 1073247 - UITour.jsm not e10s friendly.
--- a/browser/components/uitour/test/browser_UITour_loop.js
+++ b/browser/components/uitour/test/browser_UITour_loop.js
@@ -1,23 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 var gTestTab;
 var gContentAPI;
 var gContentWindow;
-var gMessageHandlers;
 var loopButton;
-var fakeRoom;
 var loopPanel = document.getElementById("loop-notification-panel");
 
-const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {});
-const { LoopRooms } = Cu.import("resource:///modules/loop/LoopRooms.jsm", {});
+const { LoopRooms } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
 const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
 
 function test() {
   UITourTest();
 }
 
 function runOffline(fun) {
   return (done) => {
@@ -48,33 +45,33 @@ var tests = [
     let loopDoc = document.getElementById("loop-notification-panel").children[0].contentDocument;
     yield waitForConditionPromise(() => {
       return loopDoc.readyState == 'complete';
     }, "Loop notification panel document should be fully loaded.", 50);
     let gettingStartedButton = loopDoc.getElementById("fte-button");
     ok(gettingStartedButton, "Getting Started button should be found");
 
     let newTabPromise = waitForConditionPromise(() => {
-      return gBrowser.currentURI.path.includes("utm_source=firefox-browser");
+      return gBrowser.currentURI.path.contains("utm_source=firefox-browser");
     }, "New tab with utm_content=testPageNewID should have opened");
 
     gettingStartedButton.click();
     yield newTabPromise;
-    ok(gBrowser.currentURI.path.includes("utm_content=hello-tour_OpenPanel_testPage"),
+    ok(gBrowser.currentURI.path.contains("utm_content=hello-tour_OpenPanel_testPage"),
         "Expected URL opened (" + gBrowser.currentURI.path + ")");
     yield gBrowser.removeCurrentTab();
 
     checkLoopPanelIsHidden();
   }),
   taskify(function* test_gettingStartedClicked_linkOpenedWithExpectedParams2() {
     Services.prefs.setBoolPref("loop.gettingStarted.seen", false);
     // Force a refresh of the loop panel since going from seen -> unseen doesn't trigger
     // automatic re-rendering.
     let loopWin = document.getElementById("loop-notification-panel").children[0].contentWindow;
-    var event = new loopWin.CustomEvent("GettingStartedSeen", { detail: false });
+    var event = new loopWin.CustomEvent("GettingStartedSeen");
     loopWin.dispatchEvent(event);
 
     UITour.pageIDsForSession.clear();
     Services.prefs.setCharPref("loop.gettingStarted.url", "http://example.com");
     is(loopButton.open, false, "Menu should initially be closed");
     loopButton.click();
 
     yield waitForConditionPromise(() => {
@@ -91,22 +88,22 @@ var tests = [
                                    {lastSeen: Date.now() - (10 * 60 * 60 * 1000)});
 
     let loopDoc = loopWin.document;
     let gettingStartedButton = loopDoc.getElementById("fte-button");
     ok(gettingStartedButton, "Getting Started button should be found");
 
     let newTabPromise = waitForConditionPromise(() => {
       Services.console.logStringMessage(gBrowser.currentURI.path);
-      return gBrowser.currentURI.path.includes("utm_source=firefox-browser");
+      return gBrowser.currentURI.path.contains("utm_source=firefox-browser");
     }, "New tab with utm_content=testPageNewID should have opened");
 
     gettingStartedButton.click();
     yield newTabPromise;
-    ok(!gBrowser.currentURI.path.includes("utm_content=hello-tour_OpenPanel_testPageOldId"),
+    ok(!gBrowser.currentURI.path.contains("utm_content=hello-tour_OpenPanel_testPageOldId"),
        "Expected URL opened without the utm_content parameter (" +
         gBrowser.currentURI.path + ")");
     yield gBrowser.removeCurrentTab();
 
     checkLoopPanelIsHidden();
   }),
   taskify(function* test_menu_show_hide() {
     // The targets to highlight only appear after getting started is launched.
@@ -214,24 +211,20 @@ var tests = [
         gContentAPI.observe((event, params) => {
           is(event, "Loop:RoomURLCopied", "Check Loop:RoomURLCopied notification");
           gContentAPI.observe((event, params) => {
             is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
           });
           chat.close();
           done();
         });
-
-        let window = chat.content.contentWindow;
-        waitForConditionPromise(
-          () => chat.content.contentDocument.querySelector(".btn-copy"),
-          "Copy button should be there"
-        ).then(() => chat.content.contentDocument.querySelector(".btn-copy").click());
+        chat.content.contentDocument.querySelector(".btn-copy").click();
       });
     });
+    setupFakeRoom();
     LoopRooms.open("fakeTourRoom");
   }),
   runOffline(function test_notifyLoopRoomURLEmailed(done) {
     gContentAPI.observe((event, params) => {
       is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
       gContentAPI.observe((event, params) => {
         is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
 
@@ -243,29 +236,27 @@ var tests = [
           ok(composeEmailCalled, "mozLoop.composeEmail should be called");
           gContentAPI.observe((event, params) => {
             is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
           });
           chat.close();
           done();
         });
 
-        gMessageHandlers.ComposeEmail = function(message, reply) {
-          let [subject, body, recipient] = message.data;
-          ok(subject, "composeEmail should be invoked with at least a subject value");
+        let chatWin = chat.content.contentWindow;
+        let oldComposeEmail = chatWin.navigator.wrappedJSObject.mozLoop.composeEmail;
+        chatWin.navigator.wrappedJSObject.mozLoop.composeEmail = function(recipient, subject, body) {
+          ok(recipient, "composeEmail should be invoked with at least a recipient value");
           composeEmailCalled = true;
-          reply();
+          chatWin.navigator.wrappedJSObject.mozLoop.composeEmail = oldComposeEmail;
         };
-
-        waitForConditionPromise(
-          () => chat.content.contentDocument.querySelector(".btn-email"),
-          "Email button should be there"
-        ).then(() => chat.content.contentDocument.querySelector(".btn-email").click());
+        chatWin.document.querySelector(".btn-email").click();
       });
     });
+    setupFakeRoom();
     LoopRooms.open("fakeTourRoom");
   }),
   taskify(function* test_arrow_panel_position() {
     is(loopButton.open, false, "Menu should initially be closed");
     let popup = document.getElementById("UITourTooltip");
 
     yield showMenuPromise("loop");
 
@@ -327,17 +318,17 @@ var tests = [
     roomsMap.get("fakeTourRoom").participants = [{
       owner: false,
     }];
 
     // Set the tour URL to a page that's not open yet
     Services.prefs.setCharPref("loop.gettingStarted.url", gBrowser.currentURI.prePath);
 
     let newTabPromise = waitForConditionPromise(() => {
-      return gBrowser.currentURI.path.includes("incomingConversation=waiting");
+      return gBrowser.currentURI.path.contains("incomingConversation=waiting");
     }, "New tab with incomingConversation=waiting should have opened");
 
     // Now open the menu while that non-owner is in the fake room to trigger resuming the tour
     yield showMenuPromise("loop");
 
     yield newTabPromise;
 
     yield gBrowser.removeCurrentTab();
@@ -350,83 +341,46 @@ var tests = [
 function checkLoopPanelIsHidden() {
   ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
   ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
   isnot(loopPanel.state, "open", "The panel shouldn't be open");
   is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
 }
 
 function setupFakeRoom() {
-  let room = Object.create(fakeRoom);
+  let room = {};
+  for (let prop of ["roomToken", "roomOwner", "roomUrl", "participants"])
+    room[prop] = "fakeTourRoom";
+  room.decryptedContext = {roomName: "fakeTourRoom"};
+  room.participants = [];
   let roomsMap = new Map([
     [room.roomToken, room]
   ]);
   LoopRooms.stubCache(roomsMap);
   return roomsMap;
 }
 
 if (Services.prefs.getBoolPref("loop.enabled")) {
   loopButton = window.LoopUI.toolbarButton.node;
 
-  fakeRoom = {
-    decryptedContext: { roomName: "fakeTourRoom" },
-    participants: [],
-    maxSize: 2,
-    ctime: Date.now()
-  };
-  for (let prop of ["roomToken", "roomOwner", "roomUrl"])
-    fakeRoom[prop] = "fakeTourRoom";
-
-  LoopAPI.stubMessageHandlers(gMessageHandlers = {
-    // Stub the rooms object API to fully control the test behavior.
-    "Rooms:*": function(action, message, reply) {
-      switch (action.split(":").pop()) {
-        case "GetAll":
-          reply([fakeRoom]);
-          break;
-        case "Get":
-          reply(fakeRoom);
-          break;
-        case "Join":
-          reply({
-            apiKey: "fakeTourRoom",
-            sessionToken: "fakeTourRoom",
-            sessionId: "fakeTourRoom",
-            expires: Date.now() + 240000
-          });
-          break;
-        case "RefreshMembership":
-          reply({ expires: Date.now() + 240000 });
-        default:
-          reply();
-      }
-    },
-    // Stub the metadata retrieval to suppress console warnings and return faster.
-    GetSelectedTabMetadata: function(message, reply) {
-      reply({ favicon: null });
-    }
-  });
-
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
     Services.prefs.clearUserPref("loop.gettingStarted.seen");
     Services.prefs.clearUserPref("loop.gettingStarted.url");
     Services.io.offline = false;
 
     // Copied from browser/components/loop/test/mochitest/head.js
     // Remove the iframe after each test. This also avoids mochitest complaining
     // about leaks on shutdown as we intentionally hold the iframe open for the
     // life of the application.
     let frameId = loopButton.getAttribute("notificationFrameId");
     let frame = document.getElementById(frameId);
     if (frame) {
       frame.remove();
     }
 
-    // Remove the stubbed rooms.
+    // Remove the stubbed rooms
     LoopRooms.stubCache(null);
-    // Restore the stubbed handlers.
-    LoopAPI.restore();
   });
 } else {
   ok(true, "Loop is disabled so skip the UITour Loop tests");
   tests = [];
 }