Merge "Adapt to changed API in Gerrit core for creating metric fields (part 2)"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..24636d6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+bower_components
+.vscode
+web-component-tester
\ No newline at end of file
diff --git a/README.md b/README.md
index ec00a50..f8b7169 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,8 @@
 
 This plugin provides a unified experience for checkers (CI systems, static
 analyzers, etc.) to integrate with Gerrit Code Review.
+
+This plugin uses [polymer-cli](https://www.polymer-project.org/1.0/docs/tools/polymer-cli#install) to test.
+
+After `bower install`, running `polymer test -l chrome` will run all tests in Chrome, and running `polymer serve` and navigating to http://127.0.0.1:8081/components/checks/gr-checks/gr-checks-view_test.html allows for manual debugging.
+
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..69b6458
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,23 @@
+{
+  "name": "checks",
+  "authors": [
+    "dhruvsri@google.com"
+  ],
+  "license": "http://www.apache.org/licenses/LICENSE-2.0",
+  "dependencies": {
+    "polymer": "Polymer/polymer#^1.0.0",
+    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+    "codemirror-minified": "^5.37.0",
+    "chai": "^4.0.0"
+  },
+  "devDependencies": {
+    "web-component-tester": "Polymer/web-component-tester#^6.0.0",
+    "iron-test-helpers": "^2.0.0",
+    "chai": "^4.0.0",
+    "moment": "^2.24.0"
+  },
+  "private": true,
+  "resolutions": {
+    "chai": "^4.0.0"
+  }
+}
diff --git a/gr-checks/gr-checks-change-list-header-view_test.html b/gr-checks/gr-checks-change-list-header-view_test.html
index d9113f5..b6aa3be 100644
--- a/gr-checks/gr-checks-change-list-header-view_test.html
+++ b/gr-checks/gr-checks-change-list-header-view_test.html
@@ -1,11 +1,12 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+<script src="/bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-change-list-header-view</title>
-<link rel="import" href="webcomponent_lib/gr-checks-change-list-header-view.html">
+<link rel="import" href="gr-checks-change-list-header-view.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
diff --git a/gr-checks/gr-checks-change-list-item-cell-view_test.html b/gr-checks/gr-checks-change-list-item-cell-view_test.html
index c50f7e6..24d5f6b 100644
--- a/gr-checks/gr-checks-change-list-item-cell-view_test.html
+++ b/gr-checks/gr-checks-change-list-item-cell-view_test.html
@@ -1,11 +1,12 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+<script src="/bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-change-list-item-cell-view</title>
-<link rel="import" href="webcomponent_lib/gr-checks-change-list-item-cell-view.html">
+<link rel="import" href="gr-checks-change-list-item-cell-view.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
diff --git a/gr-checks/gr-checks-change-view-tab-header-view_test.html b/gr-checks/gr-checks-change-view-tab-header-view_test.html
index 9915502..79fb0a9 100644
--- a/gr-checks/gr-checks-change-view-tab-header-view_test.html
+++ b/gr-checks/gr-checks-change-view-tab-header-view_test.html
@@ -1,11 +1,13 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-change-view-tab-header-view</title>
-<link rel="import" href="webcomponent_lib/gr-checks-change-view-tab-header-view.html">
+<link rel="import" href="gr-checks-change-view-tab-header-view.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
diff --git a/gr-checks/gr-checks-chip-view.js b/gr-checks/gr-checks-chip-view.js
index 3ed66e1..5e8d6c9 100644
--- a/gr-checks/gr-checks-chip-view.js
+++ b/gr-checks/gr-checks-chip-view.js
@@ -23,6 +23,8 @@
     FAILED: 'failed',
   };
 
+  const CHECKS_POLL_INTERVAL_MS = 60 * 1000;
+
   const Defs = {};
   /**
    * @typedef {{
@@ -81,11 +83,13 @@
       _downgradeFailureToWarning: {
         type: Boolean,
         value: false
-      }
+      },
+      pollChecksInterval: Object,
+      visibilityChangeListener: Object
     },
 
     observers: [
-      '_fetchChecks(change, revision, getChecks)',
+      '_pollChecksRegularly(change, revision, getChecks)',
     ],
 
     listeners: {
@@ -115,13 +119,35 @@
       getChecks(change._number, revision._number).then(checks => {
         this.set('_hasChecks', checks.length > 0);
         if (checks.length > 0) {
-          this.set(
-              '_checkStatuses', computeCheckStatuses(checks));
+          this.set('_checkStatuses', computeCheckStatuses(checks));
           this.set('_downgradeFailureToWarning', downgradeFailureToWarning(checks));
         }
       });
     },
 
+    onVisibililityChange() {
+      if (document.hidden) {
+        clearInterval(this.pollChecksInterval);
+        return;
+      }
+      this._pollChecksRegularly(this.change, this.revision, this.getChecks);
+    },
+
+    _pollChecksRegularly(change, revision, getChecks) {
+      if (this.pollChecksInterval) {
+        clearInterval(this.pollChecksInterval);
+      }
+      const poll = () => this._fetchChecks(change, revision, getChecks);
+      poll();
+      this.pollChecksInterval = setInterval(poll, CHECKS_POLL_INTERVAL_MS);
+      if (!this.visibilityChangeListener) {
+        this.visibilityChangeListener = document.addEventListener(
+          'visibilitychange',
+          this.onVisibililityChange.bind(this)
+        );
+      }
+    },
+
     /**
      * @param {!Object} checkStatuses The number of checks in each status.
      * @return {string}
diff --git a/gr-checks/gr-checks-chip-view_test.html b/gr-checks/gr-checks-chip-view_test.html
index e8decce..b13a855 100644
--- a/gr-checks/gr-checks-chip-view_test.html
+++ b/gr-checks/gr-checks-chip-view_test.html
@@ -1,33 +1,34 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-chip-view</title>
-<link rel="import" href="webcomponent_lib/gr-checks-chip-view.html">
+<link rel="import" href="gr-checks-chip-view.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
-    <gr-checks-chip-view change="[[change]]" revision="[[revision]]" get-gr-checks="[[getChecks]]"></gr-checks-chip-view>
+    <gr-checks-chip-view change="[[change]]" revision="[[revision]]" get-checks="[[getChecks]]"></gr-checks-chip-view>
   </template>
 </test-fixture>
 
 <script>
   const CHECK1 = {
     checkId: 'test-check-id',
-    logUrl: 'http://example.com/test-log-url',
-    startTime: "2019-02-06T22:25:19.269Z",
-    finishTime: "2019-02-06T22:25:44.574Z",
-    status: 'SUCCESSFUL',
+    log: 'http://example.com/test-log-url',
+    started: "2019-02-06T22:25:19.269Z",
+    finished: "2019-02-06T22:25:44.574Z",
+    state: 'SUCCESSFUL',
   };
 
   const CHECK2 = {
     checkId: 'test-check-id-2',
-    logUrl: 'http://example.com/test-log-url',
-    startTime: "2019-02-06T22:25:19.269Z",
-    finishTime: "2019-02-06T22:25:44.574Z",
-    status: 'FAILED',
+    log: 'http://example.com/test-log-url',
+    started: "2019-02-06T22:25:19.269Z",
+    finished: "2019-02-06T22:25:44.574Z",
+    state: 'FAILED',
   };
 
   suite('gr-checks-chip-view tests', () => {
diff --git a/gr-checks/gr-checks-item_test.html b/gr-checks/gr-checks-item_test.html
index ef133aa..dc155dc 100644
--- a/gr-checks/gr-checks-item_test.html
+++ b/gr-checks/gr-checks-item_test.html
@@ -1,11 +1,12 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+<script src="../../../bower_components/webcomponentsjs/webcomponents.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+<script src="../../../bower_components/moment/min/moment.min.js"></script>
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-item</title>
-<link rel="import" href="webcomponent_lib/gr-checks-item.html">
+<link rel="import" href="gr-checks-item.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
@@ -31,9 +32,9 @@
         retryCheck: retryCheckSpy,
         check: {
           checkId: 'test-check-id',
-          logUrl: 'http://example.com/test-log-url',
-          startTime: "2019-02-06T22:25:19.269Z",
-          finishTime: "2019-02-06T22:25:44.574Z",
+          url: 'http://example.com/test-log-url',
+          started: "2019-02-06T22:25:19.269Z",
+          finished: "2019-02-06T22:25:44.574Z",
         },
       });
       flush(done);
@@ -46,14 +47,9 @@
       assert.exists(status);
     });
 
-    test('renders the checking system', () => {
-      const checkingSystem = element.$$('td:nth-child(4)');
-      assert.equal(checkingSystem .textContent.trim(), "Check System");
-    });
-
-    test('renders the run date', () => {
+    test('renders the run time', () => {
       const name = element.$$('td:nth-child(5)');
-      assert.equal(name .textContent.trim(), "2/6/2019");
+      assert.equal(name .textContent.trim(), "11:25:19 PM");
     });
 
     suite('duration', () => {
@@ -65,9 +61,9 @@
       test('renders 0 sec when the start and end time are the same', () => {
         element.check = {
           checkId: 'test-check-id',
-          logUrl: 'http://example.com/test-log-url',
-          startTime: "2019-02-06T22:25:19.269Z",
-          finishTime: "2019-02-06T22:25:19.269Z",
+          url: 'http://example.com/test-log-url',
+          started: "2019-02-06T22:25:19.269Z",
+          finished: "2019-02-06T22:25:19.269Z",
         };
         const name = element.$$('td:nth-child(6)');
         assert.equal(name .textContent.trim(), "0 sec");
@@ -80,22 +76,24 @@
       assert.equal(logLink.textContent.trim(), "View log");
     });
 
-    suite('retryCheck', () => {
-      let retryCheckLink;
+    // pausing this check until retry api is available from backend
+    // suite('retryCheck', () => {
+    //   let retryCheckLink;
 
-      setup(() => {
-        retryCheckLink = element.$$('td:nth-child(7) > gr-button');
-      });
+    //   setup(() => {
+    //     retryCheckLink = element.$$('td:nth-child(7) > gr-button');
+    //   });
 
-      test('shows a link to the log url', () => {
-        assert.equal(retryCheckLink.textContent.trim(), "Re-run");
-      });
+    //   test('shows a link to the retry button', () => {
+    //     assert.equal(retryCheckLink.textContent.trim(), "Re-run");
+    //   });
 
-      test('clicking on the link calls the retryCheck property', () => {
-        assert.isFalse(retryCheckSpy.called);
-        retryCheckLink.click();
-        assert.isTrue(retryCheckSpy.called);
-      });
-    });
+    //   test('clicking on the link calls the retryCheck property', () => {
+    //     assert.isFalse(retryCheckSpy.called);
+    //     retryCheckLink.click();
+    //     assert.isTrue(retryCheckSpy.called);
+    //   });
+    // });
+
   });
 </script>
diff --git a/gr-checks/gr-checks-status.html b/gr-checks/gr-checks-status.html
index a1072bd..591d228 100644
--- a/gr-checks/gr-checks-status.html
+++ b/gr-checks/gr-checks-status.html
@@ -19,7 +19,7 @@
           vertical-align: middle;
         }
       </style>
-    <span class$="[[_className]]">
+    <span>
       <template is="dom-if" if="[[_isUnevaluated(status)]]">
         <svg width="18" height="18" xmlns="http://www.w3.org/2000/svg">
           <g fill="none" fill-rule="evenodd">
diff --git a/gr-checks/gr-checks-status_test.html b/gr-checks/gr-checks-status_test.html
index 6f6a98c..24b00d0 100644
--- a/gr-checks/gr-checks-status_test.html
+++ b/gr-checks/gr-checks-status_test.html
@@ -1,11 +1,12 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-item</title>
-<link rel="import" href="webcomponent_lib/gr-checks-status.html">
+<link rel="import" href="gr-checks-status.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
@@ -35,8 +36,8 @@
             });
 
             flush(() => {
-              const icon = element.$$(`span.${expectedStatusClass} i`);
-              assert.exists(icon);
+              const svg = element.$$(`span svg`);
+              assert.exists(svg);
               done();
             });
           });
@@ -47,7 +48,7 @@
             });
 
             flush(() => {
-              const text = element.$$(`span.${expectedStatusClass} span`);
+              const text = element.$$(`span span`);
               assert.equal(text.textContent.trim(), statusText);
               done();
             });
@@ -58,6 +59,7 @@
 
     testStatus('successful', 'Successful', ['SUCCESSFUL']);
     testStatus('failed', 'Failed', ['FAILED']);
-    testStatus('in-progress', 'In progress', ['NOT_STARTED', 'SCHEDULED', 'RUNNING']);
+    testStatus('running', 'In progress', ['RUNNING', 'SCHEDULED']);
+    testStatus('unevaluated', 'Unevaluated', ['NOT_STARTED']);
   });
 </script>
diff --git a/gr-checks/gr-checks-view.js b/gr-checks/gr-checks-view.js
index e709b28..43643f0 100644
--- a/gr-checks/gr-checks-view.js
+++ b/gr-checks/gr-checks-view.js
@@ -13,6 +13,8 @@
     Statuses.NOT_RELEVANT,
   ];
 
+  const CHECKS_POLL_INTERVAL_MS = 60 * 1000;
+
   /**
    * @typedef {{
    *   _number: number,
@@ -51,10 +53,11 @@
         type: Object,
         value: LoadingStatus.LOADING,
       },
+      pollChecksInterval: Object
     },
 
     observers: [
-      '_fetchChecks(change, revision, getChecks)',
+      '_pollChecksRegularly(change, revision, getChecks)',
     ],
 
 
@@ -92,6 +95,15 @@
       });
     },
 
+    _pollChecksRegularly(change, revision, getChecks) {
+      if (this.pollChecksInterval) {
+        clearInterval(this.pollChecksInterval);
+      }
+      const poll = () => this._fetchChecks(change, revision, getChecks);
+      poll();
+      this.pollChecksInterval = setInterval(poll, CHECKS_POLL_INTERVAL_MS)
+    },
+
     _checkConfigured() {
       const repository = this.change['project'];
       this.isConfigured(repository).then(configured => {
diff --git a/gr-checks/gr-checks-view_test.html b/gr-checks/gr-checks-view_test.html
index 6607e66..d26045e 100644
--- a/gr-checks/gr-checks-view_test.html
+++ b/gr-checks/gr-checks-view_test.html
@@ -1,11 +1,12 @@
 <!DOCTYPE html>
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<script src="imports.js"></script>
-<script src="webcomponentsjs/webcomponents-lite.js"></script>
-<link rel="import" href="polymer/polymer.html">
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="/bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="/bower_components/polymer/polymer.html">
 
 <title>gr-checks-item</title>
-<link rel="import" href="webcomponent_lib/gr-checks-view.html">
+<link rel="import" href="gr-checks-view.html">
 
 <test-fixture id="basic">
   <template is="dom-template">
@@ -75,6 +76,7 @@
       isConfigured: isConfiguredSpy,
       change: {
         'project': 'test-repository',
+        '_number': 2,
         'revisions': {
           'first-sha': "test-revision",
           'second-sha': REVISION,
@@ -93,7 +95,7 @@
 
   test('queries the checks', () => {
     assert.isTrue(getChecksSpy.called);
-    assert.isTrue(getChecksSpy.calledWith('test-repository', 'second-sha'));
+    assert.isTrue(getChecksSpy.calledWith(2, 3));
   });
 
   suite('no checks returned', () => {
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..b1ffd08
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>Test Runner</title>
+<meta charset="utf-8">
+<script src="../bower_components/webcomponentsjs/webcomponents.min.js"></script>
+<script src="../bower_components/web-component-tester/browser.js"></script>
+<script>
+  WCT.loadSuites([
+    '../gr-checks/gr-checks-change-list-header-view_test.html',
+    '../gr-checks/gr-checks-change-list-item-cell-view_test.html',
+    '../gr-checks/gr-checks-change-view-tab-header-view_test.html',
+    '../gr-checks/gr-checks-chip-view_test.html',
+    '../gr-checks/gr-checks-item_test.html',
+    '../gr-checks/gr-checks-status_test.html',
+    '../gr-checks/gr-checks-view_test.html'
+  ]);
+</script>
\ No newline at end of file