Wait for all plugins to load before sending plugin events

Bug: Issue 5068
Change-Id: I10694895c17e3f8b487fb6765d76b78cc98a58e8
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
index bb407aa..360920f 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
@@ -47,23 +47,26 @@
     EventType: EventType,
 
     handleEvent: function(type, detail) {
-      switch (type) {
-        case EventType.HISTORY:
-          this._handleHistory(detail);
-          break;
-        case EventType.SHOW_CHANGE:
-          this._handleShowChange(detail);
-          break;
-        case EventType.COMMENT:
-          this._handleComment(detail);
-          break;
-        case EventType.LABEL_CHANGE:
-          this._handleLabelChange(detail);
-          break;
-        default:
-          console.warn('handleEvent called with unsupported event type:', type);
-          break;
-      }
+      Gerrit.awaitPluginsLoaded().then(function() {
+        switch (type) {
+          case EventType.HISTORY:
+            this._handleHistory(detail);
+            break;
+          case EventType.SHOW_CHANGE:
+            this._handleShowChange(detail);
+            break;
+          case EventType.COMMENT:
+            this._handleComment(detail);
+            break;
+          case EventType.LABEL_CHANGE:
+            this._handleLabelChange(detail);
+            break;
+          default:
+            console.warn('handleEvent called with unsupported event type:',
+                type);
+            break;
+        }
+      }.bind(this));
     },
 
     addElement: function(key, el) {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index 766da84..8efe77d 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -45,6 +45,7 @@
       });
       element = fixture('basic');
       errorStub = sinon.stub(console, 'error');
+      Gerrit._setPluginsCount(1);
       Gerrit.install(function(p) { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
     });
@@ -75,10 +76,7 @@
     test('showchange event', function(done) {
       var testChange = {
         _number: 42,
-        revisions: {
-          def: {_number: 2},
-          abc: {_number: 1},
-        },
+        revisions: {def: {_number: 2}, abc: {_number: 1}},
       };
       plugin.on(element.EventType.SHOW_CHANGE, throwErrFn);
       plugin.on(element.EventType.SHOW_CHANGE, function(change, revision) {
@@ -91,6 +89,24 @@
           {change: testChange, patchNum: 1});
     });
 
+    test('handleEvent awaits plugins load', function(done) {
+      var testChange = {
+        _number: 42,
+        revisions: {def: {_number: 2}, abc: {_number: 1}},
+      };
+      var spy = sinon.spy();
+      Gerrit._setPluginsCount(1);
+      plugin.on(element.EventType.SHOW_CHANGE, spy);
+      element.handleEvent(element.EventType.SHOW_CHANGE,
+          {change: testChange, patchNum: 1});
+      assert.isFalse(spy.called);
+      Gerrit._setPluginsCount(0);
+      flush(function() {
+        assert.isTrue(spy.called);
+        done();
+      });
+    });
+
     test('comment event', function(done) {
       var testCommentNode = {foo: 'bar'};
       plugin.on(element.EventType.COMMENT, throwErrFn);
@@ -185,7 +201,7 @@
     });
 
     test('_arePluginsLoaded', function() {
-      assert.isFalse(Gerrit._arePluginsLoaded());
+      assert.isTrue(Gerrit._arePluginsLoaded());
       Gerrit._setPluginsCount(1);
       assert.isFalse(Gerrit._arePluginsLoaded());
       Gerrit._setPluginsCount(0);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index 2c6212a..588dc8b 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -111,10 +111,29 @@
     Gerrit._pluginInstalled();
   };
 
+  Gerrit._allPluginsPromise = null;
+  Gerrit._resolveAllPluginsLoaded = null;
+
+  Gerrit.awaitPluginsLoaded = function() {
+    if (!Gerrit._allPluginsPromise) {
+      if (Gerrit._arePluginsLoaded()) {
+        Gerrit._allPluginsPromise = Promise.resolve();
+      } else {
+        Gerrit._allPluginsPromise = new Promise(function(resolve) {
+          Gerrit._resolveAllPluginsLoaded = resolve;
+        });
+      }
+    }
+    return Gerrit._allPluginsPromise;
+  };
+
   Gerrit._setPluginsCount = function(count) {
     Gerrit._pluginsPending = count;
     if (Gerrit._arePluginsLoaded()) {
       document.createElement('gr-reporting').pluginsLoaded();
+      if (Gerrit._resolveAllPluginsLoaded) {
+        Gerrit._resolveAllPluginsLoaded();
+      }
     }
   };