Bug 1178393 - Countdown to zero warnings in standalone test suite. r=andreio
authorChris Rafuse <chris.rafuse@priologic.com>
Tue, 11 Aug 2015 20:35:25 +0100
changeset 289937 1175ddebd4f35ad3afaef0f4d8d49a67fff5f717
parent 289936 dfbcaf688a84285e312d267757b8b7154ebb04bf
child 289938 d85445174174fb2f74b30296643b41c1c99a0499
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersandreio
bugs1178393
milestone43.0a1
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
Bug 1178393 - Countdown to zero warnings in standalone test suite. r=andreio
browser/components/loop/standalone/content/js/standaloneMetricsStore.js
browser/components/loop/standalone/content/js/standaloneRoomViews.js
browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
browser/components/loop/standalone/content/js/webapp.js
browser/components/loop/standalone/content/js/webapp.jsx
browser/components/loop/test/index.html
browser/components/loop/test/standalone/index.html
browser/components/loop/test/standalone/standaloneMetricsStore_test.js
browser/components/loop/test/standalone/webapp_test.js
browser/components/loop/ui/ui-showcase.js
browser/components/loop/ui/ui-showcase.jsx
--- a/browser/components/loop/standalone/content/js/standaloneMetricsStore.js
+++ b/browser/components/loop/standalone/content/js/standaloneMetricsStore.js
@@ -45,17 +45,18 @@ loop.store.StandaloneMetricsStore = (fun
       "connectionFailure",
       "gotMediaPermission",
       "joinRoom",
       "joinedRoom",
       "leaveRoom",
       "mediaConnected",
       "recordClick",
       "remotePeerConnected",
-      "retryAfterRoomFailure"
+      "retryAfterRoomFailure",
+      "windowUnload"
     ],
 
     /**
      * Initializes the store and starts listening to the activeRoomStore.
      *
      * @param  {Object} options Options for the store, should include a
      *                          reference to the activeRoomStore.
      */
@@ -252,13 +253,24 @@ loop.store.StandaloneMetricsStore = (fun
         return;
       }
       this._storeState[muteItem] = muted;
 
       var muteType = type === "audio" ? METRICS_GA_ACTIONS.audioMute : METRICS_GA_ACTIONS.faceMute;
       var muteState = muted ? "mute" : "unmute";
 
       this._storeEvent(METRICS_GA_CATEGORY.general, muteType, muteState);
+    },
+
+    /**
+     * Called when the window is unloaded, either by code, or by the user
+     * explicitly closing it.  Expected to do any necessary housekeeping, such
+     * as shutting down the call cleanly and adding any relevant telemetry data.
+     */
+    windowUnload: function() {
+      if (this.activeRoomStore) {
+        this.stopListening(this.activeRoomStore);
+      }
     }
   });
 
   return StandaloneMetricsStore;
 })();
--- a/browser/components/loop/standalone/content/js/standaloneRoomViews.js
+++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.js
@@ -409,16 +409,18 @@ loop.standaloneRoomViews = (function(moz
         case ROOM_STATES.JOINED:
         case ROOM_STATES.MEDIA_WAIT:
           // this case is so that we don't show an avatar while waiting for
           // the other party to connect
           return true;
 
         case ROOM_STATES.FAILED:
         case ROOM_STATES.CLOSING:
+        case ROOM_STATES.FULL:
+        case ROOM_STATES.ENDED:
           // the other person has shown up, so we don't want to show an avatar
           return true;
 
         default:
           console.warn("StandaloneRoomView.shouldRenderRemoteVideo:" +
             " unexpected roomState: ", this.state.roomState);
           return true;
 
--- a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
+++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
@@ -409,16 +409,18 @@ loop.standaloneRoomViews = (function(moz
         case ROOM_STATES.JOINED:
         case ROOM_STATES.MEDIA_WAIT:
           // this case is so that we don't show an avatar while waiting for
           // the other party to connect
           return true;
 
         case ROOM_STATES.FAILED:
         case ROOM_STATES.CLOSING:
+        case ROOM_STATES.FULL:
+        case ROOM_STATES.ENDED:
           // the other person has shown up, so we don't want to show an avatar
           return true;
 
         default:
           console.warn("StandaloneRoomView.shouldRenderRemoteVideo:" +
             " unexpected roomState: ", this.state.roomState);
           return true;
 
--- a/browser/components/loop/standalone/content/js/webapp.js
+++ b/browser/components/loop/standalone/content/js/webapp.js
@@ -88,17 +88,17 @@ loop.webapp = (function($, _, OT, mozL10
    */
   var PromoteFirefoxView = React.createClass({displayName: "PromoteFirefoxView",
     propTypes: {
       isFirefox: React.PropTypes.bool.isRequired
     },
 
     render: function() {
       if (this.props.isFirefox) {
-        return React.createElement("div", null);
+        return null;
       }
       return (
         React.createElement("div", {className: "promote-firefox"}, 
           React.createElement("h3", null, mozL10n.get("promote_firefox_hello_heading", {brandShortname: mozL10n.get("brandShortname")})), 
           React.createElement("p", null, 
             React.createElement("a", {className: "btn btn-large btn-accept", 
                href: loop.config.downloadFirefoxUrl}, 
               mozL10n.get("get_firefox_button", {
@@ -644,18 +644,18 @@ loop.webapp = (function($, _, OT, mozL10
   var OutgoingConversationView = React.createClass({displayName: "OutgoingConversationView",
     propTypes: {
       client: React.PropTypes.instanceOf(loop.StandaloneClient).isRequired,
       conversation: React.PropTypes.oneOfType([
         React.PropTypes.instanceOf(sharedModels.ConversationModel),
         React.PropTypes.instanceOf(FxOSConversationModel)
       ]).isRequired,
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
-      notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection)
-                          .isRequired,
+      isFirefox: React.PropTypes.bool.isRequired,
+      notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection).isRequired,
       sdk: React.PropTypes.object.isRequired
     },
 
     getInitialState: function() {
       return {
         callStatus: "start"
       };
     },
@@ -733,17 +733,17 @@ loop.webapp = (function($, _, OT, mozL10
               conversation: this.props.conversation, 
               dispatcher: this.props.dispatcher, 
               onAfterFeedbackReceived: this.resetCallStatus(), 
               sdk: this.props.sdk})
           );
         }
         case "expired": {
           return (
-            React.createElement(CallUrlExpiredView, null)
+            React.createElement(CallUrlExpiredView, {isFirefox: this.props.isFirefox})
           );
         }
         default: {
           return React.createElement(HomeView, null);
         }
       }
     },
 
@@ -981,16 +981,17 @@ loop.webapp = (function($, _, OT, mozL10
           return React.createElement(UnsupportedBrowserView, {isFirefox: this.state.isFirefox});
         }
         case "outgoing": {
           return (
             React.createElement(OutgoingConversationView, {
                client: this.props.client, 
                conversation: this.props.conversation, 
                dispatcher: this.props.dispatcher, 
+               isFirefox: this.state.isFirefox, 
                notifications: this.props.notifications, 
                sdk: this.props.sdk})
           );
         }
         case "room": {
           return (
             React.createElement(loop.standaloneRoomViews.StandaloneRoomView, {
               activeRoomStore: this.props.activeRoomStore, 
--- a/browser/components/loop/standalone/content/js/webapp.jsx
+++ b/browser/components/loop/standalone/content/js/webapp.jsx
@@ -88,17 +88,17 @@ loop.webapp = (function($, _, OT, mozL10
    */
   var PromoteFirefoxView = React.createClass({
     propTypes: {
       isFirefox: React.PropTypes.bool.isRequired
     },
 
     render: function() {
       if (this.props.isFirefox) {
-        return <div />;
+        return null;
       }
       return (
         <div className="promote-firefox">
           <h3>{mozL10n.get("promote_firefox_hello_heading", {brandShortname: mozL10n.get("brandShortname")})}</h3>
           <p>
             <a className="btn btn-large btn-accept"
                href={loop.config.downloadFirefoxUrl}>
               {mozL10n.get("get_firefox_button", {
@@ -644,18 +644,18 @@ loop.webapp = (function($, _, OT, mozL10
   var OutgoingConversationView = React.createClass({
     propTypes: {
       client: React.PropTypes.instanceOf(loop.StandaloneClient).isRequired,
       conversation: React.PropTypes.oneOfType([
         React.PropTypes.instanceOf(sharedModels.ConversationModel),
         React.PropTypes.instanceOf(FxOSConversationModel)
       ]).isRequired,
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
-      notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection)
-                          .isRequired,
+      isFirefox: React.PropTypes.bool.isRequired,
+      notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection).isRequired,
       sdk: React.PropTypes.object.isRequired
     },
 
     getInitialState: function() {
       return {
         callStatus: "start"
       };
     },
@@ -733,17 +733,17 @@ loop.webapp = (function($, _, OT, mozL10
               conversation={this.props.conversation}
               dispatcher={this.props.dispatcher}
               onAfterFeedbackReceived={this.resetCallStatus()}
               sdk={this.props.sdk} />
           );
         }
         case "expired": {
           return (
-            <CallUrlExpiredView />
+            <CallUrlExpiredView isFirefox={this.props.isFirefox}/>
           );
         }
         default: {
           return <HomeView />;
         }
       }
     },
 
@@ -981,16 +981,17 @@ loop.webapp = (function($, _, OT, mozL10
           return <UnsupportedBrowserView isFirefox={this.state.isFirefox}/>;
         }
         case "outgoing": {
           return (
             <OutgoingConversationView
                client={this.props.client}
                conversation={this.props.conversation}
                dispatcher={this.props.dispatcher}
+               isFirefox={this.state.isFirefox}
                notifications={this.props.notifications}
                sdk={this.props.sdk} />
           );
         }
         case "room": {
           return (
             <loop.standaloneRoomViews.StandaloneRoomView
               activeRoomStore={this.props.activeRoomStore}
--- a/browser/components/loop/test/index.html
+++ b/browser/components/loop/test/index.html
@@ -9,11 +9,12 @@
 </head>
 <body>
   <h1>Loop tests</h1>
   <ul>
     <li><a href="shared/">Shared tests</a></li>
     <li><a href="desktop-local/">Local tests</a></li>
     <li><a href="standalone/">Standalone tests</a></li>
     <li><a href="coverage/">Code Coverage</a></li>
+    <li><a href="../ui/">UI Showcase</a></li>
  </ul>
 </body>
 </html>
--- a/browser/components/loop/test/standalone/index.html
+++ b/browser/components/loop/test/standalone/index.html
@@ -79,18 +79,18 @@
   <script>
     describe("Uncaught Error Check", function() {
       it("should load the tests without errors", function() {
         chai.expect(uncaughtError && uncaughtError.message).to.be.undefined;
       });
     });
 
     describe("Unexpected Warnings Check", function() {
-      it("should long only the warnings we expect", function() {
-        chai.expect(caughtWarnings.length).to.eql(10);
+      it("should log only the warnings we expect", function() {
+        chai.expect(caughtWarnings.length).to.eql(0);
       });
     });
 
     mocha.run(function () {
       var completeNode = document.createElement("p");
       completeNode.setAttribute("id", "complete");
       completeNode.appendChild(document.createTextNode("Complete"));
       document.getElementById("mocha").appendChild(completeNode);
--- a/browser/components/loop/test/standalone/standaloneMetricsStore_test.js
+++ b/browser/components/loop/test/standalone/standaloneMetricsStore_test.js
@@ -190,10 +190,27 @@ describe("loop.store.StandaloneMetricsSt
         audioMuted: true
       });
 
       sinon.assert.calledOnce(window.ga);
       sinon.assert.calledWithExactly(window.ga,
         "send", "event", METRICS_GA_CATEGORY.general, METRICS_GA_ACTIONS.audioMute,
         "mute");
     });
+
+    describe("Event listeners", function() {
+      it("should call windowUnload when action is dispatched", function() {
+        sandbox.stub(store, "windowUnload");
+
+        dispatcher.dispatch(new sharedActions.WindowUnload());
+        sinon.assert.calledOnce(store.windowUnload);
+      });
+
+      it("should stop listening to activeRoomStore", function() {
+        var stopListeningStub = sandbox.stub(store, "stopListening");
+        store.windowUnload();
+
+        sinon.assert.calledOnce(stopListeningStub);
+        sinon.assert.calledWithExactly(stopListeningStub, store.activeRoomStore);
+      });
+    });
   });
 });
--- a/browser/components/loop/test/standalone/webapp_test.js
+++ b/browser/components/loop/test/standalone/webapp_test.js
@@ -12,26 +12,31 @@ describe("loop.webapp", function() {
       sharedViews = loop.shared.views,
       sharedUtils = loop.shared.utils,
       standaloneMedia = loop.standaloneMedia,
       sandbox,
       notifications,
       stubGetPermsAndCacheMedia,
       fakeAudioXHR,
       dispatcher,
+      mozL10nGet,
       WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
 
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
     dispatcher = new loop.Dispatcher();
     notifications = new sharedModels.NotificationCollection();
 
     stubGetPermsAndCacheMedia = sandbox.stub(
       loop.standaloneMedia._MultiplexGum.prototype, "getPermsAndCacheMedia");
 
+    mozL10nGet = sandbox.stub(navigator.mozL10n, "get", function(x) {
+      return "translated:" + x;
+    });
+
     fakeAudioXHR = {
       open: sinon.spy(),
       send: function() {},
       abort: function() {},
       getResponseHeader: function(header) {
         if (header === "Content-Type") {
           return "audio/ogg";
         }
@@ -109,16 +114,17 @@ describe("loop.webapp", function() {
       sandbox.stub(client, "requestCallUrlInfo");
       conversation = new sharedModels.ConversationModel({}, {
         sdk: {}
       });
       conversation.set("loopToken", "fakeToken");
       ocView = mountTestComponent({
         client: client,
         conversation: conversation,
+        isFirefox: true,
         notifications: notifications,
         sdk: {
           on: sandbox.stub()
         },
         dispatcher: dispatcher
       });
     });
 
@@ -672,56 +678,55 @@ describe("loop.webapp", function() {
       });
       // Stub this to stop the StartConversationView kicking in the request and
       // follow-ups.
       sandbox.stub(client, "requestCallUrlInfo");
     });
 
     it("should display the UnsupportedDeviceView for `unsupportedDevice` window type",
       function() {
-        standaloneAppStore.setStoreState({windowType: "unsupportedDevice"});
-
+        standaloneAppStore.setStoreState({windowType: "unsupportedDevice", unsupportedPlatform: "ios"});
         var webappRootView = mountTestComponent();
 
         TestUtils.findRenderedComponentWithType(webappRootView,
           loop.webapp.UnsupportedDeviceView);
       });
 
     it("should display the UnsupportedBrowserView for `unsupportedBrowser` window type",
       function() {
-        standaloneAppStore.setStoreState({windowType: "unsupportedBrowser"});
+        standaloneAppStore.setStoreState({windowType: "unsupportedBrowser", isFirefox: false});
 
         var webappRootView = mountTestComponent();
 
         TestUtils.findRenderedComponentWithType(webappRootView,
           loop.webapp.UnsupportedBrowserView);
       });
 
     it("should display the OutgoingConversationView for `outgoing` window type",
       function() {
-        standaloneAppStore.setStoreState({windowType: "outgoing"});
+        standaloneAppStore.setStoreState({windowType: "outgoing", isFirefox: true});
 
         var webappRootView = mountTestComponent();
 
         TestUtils.findRenderedComponentWithType(webappRootView,
           loop.webapp.OutgoingConversationView);
       });
 
     it("should display the StandaloneRoomView for `room` window type",
       function() {
-        standaloneAppStore.setStoreState({windowType: "room"});
+        standaloneAppStore.setStoreState({windowType: "room", isFirefox: true});
 
         var webappRootView = mountTestComponent();
 
         TestUtils.findRenderedComponentWithType(webappRootView,
           loop.standaloneRoomViews.StandaloneRoomView);
       });
 
     it("should display the HomeView for `home` window type", function() {
-        standaloneAppStore.setStoreState({windowType: "home"});
+        standaloneAppStore.setStoreState({windowType: "home", isFirefox: true});
 
         var webappRootView = mountTestComponent();
 
         TestUtils.findRenderedComponentWithType(webappRootView,
           loop.webapp.HomeView);
     });
   });
 
@@ -1085,29 +1090,29 @@ describe("loop.webapp", function() {
   });
 
   describe("PromoteFirefoxView", function() {
     describe("#render", function() {
       it("should not render when using Firefox", function() {
         var comp = TestUtils.renderIntoDocument(
           React.createElement(loop.webapp.PromoteFirefoxView, {
             isFirefox: true
-          }));
+        }));
 
-        expect(comp.getDOMNode().querySelectorAll("h3").length).eql(0);
+        expect(comp.getDOMNode()).eql(null);
       });
 
       it("should render when not using Firefox", function() {
         var comp = TestUtils.renderIntoDocument(
-          React.createElement(
-            loop.webapp.PromoteFirefoxView, {
+          React.createElement(loop.webapp.PromoteFirefoxView, {
               isFirefox: false
-            }));
+        }));
 
-        expect(comp.getDOMNode().querySelectorAll("h3").length).eql(1);
+        sinon.assert.calledWith(mozL10nGet, "promote_firefox_hello_heading");
+        sinon.assert.calledWith(mozL10nGet, "get_firefox_button");
       });
     });
   });
 
   describe("Firefox OS", function() {
     var conversation, client;
 
     before(function() {
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -1536,17 +1536,17 @@
         setTimeout(waitForQueuedFrames, 500);
         return;
       }
       // Put the title back, in case views changed it.
       document.title = "Loop UI Components Showcase";
 
       // This simulates the mocha layout for errors which means we can run
       // this alongside our other unit tests but use the same harness.
-      var expectedWarningsCount = 18;
+      var expectedWarningsCount = 16;
       var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
       if (uncaughtError || warningsMismatch) {
         $("#results").append("<div class='failures'><em>" +
           ((uncaughtError && warningsMismatch) ? 2 : 1) + "</em></div>");
         if (warningsMismatch) {
           $("#results").append("<li class='test fail'>" +
             "<h2>Unexpected number of warnings detected in UI-Showcase</h2>" +
             "<pre class='error'>Got: " + caughtWarnings.length + "\n" +
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -1536,17 +1536,17 @@
         setTimeout(waitForQueuedFrames, 500);
         return;
       }
       // Put the title back, in case views changed it.
       document.title = "Loop UI Components Showcase";
 
       // This simulates the mocha layout for errors which means we can run
       // this alongside our other unit tests but use the same harness.
-      var expectedWarningsCount = 18;
+      var expectedWarningsCount = 16;
       var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
       if (uncaughtError || warningsMismatch) {
         $("#results").append("<div class='failures'><em>" +
           ((uncaughtError && warningsMismatch) ? 2 : 1) + "</em></div>");
         if (warningsMismatch) {
           $("#results").append("<li class='test fail'>" +
             "<h2>Unexpected number of warnings detected in UI-Showcase</h2>" +
             "<pre class='error'>Got: " + caughtWarnings.length + "\n" +