Convert polygerrit to es6-modules

This change replace all HTML imports with es6-modules. The only exceptions are:
* gr-app.html file, which can be deleted only after updating the
  gerrit/httpd/raw/PolyGerritIndexHtml.soy file.
* dark-theme.html which is loaded via importHref. Must be updated manually
  later in a separate change.

This change was produced automatically by ./es6-modules-converter.sh script.
No manual changes were made.

Change-Id: I0c447dd8c05757741e2c940720652d01d9fb7d67
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
index ea5740f..c044327 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
@@ -19,17 +19,23 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-annotation-actions-context</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../diff/gr-diff-highlight/gr-annotation.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../diff/gr-diff-highlight/gr-annotation.js"></script>
 
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html"/>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../diff/gr-diff-highlight/gr-annotation.js';
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -37,68 +43,71 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-annotation-actions-context tests', async () => {
-    await readyToTest();
-    let instance;
-    let sandbox;
-    let el;
-    let lineNumberEl;
-    let plugin;
+<script type="module">
+import '../../diff/gr-diff-highlight/gr-annotation.js';
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+suite('gr-annotation-actions-context tests', () => {
+  let instance;
+  let sandbox;
+  let el;
+  let lineNumberEl;
+  let plugin;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
+  setup(() => {
+    sandbox = sinon.sandbox.create();
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
 
-      const str = 'lorem ipsum blah blah';
-      const line = {text: str};
-      el = document.createElement('div');
-      el.textContent = str;
-      el.setAttribute('data-side', 'right');
-      lineNumberEl = document.createElement('td');
-      lineNumberEl.classList.add('right');
-      document.body.appendChild(el);
-      instance = new GrAnnotationActionsContext(
-          el, lineNumberEl, line, 'dummy/path', '123', '1');
-    });
-
-    teardown(() => {
-      sandbox.restore();
-    });
-
-    test('test annotateRange', () => {
-      const annotateElementSpy = sandbox.spy(GrAnnotation, 'annotateElement');
-      const start = 0;
-      const end = 100;
-      const cssStyleObject = plugin.styles().css('background-color: #000000');
-
-      // Assert annotateElement is not called when side is different.
-      instance.annotateRange(start, end, cssStyleObject, 'left');
-      assert.equal(annotateElementSpy.callCount, 0);
-
-      // Assert annotateElement is called once when side is the same.
-      instance.annotateRange(start, end, cssStyleObject, 'right');
-      assert.equal(annotateElementSpy.callCount, 1);
-      const args = annotateElementSpy.getCalls()[0].args;
-      assert.equal(args[0], el);
-      assert.equal(args[1], start);
-      assert.equal(args[2], end);
-      assert.equal(args[3], cssStyleObject.getClassName(el));
-    });
-
-    test('test annotateLineNumber', () => {
-      const cssStyleObject = plugin.styles().css('background-color: #000000');
-
-      const className = cssStyleObject.getClassName(lineNumberEl);
-
-      // Assert that css class is *not* applied when side is different.
-      instance.annotateLineNumber(cssStyleObject, 'left');
-      assert.isFalse(lineNumberEl.classList.contains(className));
-
-      // Assert that css class is applied when side is the same.
-      instance.annotateLineNumber(cssStyleObject, 'right');
-      assert.isTrue(lineNumberEl.classList.contains(className));
-    });
+    const str = 'lorem ipsum blah blah';
+    const line = {text: str};
+    el = document.createElement('div');
+    el.textContent = str;
+    el.setAttribute('data-side', 'right');
+    lineNumberEl = document.createElement('td');
+    lineNumberEl.classList.add('right');
+    document.body.appendChild(el);
+    instance = new GrAnnotationActionsContext(
+        el, lineNumberEl, line, 'dummy/path', '123', '1');
   });
+
+  teardown(() => {
+    sandbox.restore();
+  });
+
+  test('test annotateRange', () => {
+    const annotateElementSpy = sandbox.spy(GrAnnotation, 'annotateElement');
+    const start = 0;
+    const end = 100;
+    const cssStyleObject = plugin.styles().css('background-color: #000000');
+
+    // Assert annotateElement is not called when side is different.
+    instance.annotateRange(start, end, cssStyleObject, 'left');
+    assert.equal(annotateElementSpy.callCount, 0);
+
+    // Assert annotateElement is called once when side is the same.
+    instance.annotateRange(start, end, cssStyleObject, 'right');
+    assert.equal(annotateElementSpy.callCount, 1);
+    const args = annotateElementSpy.getCalls()[0].args;
+    assert.equal(args[0], el);
+    assert.equal(args[1], start);
+    assert.equal(args[2], end);
+    assert.equal(args[3], cssStyleObject.getClassName(el));
+  });
+
+  test('test annotateLineNumber', () => {
+    const cssStyleObject = plugin.styles().css('background-color: #000000');
+
+    const className = cssStyleObject.getClassName(lineNumberEl);
+
+    // Assert that css class is *not* applied when side is different.
+    instance.annotateLineNumber(cssStyleObject, 'left');
+    assert.isFalse(lineNumberEl.classList.contains(className));
+
+    // Assert that css class is applied when side is the same.
+    instance.annotateLineNumber(cssStyleObject, 'right');
+    assert.isTrue(lineNumberEl.classList.contains(className));
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
index b8c4f83..061f22c 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
@@ -19,13 +19,13 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-annotation-actions-js-api-js-api</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="../../change/gr-change-actions/gr-change-actions.html">
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="../../change/gr-change-actions/gr-change-actions.js"></script>
 
 <test-fixture id="basic">
   <template>
@@ -38,153 +38,155 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-annotation-actions-js-api tests', async () => {
-    await readyToTest();
-    let annotationActions;
-    let sandbox;
-    let plugin;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../change/gr-change-actions/gr-change-actions.js';
+suite('gr-annotation-actions-js-api tests', () => {
+  let annotationActions;
+  let sandbox;
+  let plugin;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-      annotationActions = plugin.annotationApi();
-    });
-
-    teardown(() => {
-      annotationActions = null;
-      sandbox.restore();
-    });
-
-    test('add/get layer', () => {
-      const str = 'lorem ipsum blah blah';
-      const line = {text: str};
-      const el = document.createElement('div');
-      el.textContent = str;
-      const changeNum = 1234;
-      const patchNum = 2;
-      let testLayerFuncCalled = false;
-
-      const testLayerFunc = context => {
-        testLayerFuncCalled = true;
-        assert.equal(context.line, line);
-        assert.equal(context.changeNum, changeNum);
-        assert.equal(context.patchNum, 2);
-      };
-      annotationActions.addLayer(testLayerFunc);
-
-      const annotationLayer = annotationActions.getLayer(
-          '/dummy/path', changeNum, patchNum);
-
-      const lineNumberEl = document.createElement('td');
-      annotationLayer.annotate(el, lineNumberEl, line);
-      assert.isTrue(testLayerFuncCalled);
-    });
-
-    test('add notifier', () => {
-      const path1 = '/dummy/path1';
-      const path2 = '/dummy/path2';
-      const annotationLayer1 = annotationActions.getLayer(path1, 1, 2);
-      const annotationLayer2 = annotationActions.getLayer(path2, 1, 2);
-      const layer1Spy = sandbox.spy(annotationLayer1, 'notifyListeners');
-      const layer2Spy = sandbox.spy(annotationLayer2, 'notifyListeners');
-
-      let notify;
-      let notifyFuncCalled;
-      const notifyFunc = n => {
-        notifyFuncCalled = true;
-        notify = n;
-      };
-      annotationActions.addNotifier(notifyFunc);
-      assert.isTrue(notifyFuncCalled);
-
-      // Assert that no layers are invoked with a different path.
-      notify('/dummy/path3', 0, 10, 'right');
-      assert.isFalse(layer1Spy.called);
-      assert.isFalse(layer2Spy.called);
-
-      // Assert that only the 1st layer is invoked with path1.
-      notify(path1, 0, 10, 'right');
-      assert.isTrue(layer1Spy.called);
-      assert.isFalse(layer2Spy.called);
-
-      // Reset spies.
-      layer1Spy.reset();
-      layer2Spy.reset();
-
-      // Assert that only the 2nd layer is invoked with path2.
-      notify(path2, 0, 20, 'left');
-      assert.isFalse(layer1Spy.called);
-      assert.isTrue(layer2Spy.called);
-    });
-
-    test('toggle checkbox', () => {
-      const fakeEl = {content: fixture('basic')};
-      const hookStub = {onAttached: sandbox.stub()};
-      sandbox.stub(plugin, 'hook').returns(hookStub);
-
-      let checkbox;
-      let onAttachedFuncCalled = false;
-      const onAttachedFunc = c => {
-        checkbox = c;
-        onAttachedFuncCalled = true;
-      };
-      annotationActions.enableToggleCheckbox('test label', onAttachedFunc);
-      const emulateAttached = () => hookStub.onAttached.callArgWith(0, fakeEl);
-      emulateAttached();
-
-      // Assert that onAttachedFunc is called and HTML elements have the
-      // expected state.
-      assert.isTrue(onAttachedFuncCalled);
-      assert.equal(checkbox.id, 'annotation-checkbox');
-      assert.isTrue(checkbox.disabled);
-      assert.equal(document.getElementById('annotation-label').textContent,
-          'test label');
-      assert.isFalse(document.getElementById('annotation-span').hidden);
-
-      // Assert that error is shown if we try to enable checkbox again.
-      onAttachedFuncCalled = false;
-      annotationActions.enableToggleCheckbox('test label2', onAttachedFunc);
-      const errorStub = sandbox.stub(
-          console, 'error', (msg, err) => undefined);
-      emulateAttached();
-      assert.isTrue(
-          errorStub.calledWith(
-              'annotation-span is already enabled. Cannot re-enable.'));
-      // Assert that onAttachedFunc is not called and the label has not changed.
-      assert.isFalse(onAttachedFuncCalled);
-      assert.equal(document.getElementById('annotation-label').textContent,
-          'test label');
-    });
-
-    test('layer notify listeners', () => {
-      const annotationLayer = annotationActions.getLayer(
-          '/dummy/path', 1, 2);
-      let listenerCalledTimes = 0;
-      const startRange = 10;
-      const endRange = 20;
-      const side = 'right';
-      const listener = (st, end, s) => {
-        listenerCalledTimes++;
-        assert.equal(st, startRange);
-        assert.equal(end, endRange);
-        assert.equal(s, side);
-      };
-
-      // Notify with 0 listeners added.
-      annotationLayer.notifyListeners(startRange, endRange, side);
-      assert.equal(listenerCalledTimes, 0);
-
-      // Add 1 listener.
-      annotationLayer.addListener(listener);
-      annotationLayer.notifyListeners(startRange, endRange, side);
-      assert.equal(listenerCalledTimes, 1);
-
-      // Add 1 more listener. Total 2 listeners.
-      annotationLayer.addListener(listener);
-      annotationLayer.notifyListeners(startRange, endRange, side);
-      assert.equal(listenerCalledTimes, 3);
-    });
+  setup(() => {
+    sandbox = sinon.sandbox.create();
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
+    annotationActions = plugin.annotationApi();
   });
+
+  teardown(() => {
+    annotationActions = null;
+    sandbox.restore();
+  });
+
+  test('add/get layer', () => {
+    const str = 'lorem ipsum blah blah';
+    const line = {text: str};
+    const el = document.createElement('div');
+    el.textContent = str;
+    const changeNum = 1234;
+    const patchNum = 2;
+    let testLayerFuncCalled = false;
+
+    const testLayerFunc = context => {
+      testLayerFuncCalled = true;
+      assert.equal(context.line, line);
+      assert.equal(context.changeNum, changeNum);
+      assert.equal(context.patchNum, 2);
+    };
+    annotationActions.addLayer(testLayerFunc);
+
+    const annotationLayer = annotationActions.getLayer(
+        '/dummy/path', changeNum, patchNum);
+
+    const lineNumberEl = document.createElement('td');
+    annotationLayer.annotate(el, lineNumberEl, line);
+    assert.isTrue(testLayerFuncCalled);
+  });
+
+  test('add notifier', () => {
+    const path1 = '/dummy/path1';
+    const path2 = '/dummy/path2';
+    const annotationLayer1 = annotationActions.getLayer(path1, 1, 2);
+    const annotationLayer2 = annotationActions.getLayer(path2, 1, 2);
+    const layer1Spy = sandbox.spy(annotationLayer1, 'notifyListeners');
+    const layer2Spy = sandbox.spy(annotationLayer2, 'notifyListeners');
+
+    let notify;
+    let notifyFuncCalled;
+    const notifyFunc = n => {
+      notifyFuncCalled = true;
+      notify = n;
+    };
+    annotationActions.addNotifier(notifyFunc);
+    assert.isTrue(notifyFuncCalled);
+
+    // Assert that no layers are invoked with a different path.
+    notify('/dummy/path3', 0, 10, 'right');
+    assert.isFalse(layer1Spy.called);
+    assert.isFalse(layer2Spy.called);
+
+    // Assert that only the 1st layer is invoked with path1.
+    notify(path1, 0, 10, 'right');
+    assert.isTrue(layer1Spy.called);
+    assert.isFalse(layer2Spy.called);
+
+    // Reset spies.
+    layer1Spy.reset();
+    layer2Spy.reset();
+
+    // Assert that only the 2nd layer is invoked with path2.
+    notify(path2, 0, 20, 'left');
+    assert.isFalse(layer1Spy.called);
+    assert.isTrue(layer2Spy.called);
+  });
+
+  test('toggle checkbox', () => {
+    const fakeEl = {content: fixture('basic')};
+    const hookStub = {onAttached: sandbox.stub()};
+    sandbox.stub(plugin, 'hook').returns(hookStub);
+
+    let checkbox;
+    let onAttachedFuncCalled = false;
+    const onAttachedFunc = c => {
+      checkbox = c;
+      onAttachedFuncCalled = true;
+    };
+    annotationActions.enableToggleCheckbox('test label', onAttachedFunc);
+    const emulateAttached = () => hookStub.onAttached.callArgWith(0, fakeEl);
+    emulateAttached();
+
+    // Assert that onAttachedFunc is called and HTML elements have the
+    // expected state.
+    assert.isTrue(onAttachedFuncCalled);
+    assert.equal(checkbox.id, 'annotation-checkbox');
+    assert.isTrue(checkbox.disabled);
+    assert.equal(document.getElementById('annotation-label').textContent,
+        'test label');
+    assert.isFalse(document.getElementById('annotation-span').hidden);
+
+    // Assert that error is shown if we try to enable checkbox again.
+    onAttachedFuncCalled = false;
+    annotationActions.enableToggleCheckbox('test label2', onAttachedFunc);
+    const errorStub = sandbox.stub(
+        console, 'error', (msg, err) => undefined);
+    emulateAttached();
+    assert.isTrue(
+        errorStub.calledWith(
+            'annotation-span is already enabled. Cannot re-enable.'));
+    // Assert that onAttachedFunc is not called and the label has not changed.
+    assert.isFalse(onAttachedFuncCalled);
+    assert.equal(document.getElementById('annotation-label').textContent,
+        'test label');
+  });
+
+  test('layer notify listeners', () => {
+    const annotationLayer = annotationActions.getLayer(
+        '/dummy/path', 1, 2);
+    let listenerCalledTimes = 0;
+    const startRange = 10;
+    const endRange = 20;
+    const side = 'right';
+    const listener = (st, end, s) => {
+      listenerCalledTimes++;
+      assert.equal(st, startRange);
+      assert.equal(end, endRange);
+      assert.equal(s, side);
+    };
+
+    // Notify with 0 listeners added.
+    annotationLayer.notifyListeners(startRange, endRange, side);
+    assert.equal(listenerCalledTimes, 0);
+
+    // Add 1 listener.
+    annotationLayer.addListener(listener);
+    annotationLayer.notifyListeners(startRange, endRange, side);
+    assert.equal(listenerCalledTimes, 1);
+
+    // Add 1 more listener. Total 2 listeners.
+    annotationLayer.addListener(listener);
+    annotationLayer.notifyListeners(startRange, endRange, side);
+    assert.equal(listenerCalledTimes, 3);
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html
index d70a8d2..154d287 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.html
@@ -19,70 +19,77 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-api-interface</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html">
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
-<script>
-  const PRELOADED_PROTOCOL = 'preloaded:';
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+const PRELOADED_PROTOCOL = 'preloaded:';
 
-  suite('gr-api-utils tests', async () => {
-    await readyToTest();
-    suite('test getPluginNameFromUrl', () => {
-      const {getPluginNameFromUrl} = window._apiUtils;
+suite('gr-api-utils tests', () => {
+  suite('test getPluginNameFromUrl', () => {
+    const {getPluginNameFromUrl} = window._apiUtils;
 
-      test('with empty string', () => {
-        assert.equal(getPluginNameFromUrl(''), null);
-      });
+    test('with empty string', () => {
+      assert.equal(getPluginNameFromUrl(''), null);
+    });
 
-      test('with invalid url', () => {
-        assert.equal(getPluginNameFromUrl('test'), null);
-      });
+    test('with invalid url', () => {
+      assert.equal(getPluginNameFromUrl('test'), null);
+    });
 
-      test('with random invalid url', () => {
-        assert.equal(getPluginNameFromUrl('http://example.com'), null);
-        assert.equal(
-            getPluginNameFromUrl('http://example.com/static/a.html'),
-            null
-        );
-      });
+    test('with random invalid url', () => {
+      assert.equal(getPluginNameFromUrl('http://example.com'), null);
+      assert.equal(
+          getPluginNameFromUrl('http://example.com/static/a.html'),
+          null
+      );
+    });
 
-      test('with valid urls', () => {
-        assert.equal(
-            getPluginNameFromUrl('http://example.com/plugins/a.html'),
-            'a'
-        );
-        assert.equal(
-            getPluginNameFromUrl('http://example.com/plugins/a/static/t.html'),
-            'a'
-        );
-      });
+    test('with valid urls', () => {
+      assert.equal(
+          getPluginNameFromUrl('http://example.com/plugins/a.html'),
+          'a'
+      );
+      assert.equal(
+          getPluginNameFromUrl('http://example.com/plugins/a/static/t.html'),
+          'a'
+      );
+    });
 
-      test('with preloaded urls', () => {
-        assert.equal(getPluginNameFromUrl(`${PRELOADED_PROTOCOL}a`), 'a');
-      });
+    test('with preloaded urls', () => {
+      assert.equal(getPluginNameFromUrl(`${PRELOADED_PROTOCOL}a`), 'a');
+    });
 
-      test('with gerrit-theme override', () => {
-        assert.equal(
-            getPluginNameFromUrl('http://example.com/static/gerrit-theme.html'),
-            'gerrit-theme'
-        );
-      });
+    test('with gerrit-theme override', () => {
+      assert.equal(
+          getPluginNameFromUrl('http://example.com/static/gerrit-theme.html'),
+          'gerrit-theme'
+      );
+    });
 
-      test('with ASSETS_PATH', () => {
-        window.ASSETS_PATH = 'http://cdn.com/2';
-        assert.equal(
-            getPluginNameFromUrl(`${window.ASSETS_PATH}/plugins/a.html`),
-            'a'
-        );
-        window.ASSETS_PATH = undefined;
-      });
+    test('with ASSETS_PATH', () => {
+      window.ASSETS_PATH = 'http://cdn.com/2';
+      assert.equal(
+          getPluginNameFromUrl(`${window.ASSETS_PATH}/plugins/a.html`),
+          'a'
+      );
+      window.ASSETS_PATH = undefined;
     });
   });
+});
 </script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
index 91e1a49..1425f71 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
@@ -19,19 +19,24 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-change-actions-js-api</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
 <!--
 This must refer to the element this interface is wrapping around. Otherwise
 breaking changes to gr-change-actions won’t be noticed.
 -->
-<link rel="import" href="../../change/gr-change-actions/gr-change-actions.html">
+<script type="module" src="../../change/gr-change-actions/gr-change-actions.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../change/gr-change-actions/gr-change-actions.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -39,191 +44,194 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-js-api-interface tests', async () => {
-    await readyToTest();
-    let element;
-    let changeActions;
-    let plugin;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../change/gr-change-actions/gr-change-actions.js';
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+suite('gr-js-api-interface tests', () => {
+  let element;
+  let changeActions;
+  let plugin;
 
-    // Because deepEqual doesn’t behave in Safari.
-    function assertArraysEqual(actual, expected) {
-      assert.equal(actual.length, expected.length);
-      for (let i = 0; i < actual.length; i++) {
-        assert.equal(actual[i], expected[i]);
-      }
+  // Because deepEqual doesn’t behave in Safari.
+  function assertArraysEqual(actual, expected) {
+    assert.equal(actual.length, expected.length);
+    for (let i = 0; i < actual.length; i++) {
+      assert.equal(actual[i], expected[i]);
     }
+  }
 
-    suite('early init', () => {
-      setup(() => {
-        Gerrit._testOnly_resetPlugins();
-        Gerrit.install(p => { plugin = p; }, '0.1',
-            'http://test.com/plugins/testplugin/static/test.js');
-        // Mimic all plugins loaded.
-        Gerrit._loadPlugins([]);
-        changeActions = plugin.changeActions();
-        element = fixture('basic');
+  suite('early init', () => {
+    setup(() => {
+      Gerrit._testOnly_resetPlugins();
+      Gerrit.install(p => { plugin = p; }, '0.1',
+          'http://test.com/plugins/testplugin/static/test.js');
+      // Mimic all plugins loaded.
+      Gerrit._loadPlugins([]);
+      changeActions = plugin.changeActions();
+      element = fixture('basic');
+    });
+
+    teardown(() => {
+      changeActions = null;
+      Gerrit._testOnly_resetPlugins();
+    });
+
+    test('does not throw', ()=> {
+      assert.doesNotThrow(() => {
+        changeActions.add('change', 'foo');
       });
+    });
+  });
 
-      teardown(() => {
-        changeActions = null;
-        Gerrit._testOnly_resetPlugins();
-      });
+  suite('normal init', () => {
+    setup(() => {
+      Gerrit._testOnly_resetPlugins();
+      element = fixture('basic');
+      sinon.stub(element, '_editStatusChanged');
+      element.change = {};
+      element._hasKnownChainState = false;
+      Gerrit.install(p => { plugin = p; }, '0.1',
+          'http://test.com/plugins/testplugin/static/test.js');
+      changeActions = plugin.changeActions();
+      // Mimic all plugins loaded.
+      Gerrit._loadPlugins([]);
+    });
 
-      test('does not throw', ()=> {
-        assert.doesNotThrow(() => {
-          changeActions.add('change', 'foo');
+    teardown(() => {
+      changeActions = null;
+      Gerrit._testOnly_resetPlugins();
+    });
+
+    test('property existence', () => {
+      const properties = [
+        'ActionType',
+        'ChangeActions',
+        'RevisionActions',
+      ];
+      for (const p of properties) {
+        assertArraysEqual(changeActions[p], element[p]);
+      }
+    });
+
+    test('add/remove primary action keys', () => {
+      element.primaryActionKeys = [];
+      changeActions.addPrimaryActionKey('foo');
+      assertArraysEqual(element.primaryActionKeys, ['foo']);
+      changeActions.addPrimaryActionKey('foo');
+      assertArraysEqual(element.primaryActionKeys, ['foo']);
+      changeActions.addPrimaryActionKey('bar');
+      assertArraysEqual(element.primaryActionKeys, ['foo', 'bar']);
+      changeActions.removePrimaryActionKey('foo');
+      assertArraysEqual(element.primaryActionKeys, ['bar']);
+      changeActions.removePrimaryActionKey('baz');
+      assertArraysEqual(element.primaryActionKeys, ['bar']);
+      changeActions.removePrimaryActionKey('bar');
+      assertArraysEqual(element.primaryActionKeys, []);
+    });
+
+    test('action buttons', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      const handler = sinon.spy();
+      changeActions.addTapListener(key, handler);
+      flush(() => {
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('[data-action-key="' + key + '"]'));
+        assert(handler.calledOnce);
+        changeActions.removeTapListener(key, handler);
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('[data-action-key="' + key + '"]'));
+        assert(handler.calledOnce);
+        changeActions.remove(key);
+        flush(() => {
+          assert.isNull(element.shadowRoot
+              .querySelector('[data-action-key="' + key + '"]'));
+          done();
         });
       });
     });
 
-    suite('normal init', () => {
-      setup(() => {
-        Gerrit._testOnly_resetPlugins();
-        element = fixture('basic');
-        sinon.stub(element, '_editStatusChanged');
-        element.change = {};
-        element._hasKnownChainState = false;
-        Gerrit.install(p => { plugin = p; }, '0.1',
-            'http://test.com/plugins/testplugin/static/test.js');
-        changeActions = plugin.changeActions();
-        // Mimic all plugins loaded.
-        Gerrit._loadPlugins([]);
-      });
-
-      teardown(() => {
-        changeActions = null;
-        Gerrit._testOnly_resetPlugins();
-      });
-
-      test('property existence', () => {
-        const properties = [
-          'ActionType',
-          'ChangeActions',
-          'RevisionActions',
-        ];
-        for (const p of properties) {
-          assertArraysEqual(changeActions[p], element[p]);
-        }
-      });
-
-      test('add/remove primary action keys', () => {
-        element.primaryActionKeys = [];
-        changeActions.addPrimaryActionKey('foo');
-        assertArraysEqual(element.primaryActionKeys, ['foo']);
-        changeActions.addPrimaryActionKey('foo');
-        assertArraysEqual(element.primaryActionKeys, ['foo']);
-        changeActions.addPrimaryActionKey('bar');
-        assertArraysEqual(element.primaryActionKeys, ['foo', 'bar']);
-        changeActions.removePrimaryActionKey('foo');
-        assertArraysEqual(element.primaryActionKeys, ['bar']);
-        changeActions.removePrimaryActionKey('baz');
-        assertArraysEqual(element.primaryActionKeys, ['bar']);
-        changeActions.removePrimaryActionKey('bar');
-        assertArraysEqual(element.primaryActionKeys, []);
-      });
-
-      test('action buttons', done => {
-        const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-        const handler = sinon.spy();
-        changeActions.addTapListener(key, handler);
+    test('action button properties', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        const button = element.shadowRoot
+            .querySelector('[data-action-key="' + key + '"]');
+        assert.isOk(button);
+        assert.equal(button.getAttribute('data-label'), 'Bork!');
+        assert.isNotOk(button.disabled);
+        changeActions.setLabel(key, 'Yo');
+        changeActions.setTitle(key, 'Yo hint');
+        changeActions.setEnabled(key, false);
+        changeActions.setIcon(key, 'pupper');
         flush(() => {
-          MockInteractions.tap(element.shadowRoot
-              .querySelector('[data-action-key="' + key + '"]'));
-          assert(handler.calledOnce);
-          changeActions.removeTapListener(key, handler);
-          MockInteractions.tap(element.shadowRoot
-              .querySelector('[data-action-key="' + key + '"]'));
-          assert(handler.calledOnce);
-          changeActions.remove(key);
-          flush(() => {
-            assert.isNull(element.shadowRoot
-                .querySelector('[data-action-key="' + key + '"]'));
-            done();
-          });
+          assert.equal(button.getAttribute('data-label'), 'Yo');
+          assert.equal(button.getAttribute('title'), 'Yo hint');
+          assert.isTrue(button.disabled);
+          assert.equal(dom(button).querySelector('iron-icon').icon,
+              'gr-icons:pupper');
+          done();
         });
       });
+    });
 
-      test('action button properties', done => {
-        const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+    test('hide action buttons', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        const button = element.shadowRoot
+            .querySelector('[data-action-key="' + key + '"]');
+        assert.isOk(button);
+        assert.isFalse(button.hasAttribute('hidden'));
+        changeActions.setActionHidden(
+            changeActions.ActionType.REVISION, key, true);
         flush(() => {
           const button = element.shadowRoot
               .querySelector('[data-action-key="' + key + '"]');
-          assert.isOk(button);
-          assert.equal(button.getAttribute('data-label'), 'Bork!');
-          assert.isNotOk(button.disabled);
-          changeActions.setLabel(key, 'Yo');
-          changeActions.setTitle(key, 'Yo hint');
-          changeActions.setEnabled(key, false);
-          changeActions.setIcon(key, 'pupper');
-          flush(() => {
-            assert.equal(button.getAttribute('data-label'), 'Yo');
-            assert.equal(button.getAttribute('title'), 'Yo hint');
-            assert.isTrue(button.disabled);
-            assert.equal(Polymer.dom(button).querySelector('iron-icon').icon,
-                'gr-icons:pupper');
-            done();
-          });
+          assert.isNotOk(button);
+          done();
         });
       });
+    });
 
-      test('hide action buttons', done => {
-        const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+    test('move action button to overflow', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        assert.isTrue(element.$.moreActions.hidden);
+        assert.isOk(element.shadowRoot
+            .querySelector('[data-action-key="' + key + '"]'));
+        changeActions.setActionOverflow(
+            changeActions.ActionType.REVISION, key, true);
         flush(() => {
-          const button = element.shadowRoot
-              .querySelector('[data-action-key="' + key + '"]');
-          assert.isOk(button);
-          assert.isFalse(button.hasAttribute('hidden'));
-          changeActions.setActionHidden(
-              changeActions.ActionType.REVISION, key, true);
-          flush(() => {
-            const button = element.shadowRoot
-                .querySelector('[data-action-key="' + key + '"]');
-            assert.isNotOk(button);
-            done();
-          });
-        });
-      });
-
-      test('move action button to overflow', done => {
-        const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-        flush(() => {
-          assert.isTrue(element.$.moreActions.hidden);
-          assert.isOk(element.shadowRoot
+          assert.isNotOk(element.shadowRoot
               .querySelector('[data-action-key="' + key + '"]'));
-          changeActions.setActionOverflow(
-              changeActions.ActionType.REVISION, key, true);
-          flush(() => {
-            assert.isNotOk(element.shadowRoot
-                .querySelector('[data-action-key="' + key + '"]'));
-            assert.isFalse(element.$.moreActions.hidden);
-            assert.strictEqual(element.$.moreActions.items[0].name, 'Bork!');
-            done();
-          });
+          assert.isFalse(element.$.moreActions.hidden);
+          assert.strictEqual(element.$.moreActions.items[0].name, 'Bork!');
+          done();
         });
       });
+    });
 
-      test('change actions priority', done => {
-        const key1 =
-          changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-        const key2 =
-          changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
+    test('change actions priority', done => {
+      const key1 =
+        changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      const key2 =
+        changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
+      flush(() => {
+        let buttons =
+          dom(element.root).querySelectorAll('[data-action-key]');
+        assert.equal(buttons[0].getAttribute('data-action-key'), key1);
+        assert.equal(buttons[1].getAttribute('data-action-key'), key2);
+        changeActions.setActionPriority(
+            changeActions.ActionType.REVISION, key1, 10);
         flush(() => {
-          let buttons =
-            Polymer.dom(element.root).querySelectorAll('[data-action-key]');
-          assert.equal(buttons[0].getAttribute('data-action-key'), key1);
-          assert.equal(buttons[1].getAttribute('data-action-key'), key2);
-          changeActions.setActionPriority(
-              changeActions.ActionType.REVISION, key1, 10);
-          flush(() => {
-            buttons =
-              Polymer.dom(element.root).querySelectorAll('[data-action-key]');
-            assert.equal(buttons[0].getAttribute('data-action-key'), key2);
-            assert.equal(buttons[1].getAttribute('data-action-key'), key1);
-            done();
-          });
+          buttons =
+            dom(element.root).querySelectorAll('[data-action-key]');
+          assert.equal(buttons[0].getAttribute('data-action-key'), key2);
+          assert.equal(buttons[1].getAttribute('data-action-key'), key1);
+          done();
         });
       });
     });
   });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
index 3147746..3a1c51c 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
@@ -19,19 +19,24 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-change-reply-js-api</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
 <!--
 This must refer to the element this interface is wrapping around. Otherwise
 breaking changes to gr-reply-dialog won’t be noticed.
 -->
-<link rel="import" href="../../change/gr-reply-dialog/gr-reply-dialog.html">
+<script type="module" src="../../change/gr-reply-dialog/gr-reply-dialog.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../change/gr-reply-dialog/gr-reply-dialog.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -39,86 +44,88 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-change-reply-js-api tests', async () => {
-    await readyToTest();
-    let element;
-    let sandbox;
-    let changeReply;
-    let plugin;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import '../../change/gr-reply-dialog/gr-reply-dialog.js';
+suite('gr-change-reply-js-api tests', () => {
+  let element;
+  let sandbox;
+  let changeReply;
+  let plugin;
 
+  setup(() => {
+    sandbox = sinon.sandbox.create();
+    stub('gr-rest-api-interface', {
+      getConfig() { return Promise.resolve({}); },
+      getAccount() { return Promise.resolve(null); },
+    });
+  });
+
+  teardown(() => {
+    sandbox.restore();
+  });
+
+  suite('early init', () => {
     setup(() => {
-      sandbox = sinon.sandbox.create();
-      stub('gr-rest-api-interface', {
-        getConfig() { return Promise.resolve({}); },
-        getAccount() { return Promise.resolve(null); },
-      });
+      Gerrit.install(p => { plugin = p; }, '0.1',
+          'http://test.com/plugins/testplugin/static/test.js');
+      changeReply = plugin.changeReply();
+      element = fixture('basic');
     });
 
     teardown(() => {
-      sandbox.restore();
+      changeReply = null;
     });
 
-    suite('early init', () => {
-      setup(() => {
-        Gerrit.install(p => { plugin = p; }, '0.1',
-            'http://test.com/plugins/testplugin/static/test.js');
-        changeReply = plugin.changeReply();
-        element = fixture('basic');
-      });
+    test('works', () => {
+      sandbox.stub(element, 'getLabelValue').returns('+123');
+      assert.equal(changeReply.getLabelValue('My-Label'), '+123');
 
-      teardown(() => {
-        changeReply = null;
-      });
+      sandbox.stub(element, 'setLabelValue');
+      changeReply.setLabelValue('My-Label', '+1337');
+      assert.isTrue(
+          element.setLabelValue.calledWithExactly('My-Label', '+1337'));
 
-      test('works', () => {
-        sandbox.stub(element, 'getLabelValue').returns('+123');
-        assert.equal(changeReply.getLabelValue('My-Label'), '+123');
+      sandbox.stub(element, 'send');
+      changeReply.send(false);
+      assert.isTrue(element.send.calledWithExactly(false));
 
-        sandbox.stub(element, 'setLabelValue');
-        changeReply.setLabelValue('My-Label', '+1337');
-        assert.isTrue(
-            element.setLabelValue.calledWithExactly('My-Label', '+1337'));
-
-        sandbox.stub(element, 'send');
-        changeReply.send(false);
-        assert.isTrue(element.send.calledWithExactly(false));
-
-        sandbox.stub(element, 'setPluginMessage');
-        changeReply.showMessage('foobar');
-        assert.isTrue(element.setPluginMessage.calledWithExactly('foobar'));
-      });
-    });
-
-    suite('normal init', () => {
-      setup(() => {
-        element = fixture('basic');
-        Gerrit.install(p => { plugin = p; }, '0.1',
-            'http://test.com/plugins/testplugin/static/test.js');
-        changeReply = plugin.changeReply();
-      });
-
-      teardown(() => {
-        changeReply = null;
-      });
-
-      test('works', () => {
-        sandbox.stub(element, 'getLabelValue').returns('+123');
-        assert.equal(changeReply.getLabelValue('My-Label'), '+123');
-
-        sandbox.stub(element, 'setLabelValue');
-        changeReply.setLabelValue('My-Label', '+1337');
-        assert.isTrue(
-            element.setLabelValue.calledWithExactly('My-Label', '+1337'));
-
-        sandbox.stub(element, 'send');
-        changeReply.send(false);
-        assert.isTrue(element.send.calledWithExactly(false));
-
-        sandbox.stub(element, 'setPluginMessage');
-        changeReply.showMessage('foobar');
-        assert.isTrue(element.setPluginMessage.calledWithExactly('foobar'));
-      });
+      sandbox.stub(element, 'setPluginMessage');
+      changeReply.showMessage('foobar');
+      assert.isTrue(element.setPluginMessage.calledWithExactly('foobar'));
     });
   });
+
+  suite('normal init', () => {
+    setup(() => {
+      element = fixture('basic');
+      Gerrit.install(p => { plugin = p; }, '0.1',
+          'http://test.com/plugins/testplugin/static/test.js');
+      changeReply = plugin.changeReply();
+    });
+
+    teardown(() => {
+      changeReply = null;
+    });
+
+    test('works', () => {
+      sandbox.stub(element, 'getLabelValue').returns('+123');
+      assert.equal(changeReply.getLabelValue('My-Label'), '+123');
+
+      sandbox.stub(element, 'setLabelValue');
+      changeReply.setLabelValue('My-Label', '+1337');
+      assert.isTrue(
+          element.setLabelValue.calledWithExactly('My-Label', '+1337'));
+
+      sandbox.stub(element, 'send');
+      changeReply.send(false);
+      assert.isTrue(element.send.calledWithExactly(false));
+
+      sandbox.stub(element, 'setPluginMessage');
+      changeReply.showMessage('foobar');
+      assert.isTrue(element.setPluginMessage.calledWithExactly('foobar'));
+    });
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html
index ee95a5e..57f0646 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit_test.html
@@ -19,15 +19,20 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-api-interface</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html">
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -35,68 +40,70 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-gerrit tests', async () => {
-    await readyToTest();
-    let element;
-    let sandbox;
-    let sendStub;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+suite('gr-gerrit tests', () => {
+  let element;
+  let sandbox;
+  let sendStub;
 
-    setup(() => {
-      window.clock = sinon.useFakeTimers();
-      sandbox = sinon.sandbox.create();
-      sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
-      stub('gr-rest-api-interface', {
-        getAccount() {
-          return Promise.resolve({name: 'Judy Hopps'});
-        },
-        send(...args) {
-          return sendStub(...args);
-        },
-      });
-      element = fixture('basic');
+  setup(() => {
+    window.clock = sinon.useFakeTimers();
+    sandbox = sinon.sandbox.create();
+    sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
+    stub('gr-rest-api-interface', {
+      getAccount() {
+        return Promise.resolve({name: 'Judy Hopps'});
+      },
+      send(...args) {
+        return sendStub(...args);
+      },
+    });
+    element = fixture('basic');
+  });
+
+  teardown(() => {
+    window.clock.restore();
+    sandbox.restore();
+    element._removeEventCallbacks();
+    Gerrit._testOnly_resetPlugins();
+  });
+
+  suite('proxy methods', () => {
+    test('Gerrit._isPluginEnabled proxy to pluginLoader', () => {
+      const stubFn = sandbox.stub();
+      sandbox.stub(
+          Gerrit._pluginLoader,
+          'isPluginEnabled',
+          (...args) => stubFn(...args)
+      );
+      Gerrit._isPluginEnabled('test_plugin');
+      assert.isTrue(stubFn.calledWith('test_plugin'));
     });
 
-    teardown(() => {
-      window.clock.restore();
-      sandbox.restore();
-      element._removeEventCallbacks();
-      Gerrit._testOnly_resetPlugins();
+    test('Gerrit._isPluginLoaded proxy to pluginLoader', () => {
+      const stubFn = sandbox.stub();
+      sandbox.stub(
+          Gerrit._pluginLoader,
+          'isPluginLoaded',
+          (...args) => stubFn(...args)
+      );
+      Gerrit._isPluginLoaded('test_plugin');
+      assert.isTrue(stubFn.calledWith('test_plugin'));
     });
 
-    suite('proxy methods', () => {
-      test('Gerrit._isPluginEnabled proxy to pluginLoader', () => {
-        const stubFn = sandbox.stub();
-        sandbox.stub(
-            Gerrit._pluginLoader,
-            'isPluginEnabled',
-            (...args) => stubFn(...args)
-        );
-        Gerrit._isPluginEnabled('test_plugin');
-        assert.isTrue(stubFn.calledWith('test_plugin'));
-      });
-
-      test('Gerrit._isPluginLoaded proxy to pluginLoader', () => {
-        const stubFn = sandbox.stub();
-        sandbox.stub(
-            Gerrit._pluginLoader,
-            'isPluginLoaded',
-            (...args) => stubFn(...args)
-        );
-        Gerrit._isPluginLoaded('test_plugin');
-        assert.isTrue(stubFn.calledWith('test_plugin'));
-      });
-
-      test('Gerrit._isPluginPreloaded proxy to pluginLoader', () => {
-        const stubFn = sandbox.stub();
-        sandbox.stub(
-            Gerrit._pluginLoader,
-            'isPluginPreloaded',
-            (...args) => stubFn(...args)
-        );
-        Gerrit._isPluginPreloaded('test_plugin');
-        assert.isTrue(stubFn.calledWith('test_plugin'));
-      });
+    test('Gerrit._isPluginPreloaded proxy to pluginLoader', () => {
+      const stubFn = sandbox.stub();
+      sandbox.stub(
+          Gerrit._pluginLoader,
+          'isPluginPreloaded',
+          (...args) => stubFn(...args)
+      );
+      Gerrit._isPluginPreloaded('test_plugin');
+      assert.isTrue(stubFn.calledWith('test_plugin'));
     });
   });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.html
deleted file mode 100644
index 922fa57..0000000
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-@license
-Copyright (C) 2020 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.
--->
-
-<link rel="import" href="/bower_components/polymer/polymer.html">
-<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
-<link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
-
-<dom-module id="gr-js-api-interface">
-  <script src="gr-js-api-interface-element.js"></script>
-</dom-module>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js
index 393dc77..2523d47 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js
@@ -1,6 +1,6 @@
 /**
  * @license
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,306 +14,311 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-(function() {
-  'use strict';
+import '../../../scripts/bundled-polymer.js';
 
-  // Note: for new events, naming convention should be: `a-b`
-  const EventType = {
-    HISTORY: 'history',
-    LABEL_CHANGE: 'labelchange',
-    SHOW_CHANGE: 'showchange',
-    SUBMIT_CHANGE: 'submitchange',
-    SHOW_REVISION_ACTIONS: 'show-revision-actions',
-    COMMIT_MSG_EDIT: 'commitmsgedit',
-    COMMENT: 'comment',
-    REVERT: 'revert',
-    REVERT_SUBMISSION: 'revert_submission',
-    POST_REVERT: 'postrevert',
-    ANNOTATE_DIFF: 'annotatediff',
-    ADMIN_MENU_LINKS: 'admin-menu-links',
-    HIGHLIGHTJS_LOADED: 'highlightjs-loaded',
-  };
+import '../../../behaviors/base-url-behavior/base-url-behavior.js';
+import '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
+import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
+import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
+import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
+import {PolymerElement} from '@polymer/polymer/polymer-element.js';
 
-  const Element = {
-    CHANGE_ACTIONS: 'changeactions',
-    REPLY_DIALOG: 'replydialog',
-  };
+// Note: for new events, naming convention should be: `a-b`
+const EventType = {
+  HISTORY: 'history',
+  LABEL_CHANGE: 'labelchange',
+  SHOW_CHANGE: 'showchange',
+  SUBMIT_CHANGE: 'submitchange',
+  SHOW_REVISION_ACTIONS: 'show-revision-actions',
+  COMMIT_MSG_EDIT: 'commitmsgedit',
+  COMMENT: 'comment',
+  REVERT: 'revert',
+  REVERT_SUBMISSION: 'revert_submission',
+  POST_REVERT: 'postrevert',
+  ANNOTATE_DIFF: 'annotatediff',
+  ADMIN_MENU_LINKS: 'admin-menu-links',
+  HIGHLIGHTJS_LOADED: 'highlightjs-loaded',
+};
 
-  /**
-   * @appliesMixin Gerrit.PatchSetMixin
-   * @extends Polymer.Element
-   */
-  class GrJsApiInterface extends Polymer.mixinBehaviors( [
-    Gerrit.PatchSetBehavior,
-  ], Polymer.GestureEventListeners(
-      Polymer.LegacyElementMixin(
-          Polymer.Element))) {
-    static get is() { return 'gr-js-api-interface'; }
+const Element = {
+  CHANGE_ACTIONS: 'changeactions',
+  REPLY_DIALOG: 'replydialog',
+};
 
-    constructor() {
-      super();
-      this.Element = Element;
-      this.EventType = EventType;
-    }
+/**
+ * @appliesMixin Gerrit.PatchSetMixin
+ * @extends Polymer.Element
+ */
+class GrJsApiInterface extends mixinBehaviors( [
+  Gerrit.PatchSetBehavior,
+], GestureEventListeners(
+    LegacyElementMixin(
+        PolymerElement))) {
+  static get is() { return 'gr-js-api-interface'; }
 
-    static get properties() {
-      return {
-        _elements: {
-          type: Object,
-          value: {}, // Shared across all instances.
-        },
-        _eventCallbacks: {
-          type: Object,
-          value: {}, // Shared across all instances.
-        },
-      };
-    }
+  constructor() {
+    super();
+    this.Element = Element;
+    this.EventType = EventType;
+  }
 
-    handleEvent(type, detail) {
-      Gerrit.awaitPluginsLoaded().then(() => {
-        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;
-          case EventType.SHOW_REVISION_ACTIONS:
-            this._handleShowRevisionActions(detail);
-            break;
-          case EventType.HIGHLIGHTJS_LOADED:
-            this._handleHighlightjsLoaded(detail);
-            break;
-          default:
-            console.warn('handleEvent called with unsupported event type:',
-                type);
-            break;
-        }
-      });
-    }
+  static get properties() {
+    return {
+      _elements: {
+        type: Object,
+        value: {}, // Shared across all instances.
+      },
+      _eventCallbacks: {
+        type: Object,
+        value: {}, // Shared across all instances.
+      },
+    };
+  }
 
-    addElement(key, el) {
-      this._elements[key] = el;
-    }
-
-    getElement(key) {
-      return this._elements[key];
-    }
-
-    addEventCallback(eventName, callback) {
-      if (!this._eventCallbacks[eventName]) {
-        this._eventCallbacks[eventName] = [];
-      }
-      this._eventCallbacks[eventName].push(callback);
-    }
-
-    canSubmitChange(change, revision) {
-      const submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
-      const cancelSubmit = submitCallbacks.some(callback => {
-        try {
-          return callback(change, revision) === false;
-        } catch (err) {
-          console.error(err);
-        }
-        return false;
-      });
-
-      return !cancelSubmit;
-    }
-
-    _removeEventCallbacks() {
-      for (const k in EventType) {
-        if (!EventType.hasOwnProperty(k)) { continue; }
-        this._eventCallbacks[EventType[k]] = [];
-      }
-    }
-
-    _handleHistory(detail) {
-      for (const cb of this._getEventCallbacks(EventType.HISTORY)) {
-        try {
-          cb(detail.path);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-    }
-
-    _handleShowChange(detail) {
-      // Note (issue 8221) Shallow clone the change object and add a mergeable
-      // getter with deprecation warning. This makes the change detail appear as
-      // though SKIP_MERGEABLE was not set, so that plugins that expect it can
-      // still access.
-      //
-      // This clone and getter can be removed after plugins migrate to use
-      // info.mergeable.
-      //
-      // assign on getter with existing property will report error
-      // see Issue: 12286
-      const change = Object.assign({}, detail.change, {
-        get mergeable() {
-          console.warn('Accessing change.mergeable from SHOW_CHANGE is ' +
-              'deprecated! Use info.mergeable instead.');
-          return detail.info && detail.info.mergeable;
-        },
-      });
-      const patchNum = detail.patchNum;
-      const info = detail.info;
-
-      let revision;
-      for (const rev of Object.values(change.revisions || {})) {
-        if (this.patchNumEquals(rev._number, patchNum)) {
-          revision = rev;
+  handleEvent(type, detail) {
+    Gerrit.awaitPluginsLoaded().then(() => {
+      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;
+        case EventType.SHOW_REVISION_ACTIONS:
+          this._handleShowRevisionActions(detail);
+          break;
+        case EventType.HIGHLIGHTJS_LOADED:
+          this._handleHighlightjsLoaded(detail);
+          break;
+        default:
+          console.warn('handleEvent called with unsupported event type:',
+              type);
+          break;
       }
+    });
+  }
 
-      for (const cb of this._getEventCallbacks(EventType.SHOW_CHANGE)) {
-        try {
-          cb(change, revision, info);
-        } catch (err) {
-          console.error(err);
-        }
+  addElement(key, el) {
+    this._elements[key] = el;
+  }
+
+  getElement(key) {
+    return this._elements[key];
+  }
+
+  addEventCallback(eventName, callback) {
+    if (!this._eventCallbacks[eventName]) {
+      this._eventCallbacks[eventName] = [];
+    }
+    this._eventCallbacks[eventName].push(callback);
+  }
+
+  canSubmitChange(change, revision) {
+    const submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
+    const cancelSubmit = submitCallbacks.some(callback => {
+      try {
+        return callback(change, revision) === false;
+      } catch (err) {
+        console.error(err);
       }
-    }
+      return false;
+    });
 
-    /**
-     * @param {!{change: !Object, revisionActions: !Object}} detail
-     */
-    _handleShowRevisionActions(detail) {
-      const registeredCallbacks = this._getEventCallbacks(
-          EventType.SHOW_REVISION_ACTIONS
-      );
-      for (const cb of registeredCallbacks) {
-        try {
-          cb(detail.revisionActions, detail.change);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-    }
+    return !cancelSubmit;
+  }
 
-    handleCommitMessage(change, msg) {
-      for (const cb of this._getEventCallbacks(EventType.COMMIT_MSG_EDIT)) {
-        try {
-          cb(change, msg);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-    }
-
-    _handleComment(detail) {
-      for (const cb of this._getEventCallbacks(EventType.COMMENT)) {
-        try {
-          cb(detail.node);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-    }
-
-    _handleLabelChange(detail) {
-      for (const cb of this._getEventCallbacks(EventType.LABEL_CHANGE)) {
-        try {
-          cb(detail.change);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-    }
-
-    _handleHighlightjsLoaded(detail) {
-      for (const cb of this._getEventCallbacks(EventType.HIGHLIGHTJS_LOADED)) {
-        try {
-          cb(detail.hljs);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-    }
-
-    modifyRevertMsg(change, revertMsg, origMsg) {
-      for (const cb of this._getEventCallbacks(EventType.REVERT)) {
-        try {
-          revertMsg = cb(change, revertMsg, origMsg);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-      return revertMsg;
-    }
-
-    modifyRevertSubmissionMsg(change, revertSubmissionMsg, origMsg) {
-      for (const cb of this._getEventCallbacks(EventType.REVERT_SUBMISSION)) {
-        try {
-          revertSubmissionMsg = cb(change, revertSubmissionMsg, origMsg);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-      return revertSubmissionMsg;
-    }
-
-    getDiffLayers(path, changeNum, patchNum) {
-      const layers = [];
-      for (const annotationApi of
-        this._getEventCallbacks(EventType.ANNOTATE_DIFF)) {
-        try {
-          const layer = annotationApi.getLayer(path, changeNum, patchNum);
-          layers.push(layer);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-      return layers;
-    }
-
-    /**
-     * Retrieves coverage data possibly provided by a plugin.
-     *
-     * Will wait for plugins to be loaded. If multiple plugins offer a coverage
-     * provider, the first one is returned. If no plugin offers a coverage provider,
-     * will resolve to null.
-     *
-     * @return {!Promise<?GrAnnotationActionsInterface>}
-     */
-    getCoverageAnnotationApi() {
-      return Gerrit.awaitPluginsLoaded()
-          .then(() => this._getEventCallbacks(EventType.ANNOTATE_DIFF)
-              .find(api => api.getCoverageProvider()));
-    }
-
-    getAdminMenuLinks() {
-      const links = [];
-      for (const adminApi of
-        this._getEventCallbacks(EventType.ADMIN_MENU_LINKS)) {
-        links.push(...adminApi.getMenuLinks());
-      }
-      return links;
-    }
-
-    getLabelValuesPostRevert(change) {
-      let labels = {};
-      for (const cb of this._getEventCallbacks(EventType.POST_REVERT)) {
-        try {
-          labels = cb(change);
-        } catch (err) {
-          console.error(err);
-        }
-      }
-      return labels;
-    }
-
-    _getEventCallbacks(type) {
-      return this._eventCallbacks[type] || [];
+  _removeEventCallbacks() {
+    for (const k in EventType) {
+      if (!EventType.hasOwnProperty(k)) { continue; }
+      this._eventCallbacks[EventType[k]] = [];
     }
   }
 
-  customElements.define(GrJsApiInterface.is, GrJsApiInterface);
-})();
+  _handleHistory(detail) {
+    for (const cb of this._getEventCallbacks(EventType.HISTORY)) {
+      try {
+        cb(detail.path);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  _handleShowChange(detail) {
+    // Note (issue 8221) Shallow clone the change object and add a mergeable
+    // getter with deprecation warning. This makes the change detail appear as
+    // though SKIP_MERGEABLE was not set, so that plugins that expect it can
+    // still access.
+    //
+    // This clone and getter can be removed after plugins migrate to use
+    // info.mergeable.
+    //
+    // assign on getter with existing property will report error
+    // see Issue: 12286
+    const change = Object.assign({}, detail.change, {
+      get mergeable() {
+        console.warn('Accessing change.mergeable from SHOW_CHANGE is ' +
+            'deprecated! Use info.mergeable instead.');
+        return detail.info && detail.info.mergeable;
+      },
+    });
+    const patchNum = detail.patchNum;
+    const info = detail.info;
+
+    let revision;
+    for (const rev of Object.values(change.revisions || {})) {
+      if (this.patchNumEquals(rev._number, patchNum)) {
+        revision = rev;
+        break;
+      }
+    }
+
+    for (const cb of this._getEventCallbacks(EventType.SHOW_CHANGE)) {
+      try {
+        cb(change, revision, info);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  /**
+   * @param {!{change: !Object, revisionActions: !Object}} detail
+   */
+  _handleShowRevisionActions(detail) {
+    const registeredCallbacks = this._getEventCallbacks(
+        EventType.SHOW_REVISION_ACTIONS
+    );
+    for (const cb of registeredCallbacks) {
+      try {
+        cb(detail.revisionActions, detail.change);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  handleCommitMessage(change, msg) {
+    for (const cb of this._getEventCallbacks(EventType.COMMIT_MSG_EDIT)) {
+      try {
+        cb(change, msg);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  _handleComment(detail) {
+    for (const cb of this._getEventCallbacks(EventType.COMMENT)) {
+      try {
+        cb(detail.node);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  _handleLabelChange(detail) {
+    for (const cb of this._getEventCallbacks(EventType.LABEL_CHANGE)) {
+      try {
+        cb(detail.change);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  _handleHighlightjsLoaded(detail) {
+    for (const cb of this._getEventCallbacks(EventType.HIGHLIGHTJS_LOADED)) {
+      try {
+        cb(detail.hljs);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+  }
+
+  modifyRevertMsg(change, revertMsg, origMsg) {
+    for (const cb of this._getEventCallbacks(EventType.REVERT)) {
+      try {
+        revertMsg = cb(change, revertMsg, origMsg);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+    return revertMsg;
+  }
+
+  modifyRevertSubmissionMsg(change, revertSubmissionMsg, origMsg) {
+    for (const cb of this._getEventCallbacks(EventType.REVERT_SUBMISSION)) {
+      try {
+        revertSubmissionMsg = cb(change, revertSubmissionMsg, origMsg);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+    return revertSubmissionMsg;
+  }
+
+  getDiffLayers(path, changeNum, patchNum) {
+    const layers = [];
+    for (const annotationApi of
+      this._getEventCallbacks(EventType.ANNOTATE_DIFF)) {
+      try {
+        const layer = annotationApi.getLayer(path, changeNum, patchNum);
+        layers.push(layer);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+    return layers;
+  }
+
+  /**
+   * Retrieves coverage data possibly provided by a plugin.
+   *
+   * Will wait for plugins to be loaded. If multiple plugins offer a coverage
+   * provider, the first one is returned. If no plugin offers a coverage provider,
+   * will resolve to null.
+   *
+   * @return {!Promise<?GrAnnotationActionsInterface>}
+   */
+  getCoverageAnnotationApi() {
+    return Gerrit.awaitPluginsLoaded()
+        .then(() => this._getEventCallbacks(EventType.ANNOTATE_DIFF)
+            .find(api => api.getCoverageProvider()));
+  }
+
+  getAdminMenuLinks() {
+    const links = [];
+    for (const adminApi of
+      this._getEventCallbacks(EventType.ADMIN_MENU_LINKS)) {
+      links.push(...adminApi.getMenuLinks());
+    }
+    return links;
+  }
+
+  getLabelValuesPostRevert(change) {
+    let labels = {};
+    for (const cb of this._getEventCallbacks(EventType.POST_REVERT)) {
+      try {
+        labels = cb(change);
+      } catch (err) {
+        console.error(err);
+      }
+    }
+    return labels;
+  }
+
+  _getEventCallbacks(type) {
+    return this._eventCallbacks[type] || [];
+  }
+}
+
+customElements.define(GrJsApiInterface.is, GrJsApiInterface);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
deleted file mode 100644
index a4909ec..0000000
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!--
-@license
-Copyright (C) 2016 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.
--->
-<link rel="import" href="/bower_components/polymer/polymer.html">
-<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
-<link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
-<link rel="import" href="../../core/gr-reporting/gr-reporting.html">
-<link rel="import" href="../../plugins/gr-admin-api/gr-admin-api.html">
-<link rel="import" href="../../plugins/gr-attribute-helper/gr-attribute-helper.html">
-<link rel="import" href="../../plugins/gr-change-metadata-api/gr-change-metadata-api.html">
-<link rel="import" href="../../plugins/gr-dom-hooks/gr-dom-hooks.html">
-<link rel="import" href="../../plugins/gr-event-helper/gr-event-helper.html">
-<link rel="import" href="../../plugins/gr-popup-interface/gr-popup-interface.html">
-<link rel="import" href="../../plugins/gr-repo-api/gr-repo-api.html">
-<link rel="import" href="../../plugins/gr-settings-api/gr-settings-api.html">
-<link rel="import" href="../../plugins/gr-styles-api/gr-styles-api.html">
-<link rel="import" href="../../plugins/gr-theme-api/gr-theme-api.html">
-<link rel="import" href="../gr-rest-api-interface/gr-rest-api-interface.html">
-<!--
-  Note: the order matters as files depend on each other.
-  1. gr-api-utils will be used in multiple files below.
-  2. gr-gerrit depends on gr-plugin-loader, gr-public-js-api and
-    also gr-plugin-endpoints
-  3. gr-public-js-api depends on gr-plugin-rest-api
--->
-<script src="gr-api-utils.js"></script>
-<script src="../gr-event-interface/gr-event-interface.js"></script>
-<script src="gr-annotation-actions-context.js"></script>
-<script src="gr-annotation-actions-js-api.js"></script>
-<script src="gr-change-actions-js-api.js"></script>
-<script src="gr-change-reply-js-api.js"></script>
-<link rel="import" href="./gr-js-api-interface-element.html">
-<script src="gr-plugin-endpoints.js"></script>
-<script src="gr-plugin-action-context.js"></script>
-<script src="gr-plugin-rest-api.js"></script>
-<script src="gr-public-js-api.js"></script>
-<script src="gr-plugin-loader.js"></script>
-<script src="gr-gerrit.js"></script>
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
new file mode 100644
index 0000000..6b7b13e
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
@@ -0,0 +1,58 @@
+/**
+ * @license
+ * Copyright (C) 2016 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.
+ */
+import '../../../scripts/bundled-polymer.js';
+import '../../../behaviors/base-url-behavior/base-url-behavior.js';
+import '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
+import '../../core/gr-reporting/gr-reporting.js';
+import '../../plugins/gr-admin-api/gr-admin-api.js';
+import '../../plugins/gr-attribute-helper/gr-attribute-helper.js';
+import '../../plugins/gr-change-metadata-api/gr-change-metadata-api.js';
+import '../../plugins/gr-dom-hooks/gr-dom-hooks.js';
+import '../../plugins/gr-event-helper/gr-event-helper.js';
+import '../../plugins/gr-popup-interface/gr-popup-interface.js';
+import '../../plugins/gr-repo-api/gr-repo-api.js';
+import '../../plugins/gr-settings-api/gr-settings-api.js';
+import '../../plugins/gr-styles-api/gr-styles-api.js';
+import '../../plugins/gr-theme-api/gr-theme-api.js';
+import '../gr-rest-api-interface/gr-rest-api-interface.js';
+import './gr-api-utils.js';
+import '../gr-event-interface/gr-event-interface.js';
+import './gr-annotation-actions-context.js';
+import './gr-annotation-actions-js-api.js';
+import './gr-change-actions-js-api.js';
+import './gr-change-reply-js-api.js';
+import './gr-js-api-interface-element.js';
+import './gr-plugin-endpoints.js';
+import './gr-plugin-action-context.js';
+import './gr-plugin-rest-api.js';
+import './gr-public-js-api.js';
+import './gr-plugin-loader.js';
+import './gr-gerrit.js';
+
+/*
+  Note: the order matters as files depend on each other.
+  1. gr-api-utils will be used in multiple files below.
+  2. gr-gerrit depends on gr-plugin-loader, gr-public-js-api and
+    also gr-plugin-endpoints
+  3. gr-public-js-api depends on gr-plugin-rest-api
+*/
+/*
+  FIXME(polymer-modulizer): the above comments were extracted
+  from HTML and may be out of place here. Review them and
+  then delete this comment!
+*/
+
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 efc7206..04ad490 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
@@ -19,15 +19,20 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-api-interface</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html">
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -35,539 +40,541 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-js-api-interface tests', async () => {
-    await readyToTest();
-    const {PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
-    let element;
-    let plugin;
-    let errorStub;
-    let sandbox;
-    let getResponseObjectStub;
-    let sendStub;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+suite('gr-js-api-interface tests', () => {
+  const {PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
+  let element;
+  let plugin;
+  let errorStub;
+  let sandbox;
+  let getResponseObjectStub;
+  let sendStub;
 
-    const throwErrFn = function() {
-      throw Error('Unfortunately, this handler has stopped');
+  const throwErrFn = function() {
+    throw Error('Unfortunately, this handler has stopped');
+  };
+
+  setup(() => {
+    window.clock = sinon.useFakeTimers();
+    sandbox = sinon.sandbox.create();
+    getResponseObjectStub = sandbox.stub().returns(Promise.resolve());
+    sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
+    stub('gr-rest-api-interface', {
+      getAccount() {
+        return Promise.resolve({name: 'Judy Hopps'});
+      },
+      getResponseObject: getResponseObjectStub,
+      send(...args) {
+        return sendStub(...args);
+      },
+    });
+    element = fixture('basic');
+    errorStub = sandbox.stub(console, 'error');
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
+    Gerrit._loadPlugins([]);
+  });
+
+  teardown(() => {
+    window.clock.restore();
+    sandbox.restore();
+    element._removeEventCallbacks();
+    plugin = null;
+  });
+
+  test('url', () => {
+    assert.equal(plugin.url(), 'http://test.com/plugins/testplugin/');
+    assert.equal(plugin.url('/static/test.js'),
+        'http://test.com/plugins/testplugin/static/test.js');
+  });
+
+  test('url for preloaded plugin without ASSETS_PATH', () => {
+    let plugin;
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'preloaded:testpluginB');
+    assert.equal(plugin.url(),
+        `${window.location.origin}/plugins/testpluginB/`);
+    assert.equal(plugin.url('/static/test.js'),
+        `${window.location.origin}/plugins/testpluginB/static/test.js`);
+  });
+
+  test('url for preloaded plugin without ASSETS_PATH', () => {
+    const oldAssetsPath = window.ASSETS_PATH;
+    window.ASSETS_PATH = 'http://test.com';
+    let plugin;
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'preloaded:testpluginC');
+    assert.equal(plugin.url(), `${window.ASSETS_PATH}/plugins/testpluginC/`);
+    assert.equal(plugin.url('/static/test.js'),
+        `${window.ASSETS_PATH}/plugins/testpluginC/static/test.js`);
+    window.ASSETS_PATH = oldAssetsPath;
+  });
+
+  test('_send on failure rejects with response text', () => {
+    sendStub.returns(Promise.resolve(
+        {status: 400, text() { return Promise.resolve('text'); }}));
+    return plugin._send().catch(r => {
+      assert.equal(r.message, 'text');
+    });
+  });
+
+  test('_send on failure without text rejects with code', () => {
+    sendStub.returns(Promise.resolve(
+        {status: 400, text() { return Promise.resolve(null); }}));
+    return plugin._send().catch(r => {
+      assert.equal(r.message, '400');
+    });
+  });
+
+  test('get', () => {
+    const response = {foo: 'foo'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return plugin.get('/url', r => {
+      assert.isTrue(sendStub.calledWith(
+          'GET', 'http://test.com/plugins/testplugin/url'));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('get using Promise', () => {
+    const response = {foo: 'foo'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return plugin.get('/url', r => 'rubbish').then(r => {
+      assert.isTrue(sendStub.calledWith(
+          'GET', 'http://test.com/plugins/testplugin/url'));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('post', () => {
+    const payload = {foo: 'foo'};
+    const response = {bar: 'bar'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return plugin.post('/url', payload, r => {
+      assert.isTrue(sendStub.calledWith(
+          'POST', 'http://test.com/plugins/testplugin/url', payload));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('put', () => {
+    const payload = {foo: 'foo'};
+    const response = {bar: 'bar'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return plugin.put('/url', payload, r => {
+      assert.isTrue(sendStub.calledWith(
+          'PUT', 'http://test.com/plugins/testplugin/url', payload));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('delete works', () => {
+    const response = {status: 204};
+    sendStub.returns(Promise.resolve(response));
+    return plugin.delete('/url', r => {
+      assert.isTrue(sendStub.calledWithExactly(
+          'DELETE', 'http://test.com/plugins/testplugin/url'));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('delete fails', () => {
+    sendStub.returns(Promise.resolve(
+        {status: 400, text() { return Promise.resolve('text'); }}));
+    return plugin.delete('/url', r => {
+      throw new Error('Should not resolve');
+    }).catch(err => {
+      assert.isTrue(sendStub.calledWith(
+          'DELETE', 'http://test.com/plugins/testplugin/url'));
+      assert.equal('text', err.message);
+    });
+  });
+
+  test('history event', done => {
+    plugin.on(element.EventType.HISTORY, throwErrFn);
+    plugin.on(element.EventType.HISTORY, path => {
+      assert.equal(path, '/path/to/awesomesauce');
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleEvent(element.EventType.HISTORY,
+        {path: '/path/to/awesomesauce'});
+  });
+
+  test('showchange event', done => {
+    const testChange = {
+      _number: 42,
+      revisions: {def: {_number: 2}, abc: {_number: 1}},
     };
+    const expectedChange = Object.assign({mergeable: false}, testChange);
+    plugin.on(element.EventType.SHOW_CHANGE, throwErrFn);
+    plugin.on(element.EventType.SHOW_CHANGE, (change, revision, info) => {
+      assert.deepEqual(change, expectedChange);
+      assert.deepEqual(revision, testChange.revisions.abc);
+      assert.deepEqual(info, {mergeable: false});
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleEvent(element.EventType.SHOW_CHANGE,
+        {change: testChange, patchNum: 1, info: {mergeable: false}});
+  });
+
+  test('show-revision-actions event', done => {
+    const testChange = {
+      _number: 42,
+      revisions: {def: {_number: 2}, abc: {_number: 1}},
+    };
+    plugin.on(element.EventType.SHOW_REVISION_ACTIONS, throwErrFn);
+    plugin.on(element.EventType.SHOW_REVISION_ACTIONS, (actions, change) => {
+      assert.deepEqual(change, testChange);
+      assert.deepEqual(actions, {test: {}});
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleEvent(element.EventType.SHOW_REVISION_ACTIONS,
+        {change: testChange, revisionActions: {test: {}}});
+  });
+
+  test('handleEvent awaits plugins load', done => {
+    const testChange = {
+      _number: 42,
+      revisions: {def: {_number: 2}, abc: {_number: 1}},
+    };
+    const spy = sandbox.spy();
+    Gerrit._loadPlugins(['plugins/test.html']);
+    plugin.on(element.EventType.SHOW_CHANGE, spy);
+    element.handleEvent(element.EventType.SHOW_CHANGE,
+        {change: testChange, patchNum: 1});
+    assert.isFalse(spy.called);
+
+    // Timeout on loading plugins
+    window.clock.tick(PLUGIN_LOADING_TIMEOUT_MS * 2);
+
+    flush(() => {
+      assert.isTrue(spy.called);
+      done();
+    });
+  });
+
+  test('comment event', done => {
+    const testCommentNode = {foo: 'bar'};
+    plugin.on(element.EventType.COMMENT, throwErrFn);
+    plugin.on(element.EventType.COMMENT, commentNode => {
+      assert.deepEqual(commentNode, testCommentNode);
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleEvent(element.EventType.COMMENT, {node: testCommentNode});
+  });
+
+  test('revert event', () => {
+    function appendToRevertMsg(c, revertMsg, originalMsg) {
+      return revertMsg + '\n' + originalMsg.replace(/^/gm, '> ') + '\ninfo';
+    }
+
+    assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'), 'test');
+    assert.equal(errorStub.callCount, 0);
+
+    plugin.on(element.EventType.REVERT, throwErrFn);
+    plugin.on(element.EventType.REVERT, appendToRevertMsg);
+    assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
+        'test\n> origTest\ninfo');
+    assert.isTrue(errorStub.calledOnce);
+
+    plugin.on(element.EventType.REVERT, appendToRevertMsg);
+    assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
+        'test\n> origTest\ninfo\n> origTest\ninfo');
+    assert.isTrue(errorStub.calledTwice);
+  });
+
+  test('postrevert event', () => {
+    function getLabels(c) {
+      return {'Code-Review': 1};
+    }
+
+    assert.deepEqual(element.getLabelValuesPostRevert(null), {});
+    assert.equal(errorStub.callCount, 0);
+
+    plugin.on(element.EventType.POST_REVERT, throwErrFn);
+    plugin.on(element.EventType.POST_REVERT, getLabels);
+    assert.deepEqual(
+        element.getLabelValuesPostRevert(null), {'Code-Review': 1});
+    assert.isTrue(errorStub.calledOnce);
+  });
+
+  test('commitmsgedit event', done => {
+    const testMsg = 'Test CL commit message';
+    plugin.on(element.EventType.COMMIT_MSG_EDIT, throwErrFn);
+    plugin.on(element.EventType.COMMIT_MSG_EDIT, (change, msg) => {
+      assert.deepEqual(msg, testMsg);
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleCommitMessage(null, testMsg);
+  });
+
+  test('labelchange event', done => {
+    const testChange = {_number: 42};
+    plugin.on(element.EventType.LABEL_CHANGE, throwErrFn);
+    plugin.on(element.EventType.LABEL_CHANGE, change => {
+      assert.deepEqual(change, testChange);
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleEvent(element.EventType.LABEL_CHANGE, {change: testChange});
+  });
+
+  test('submitchange', () => {
+    plugin.on(element.EventType.SUBMIT_CHANGE, throwErrFn);
+    plugin.on(element.EventType.SUBMIT_CHANGE, () => true);
+    assert.isTrue(element.canSubmitChange());
+    assert.isTrue(errorStub.calledOnce);
+    plugin.on(element.EventType.SUBMIT_CHANGE, () => false);
+    plugin.on(element.EventType.SUBMIT_CHANGE, () => true);
+    assert.isFalse(element.canSubmitChange());
+    assert.isTrue(errorStub.calledTwice);
+  });
+
+  test('highlightjs-loaded event', done => {
+    const testHljs = {_number: 42};
+    plugin.on(element.EventType.HIGHLIGHTJS_LOADED, throwErrFn);
+    plugin.on(element.EventType.HIGHLIGHTJS_LOADED, hljs => {
+      assert.deepEqual(hljs, testHljs);
+      assert.isTrue(errorStub.calledOnce);
+      done();
+    });
+    element.handleEvent(element.EventType.HIGHLIGHTJS_LOADED, {hljs: testHljs});
+  });
+
+  test('getLoggedIn', done => {
+    // fake fetch for authCheck
+    sandbox.stub(window, 'fetch', () => Promise.resolve({status: 204}));
+    plugin.restApi().getLoggedIn()
+        .then(loggedIn => {
+          assert.isTrue(loggedIn);
+          done();
+        });
+  });
+
+  test('attributeHelper', () => {
+    assert.isOk(plugin.attributeHelper());
+  });
+
+  test('deprecated.install', () => {
+    plugin.deprecated.install();
+    assert.strictEqual(plugin.popup, plugin.deprecated.popup);
+    assert.strictEqual(plugin.onAction, plugin.deprecated.onAction);
+    assert.notStrictEqual(plugin.install, plugin.deprecated.install);
+  });
+
+  test('getAdminMenuLinks', () => {
+    const links = [{text: 'a', url: 'b'}, {text: 'c', url: 'd'}];
+    const getCallbacksStub = sandbox.stub(element, '_getEventCallbacks')
+        .returns([
+          {getMenuLinks: () => [links[0]]},
+          {getMenuLinks: () => [links[1]]},
+        ]);
+    const result = element.getAdminMenuLinks();
+    assert.deepEqual(result, links);
+    assert.isTrue(getCallbacksStub.calledOnce);
+    assert.equal(getCallbacksStub.lastCall.args[0],
+        element.EventType.ADMIN_MENU_LINKS);
+  });
+
+  suite('test plugin with base url', () => {
+    let baseUrlPlugin;
 
     setup(() => {
-      window.clock = sinon.useFakeTimers();
-      sandbox = sinon.sandbox.create();
-      getResponseObjectStub = sandbox.stub().returns(Promise.resolve());
-      sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
-      stub('gr-rest-api-interface', {
-        getAccount() {
-          return Promise.resolve({name: 'Judy Hopps'});
-        },
-        getResponseObject: getResponseObjectStub,
-        send(...args) {
-          return sendStub(...args);
-        },
-      });
-      element = fixture('basic');
-      errorStub = sandbox.stub(console, 'error');
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-      Gerrit._loadPlugins([]);
-    });
+      sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl').returns('/r');
 
-    teardown(() => {
-      window.clock.restore();
-      sandbox.restore();
-      element._removeEventCallbacks();
-      plugin = null;
+      Gerrit.install(p => { baseUrlPlugin = p; }, '0.1',
+          'http://test.com/r/plugins/baseurlplugin/static/test.js');
     });
 
     test('url', () => {
-      assert.equal(plugin.url(), 'http://test.com/plugins/testplugin/');
-      assert.equal(plugin.url('/static/test.js'),
-          'http://test.com/plugins/testplugin/static/test.js');
+      assert.notEqual(baseUrlPlugin.url(),
+          'http://test.com/plugins/baseurlplugin/');
+      assert.equal(baseUrlPlugin.url(),
+          'http://test.com/r/plugins/baseurlplugin/');
+      assert.equal(baseUrlPlugin.url('/static/test.js'),
+          'http://test.com/r/plugins/baseurlplugin/static/test.js');
+    });
+  });
+
+  suite('popup', () => {
+    test('popup(element) is deprecated', () => {
+      plugin.popup(document.createElement('div'));
+      assert.isTrue(console.error.calledOnce);
     });
 
-    test('url for preloaded plugin without ASSETS_PATH', () => {
-      let plugin;
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'preloaded:testpluginB');
-      assert.equal(plugin.url(),
-          `${window.location.origin}/plugins/testpluginB/`);
-      assert.equal(plugin.url('/static/test.js'),
-          `${window.location.origin}/plugins/testpluginB/static/test.js`);
+    test('popup(moduleName) creates popup with component', () => {
+      const openStub = sandbox.stub();
+      sandbox.stub(window, 'GrPopupInterface').returns({
+        open: openStub,
+      });
+      plugin.popup('some-name');
+      assert.isTrue(openStub.calledOnce);
+      assert.isTrue(GrPopupInterface.calledWith(plugin, 'some-name'));
     });
 
-    test('url for preloaded plugin without ASSETS_PATH', () => {
-      const oldAssetsPath = window.ASSETS_PATH;
-      window.ASSETS_PATH = 'http://test.com';
-      let plugin;
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'preloaded:testpluginC');
-      assert.equal(plugin.url(), `${window.ASSETS_PATH}/plugins/testpluginC/`);
-      assert.equal(plugin.url('/static/test.js'),
-          `${window.ASSETS_PATH}/plugins/testpluginC/static/test.js`);
-      window.ASSETS_PATH = oldAssetsPath;
+    test('deprecated.popup(element) creates popup with element', () => {
+      const el = document.createElement('div');
+      el.textContent = 'some text here';
+      const openStub = sandbox.stub(GrPopupInterface.prototype, 'open');
+      openStub.returns(Promise.resolve({
+        _getElement() {
+          return document.createElement('div');
+        }}));
+      plugin.deprecated.popup(el);
+      assert.isTrue(openStub.calledOnce);
     });
+  });
 
-    test('_send on failure rejects with response text', () => {
-      sendStub.returns(Promise.resolve(
-          {status: 400, text() { return Promise.resolve('text'); }}));
-      return plugin._send().catch(r => {
-        assert.equal(r.message, 'text');
+  suite('onAction', () => {
+    let change;
+    let revision;
+    let actionDetails;
+
+    setup(() => {
+      change = {};
+      revision = {};
+      actionDetails = {__key: 'some'};
+      sandbox.stub(plugin, 'on').callsArgWith(1, change, revision);
+      sandbox.stub(plugin, 'changeActions').returns({
+        addTapListener: sandbox.stub().callsArg(1),
+        getActionDetails: () => actionDetails,
       });
     });
 
-    test('_send on failure without text rejects with code', () => {
-      sendStub.returns(Promise.resolve(
-          {status: 400, text() { return Promise.resolve(null); }}));
-      return plugin._send().catch(r => {
-        assert.equal(r.message, '400');
+    test('returns GrPluginActionContext', () => {
+      const stub = sandbox.stub();
+      plugin.deprecated.onAction('change', 'foo', ctx => {
+        assert.isTrue(ctx instanceof GrPluginActionContext);
+        assert.strictEqual(ctx.change, change);
+        assert.strictEqual(ctx.revision, revision);
+        assert.strictEqual(ctx.action, actionDetails);
+        assert.strictEqual(ctx.plugin, plugin);
+        stub();
       });
+      assert.isTrue(stub.called);
     });
 
-    test('get', () => {
-      const response = {foo: 'foo'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return plugin.get('/url', r => {
-        assert.isTrue(sendStub.calledWith(
-            'GET', 'http://test.com/plugins/testplugin/url'));
-        assert.strictEqual(r, response);
-      });
+    test('other actions', () => {
+      const stub = sandbox.stub();
+      plugin.deprecated.onAction('project', 'foo', stub);
+      plugin.deprecated.onAction('edit', 'foo', stub);
+      plugin.deprecated.onAction('branch', 'foo', stub);
+      assert.isFalse(stub.called);
+    });
+  });
+
+  suite('screen', () => {
+    test('screenUrl()', () => {
+      sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl').returns('/base');
+      assert.equal(plugin.screenUrl(), 'http://test.com/base/x/testplugin');
+      assert.equal(
+          plugin.screenUrl('foo'), 'http://test.com/base/x/testplugin/foo');
     });
 
-    test('get using Promise', () => {
-      const response = {foo: 'foo'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return plugin.get('/url', r => 'rubbish').then(r => {
-        assert.isTrue(sendStub.calledWith(
-            'GET', 'http://test.com/plugins/testplugin/url'));
-        assert.strictEqual(r, response);
-      });
+    test('deprecated works', () => {
+      const stub = sandbox.stub();
+      const hookStub = {onAttached: sandbox.stub()};
+      sandbox.stub(plugin, 'hook').returns(hookStub);
+      plugin.deprecated.screen('foo', stub);
+      assert.isTrue(plugin.hook.calledWith('testplugin-screen-foo'));
+      const fakeEl = {style: {display: ''}};
+      hookStub.onAttached.callArgWith(0, fakeEl);
+      assert.isTrue(stub.called);
+      assert.equal(fakeEl.style.display, 'none');
     });
 
-    test('post', () => {
-      const payload = {foo: 'foo'};
-      const response = {bar: 'bar'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return plugin.post('/url', payload, r => {
-        assert.isTrue(sendStub.calledWith(
-            'POST', 'http://test.com/plugins/testplugin/url', payload));
-        assert.strictEqual(r, response);
-      });
+    test('works', () => {
+      sandbox.stub(plugin, 'registerCustomComponent');
+      plugin.screen('foo', 'some-module');
+      assert.isTrue(plugin.registerCustomComponent.calledWith(
+          'testplugin-screen-foo', 'some-module'));
+    });
+  });
+
+  suite('panel', () => {
+    let fakeEl;
+    let emulateAttached;
+
+    setup(()=> {
+      fakeEl = {change: {}, revision: {}};
+      const hookStub = {onAttached: sandbox.stub()};
+      sandbox.stub(plugin, 'hook').returns(hookStub);
+      emulateAttached = () => hookStub.onAttached.callArgWith(0, fakeEl);
     });
 
-    test('put', () => {
-      const payload = {foo: 'foo'};
-      const response = {bar: 'bar'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return plugin.put('/url', payload, r => {
-        assert.isTrue(sendStub.calledWith(
-            'PUT', 'http://test.com/plugins/testplugin/url', payload));
-        assert.strictEqual(r, response);
-      });
+    test('plugin.panel is deprecated', () => {
+      plugin.panel('rubbish');
+      assert.isTrue(console.error.called);
     });
 
-    test('delete works', () => {
-      const response = {status: 204};
-      sendStub.returns(Promise.resolve(response));
-      return plugin.delete('/url', r => {
-        assert.isTrue(sendStub.calledWithExactly(
-            'DELETE', 'http://test.com/plugins/testplugin/url'));
-        assert.strictEqual(r, response);
-      });
-    });
-
-    test('delete fails', () => {
-      sendStub.returns(Promise.resolve(
-          {status: 400, text() { return Promise.resolve('text'); }}));
-      return plugin.delete('/url', r => {
-        throw new Error('Should not resolve');
-      }).catch(err => {
-        assert.isTrue(sendStub.calledWith(
-            'DELETE', 'http://test.com/plugins/testplugin/url'));
-        assert.equal('text', err.message);
-      });
-    });
-
-    test('history event', done => {
-      plugin.on(element.EventType.HISTORY, throwErrFn);
-      plugin.on(element.EventType.HISTORY, path => {
-        assert.equal(path, '/path/to/awesomesauce');
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleEvent(element.EventType.HISTORY,
-          {path: '/path/to/awesomesauce'});
-    });
-
-    test('showchange event', done => {
-      const testChange = {
-        _number: 42,
-        revisions: {def: {_number: 2}, abc: {_number: 1}},
-      };
-      const expectedChange = Object.assign({mergeable: false}, testChange);
-      plugin.on(element.EventType.SHOW_CHANGE, throwErrFn);
-      plugin.on(element.EventType.SHOW_CHANGE, (change, revision, info) => {
-        assert.deepEqual(change, expectedChange);
-        assert.deepEqual(revision, testChange.revisions.abc);
-        assert.deepEqual(info, {mergeable: false});
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleEvent(element.EventType.SHOW_CHANGE,
-          {change: testChange, patchNum: 1, info: {mergeable: false}});
-    });
-
-    test('show-revision-actions event', done => {
-      const testChange = {
-        _number: 42,
-        revisions: {def: {_number: 2}, abc: {_number: 1}},
-      };
-      plugin.on(element.EventType.SHOW_REVISION_ACTIONS, throwErrFn);
-      plugin.on(element.EventType.SHOW_REVISION_ACTIONS, (actions, change) => {
-        assert.deepEqual(change, testChange);
-        assert.deepEqual(actions, {test: {}});
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleEvent(element.EventType.SHOW_REVISION_ACTIONS,
-          {change: testChange, revisionActions: {test: {}}});
-    });
-
-    test('handleEvent awaits plugins load', done => {
-      const testChange = {
-        _number: 42,
-        revisions: {def: {_number: 2}, abc: {_number: 1}},
-      };
-      const spy = sandbox.spy();
-      Gerrit._loadPlugins(['plugins/test.html']);
-      plugin.on(element.EventType.SHOW_CHANGE, spy);
-      element.handleEvent(element.EventType.SHOW_CHANGE,
-          {change: testChange, patchNum: 1});
-      assert.isFalse(spy.called);
-
-      // Timeout on loading plugins
-      window.clock.tick(PLUGIN_LOADING_TIMEOUT_MS * 2);
-
-      flush(() => {
-        assert.isTrue(spy.called);
-        done();
-      });
-    });
-
-    test('comment event', done => {
-      const testCommentNode = {foo: 'bar'};
-      plugin.on(element.EventType.COMMENT, throwErrFn);
-      plugin.on(element.EventType.COMMENT, commentNode => {
-        assert.deepEqual(commentNode, testCommentNode);
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleEvent(element.EventType.COMMENT, {node: testCommentNode});
-    });
-
-    test('revert event', () => {
-      function appendToRevertMsg(c, revertMsg, originalMsg) {
-        return revertMsg + '\n' + originalMsg.replace(/^/gm, '> ') + '\ninfo';
-      }
-
-      assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'), 'test');
-      assert.equal(errorStub.callCount, 0);
-
-      plugin.on(element.EventType.REVERT, throwErrFn);
-      plugin.on(element.EventType.REVERT, appendToRevertMsg);
-      assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
-          'test\n> origTest\ninfo');
-      assert.isTrue(errorStub.calledOnce);
-
-      plugin.on(element.EventType.REVERT, appendToRevertMsg);
-      assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
-          'test\n> origTest\ninfo\n> origTest\ninfo');
-      assert.isTrue(errorStub.calledTwice);
-    });
-
-    test('postrevert event', () => {
-      function getLabels(c) {
-        return {'Code-Review': 1};
-      }
-
-      assert.deepEqual(element.getLabelValuesPostRevert(null), {});
-      assert.equal(errorStub.callCount, 0);
-
-      plugin.on(element.EventType.POST_REVERT, throwErrFn);
-      plugin.on(element.EventType.POST_REVERT, getLabels);
-      assert.deepEqual(
-          element.getLabelValuesPostRevert(null), {'Code-Review': 1});
-      assert.isTrue(errorStub.calledOnce);
-    });
-
-    test('commitmsgedit event', done => {
-      const testMsg = 'Test CL commit message';
-      plugin.on(element.EventType.COMMIT_MSG_EDIT, throwErrFn);
-      plugin.on(element.EventType.COMMIT_MSG_EDIT, (change, msg) => {
-        assert.deepEqual(msg, testMsg);
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleCommitMessage(null, testMsg);
-    });
-
-    test('labelchange event', done => {
-      const testChange = {_number: 42};
-      plugin.on(element.EventType.LABEL_CHANGE, throwErrFn);
-      plugin.on(element.EventType.LABEL_CHANGE, change => {
-        assert.deepEqual(change, testChange);
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleEvent(element.EventType.LABEL_CHANGE, {change: testChange});
-    });
-
-    test('submitchange', () => {
-      plugin.on(element.EventType.SUBMIT_CHANGE, throwErrFn);
-      plugin.on(element.EventType.SUBMIT_CHANGE, () => true);
-      assert.isTrue(element.canSubmitChange());
-      assert.isTrue(errorStub.calledOnce);
-      plugin.on(element.EventType.SUBMIT_CHANGE, () => false);
-      plugin.on(element.EventType.SUBMIT_CHANGE, () => true);
-      assert.isFalse(element.canSubmitChange());
-      assert.isTrue(errorStub.calledTwice);
-    });
-
-    test('highlightjs-loaded event', done => {
-      const testHljs = {_number: 42};
-      plugin.on(element.EventType.HIGHLIGHTJS_LOADED, throwErrFn);
-      plugin.on(element.EventType.HIGHLIGHTJS_LOADED, hljs => {
-        assert.deepEqual(hljs, testHljs);
-        assert.isTrue(errorStub.calledOnce);
-        done();
-      });
-      element.handleEvent(element.EventType.HIGHLIGHTJS_LOADED, {hljs: testHljs});
-    });
-
-    test('getLoggedIn', done => {
-      // fake fetch for authCheck
-      sandbox.stub(window, 'fetch', () => Promise.resolve({status: 204}));
-      plugin.restApi().getLoggedIn()
-          .then(loggedIn => {
-            assert.isTrue(loggedIn);
-            done();
-          });
-    });
-
-    test('attributeHelper', () => {
-      assert.isOk(plugin.attributeHelper());
-    });
-
-    test('deprecated.install', () => {
-      plugin.deprecated.install();
-      assert.strictEqual(plugin.popup, plugin.deprecated.popup);
-      assert.strictEqual(plugin.onAction, plugin.deprecated.onAction);
-      assert.notStrictEqual(plugin.install, plugin.deprecated.install);
-    });
-
-    test('getAdminMenuLinks', () => {
-      const links = [{text: 'a', url: 'b'}, {text: 'c', url: 'd'}];
-      const getCallbacksStub = sandbox.stub(element, '_getEventCallbacks')
-          .returns([
-            {getMenuLinks: () => [links[0]]},
-            {getMenuLinks: () => [links[1]]},
-          ]);
-      const result = element.getAdminMenuLinks();
-      assert.deepEqual(result, links);
-      assert.isTrue(getCallbacksStub.calledOnce);
-      assert.equal(getCallbacksStub.lastCall.args[0],
-          element.EventType.ADMIN_MENU_LINKS);
-    });
-
-    suite('test plugin with base url', () => {
-      let baseUrlPlugin;
-
-      setup(() => {
-        sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl').returns('/r');
-
-        Gerrit.install(p => { baseUrlPlugin = p; }, '0.1',
-            'http://test.com/r/plugins/baseurlplugin/static/test.js');
-      });
-
-      test('url', () => {
-        assert.notEqual(baseUrlPlugin.url(),
-            'http://test.com/plugins/baseurlplugin/');
-        assert.equal(baseUrlPlugin.url(),
-            'http://test.com/r/plugins/baseurlplugin/');
-        assert.equal(baseUrlPlugin.url('/static/test.js'),
-            'http://test.com/r/plugins/baseurlplugin/static/test.js');
-      });
-    });
-
-    suite('popup', () => {
-      test('popup(element) is deprecated', () => {
-        plugin.popup(document.createElement('div'));
-        assert.isTrue(console.error.calledOnce);
-      });
-
-      test('popup(moduleName) creates popup with component', () => {
-        const openStub = sandbox.stub();
-        sandbox.stub(window, 'GrPopupInterface').returns({
-          open: openStub,
-        });
-        plugin.popup('some-name');
-        assert.isTrue(openStub.calledOnce);
-        assert.isTrue(GrPopupInterface.calledWith(plugin, 'some-name'));
-      });
-
-      test('deprecated.popup(element) creates popup with element', () => {
-        const el = document.createElement('div');
-        el.textContent = 'some text here';
-        const openStub = sandbox.stub(GrPopupInterface.prototype, 'open');
-        openStub.returns(Promise.resolve({
-          _getElement() {
-            return document.createElement('div');
-          }}));
-        plugin.deprecated.popup(el);
-        assert.isTrue(openStub.calledOnce);
-      });
-    });
-
-    suite('onAction', () => {
-      let change;
-      let revision;
-      let actionDetails;
-
-      setup(() => {
-        change = {};
-        revision = {};
-        actionDetails = {__key: 'some'};
-        sandbox.stub(plugin, 'on').callsArgWith(1, change, revision);
-        sandbox.stub(plugin, 'changeActions').returns({
-          addTapListener: sandbox.stub().callsArg(1),
-          getActionDetails: () => actionDetails,
-        });
-      });
-
-      test('returns GrPluginActionContext', () => {
-        const stub = sandbox.stub();
-        plugin.deprecated.onAction('change', 'foo', ctx => {
-          assert.isTrue(ctx instanceof GrPluginActionContext);
-          assert.strictEqual(ctx.change, change);
-          assert.strictEqual(ctx.revision, revision);
-          assert.strictEqual(ctx.action, actionDetails);
-          assert.strictEqual(ctx.plugin, plugin);
-          stub();
-        });
-        assert.isTrue(stub.called);
-      });
-
-      test('other actions', () => {
-        const stub = sandbox.stub();
-        plugin.deprecated.onAction('project', 'foo', stub);
-        plugin.deprecated.onAction('edit', 'foo', stub);
-        plugin.deprecated.onAction('branch', 'foo', stub);
-        assert.isFalse(stub.called);
-      });
-    });
-
-    suite('screen', () => {
-      test('screenUrl()', () => {
-        sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl').returns('/base');
-        assert.equal(plugin.screenUrl(), 'http://test.com/base/x/testplugin');
-        assert.equal(
-            plugin.screenUrl('foo'), 'http://test.com/base/x/testplugin/foo');
-      });
-
-      test('deprecated works', () => {
-        const stub = sandbox.stub();
-        const hookStub = {onAttached: sandbox.stub()};
-        sandbox.stub(plugin, 'hook').returns(hookStub);
-        plugin.deprecated.screen('foo', stub);
-        assert.isTrue(plugin.hook.calledWith('testplugin-screen-foo'));
-        const fakeEl = {style: {display: ''}};
-        hookStub.onAttached.callArgWith(0, fakeEl);
-        assert.isTrue(stub.called);
-        assert.equal(fakeEl.style.display, 'none');
-      });
-
-      test('works', () => {
-        sandbox.stub(plugin, 'registerCustomComponent');
-        plugin.screen('foo', 'some-module');
-        assert.isTrue(plugin.registerCustomComponent.calledWith(
-            'testplugin-screen-foo', 'some-module'));
-      });
-    });
-
-    suite('panel', () => {
-      let fakeEl;
-      let emulateAttached;
-
-      setup(()=> {
-        fakeEl = {change: {}, revision: {}};
-        const hookStub = {onAttached: sandbox.stub()};
-        sandbox.stub(plugin, 'hook').returns(hookStub);
-        emulateAttached = () => hookStub.onAttached.callArgWith(0, fakeEl);
-      });
-
-      test('plugin.panel is deprecated', () => {
-        plugin.panel('rubbish');
-        assert.isTrue(console.error.called);
-      });
-
-      [
-        ['CHANGE_SCREEN_BELOW_COMMIT_INFO_BLOCK', 'change-view-integration'],
-        ['CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK', 'change-metadata-item'],
-      ].forEach(([panelName, endpointName]) => {
-        test(`deprecated.panel works for ${panelName}`, () => {
-          const callback = sandbox.stub();
-          plugin.deprecated.panel(panelName, callback);
-          assert.isTrue(plugin.hook.calledWith(endpointName));
-          emulateAttached();
-          assert.isTrue(callback.called);
-          const args = callback.args[0][0];
-          assert.strictEqual(args.body, fakeEl);
-          assert.strictEqual(args.p.CHANGE_INFO, fakeEl.change);
-          assert.strictEqual(args.p.REVISION_INFO, fakeEl.revision);
-        });
-      });
-    });
-
-    suite('settingsScreen', () => {
-      test('plugin.settingsScreen is deprecated', () => {
-        plugin.settingsScreen('rubbish');
-        assert.isTrue(console.error.called);
-      });
-
-      test('plugin.settings() returns GrSettingsApi', () => {
-        assert.isOk(plugin.settings());
-        assert.isTrue(plugin.settings() instanceof GrSettingsApi);
-      });
-
-      test('plugin.deprecated.settingsScreen() works', () => {
-        const hookStub = {onAttached: sandbox.stub()};
-        sandbox.stub(plugin, 'hook').returns(hookStub);
-        const fakeSettings = {};
-        fakeSettings.title = sandbox.stub().returns(fakeSettings);
-        fakeSettings.token = sandbox.stub().returns(fakeSettings);
-        fakeSettings.module = sandbox.stub().returns(fakeSettings);
-        fakeSettings.build = sandbox.stub().returns(hookStub);
-        sandbox.stub(plugin, 'settings').returns(fakeSettings);
+    [
+      ['CHANGE_SCREEN_BELOW_COMMIT_INFO_BLOCK', 'change-view-integration'],
+      ['CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK', 'change-metadata-item'],
+    ].forEach(([panelName, endpointName]) => {
+      test(`deprecated.panel works for ${panelName}`, () => {
         const callback = sandbox.stub();
-
-        plugin.deprecated.settingsScreen('path', 'menu', callback);
-        assert.isTrue(fakeSettings.title.calledWith('menu'));
-        assert.isTrue(fakeSettings.token.calledWith('path'));
-        assert.isTrue(fakeSettings.module.calledWith('div'));
-        assert.equal(fakeSettings.build.callCount, 1);
-
-        const fakeBody = {};
-        const fakeEl = {
-          style: {
-            display: '',
-          },
-          querySelector: sandbox.stub().returns(fakeBody),
-        };
-        // Emulate settings screen attached
-        hookStub.onAttached.callArgWith(0, fakeEl);
+        plugin.deprecated.panel(panelName, callback);
+        assert.isTrue(plugin.hook.calledWith(endpointName));
+        emulateAttached();
         assert.isTrue(callback.called);
         const args = callback.args[0][0];
-        assert.strictEqual(args.body, fakeBody);
-        assert.equal(fakeEl.style.display, 'none');
+        assert.strictEqual(args.body, fakeEl);
+        assert.strictEqual(args.p.CHANGE_INFO, fakeEl.change);
+        assert.strictEqual(args.p.REVISION_INFO, fakeEl.revision);
       });
     });
   });
+
+  suite('settingsScreen', () => {
+    test('plugin.settingsScreen is deprecated', () => {
+      plugin.settingsScreen('rubbish');
+      assert.isTrue(console.error.called);
+    });
+
+    test('plugin.settings() returns GrSettingsApi', () => {
+      assert.isOk(plugin.settings());
+      assert.isTrue(plugin.settings() instanceof GrSettingsApi);
+    });
+
+    test('plugin.deprecated.settingsScreen() works', () => {
+      const hookStub = {onAttached: sandbox.stub()};
+      sandbox.stub(plugin, 'hook').returns(hookStub);
+      const fakeSettings = {};
+      fakeSettings.title = sandbox.stub().returns(fakeSettings);
+      fakeSettings.token = sandbox.stub().returns(fakeSettings);
+      fakeSettings.module = sandbox.stub().returns(fakeSettings);
+      fakeSettings.build = sandbox.stub().returns(hookStub);
+      sandbox.stub(plugin, 'settings').returns(fakeSettings);
+      const callback = sandbox.stub();
+
+      plugin.deprecated.settingsScreen('path', 'menu', callback);
+      assert.isTrue(fakeSettings.title.calledWith('menu'));
+      assert.isTrue(fakeSettings.token.calledWith('path'));
+      assert.isTrue(fakeSettings.module.calledWith('div'));
+      assert.equal(fakeSettings.build.callCount, 1);
+
+      const fakeBody = {};
+      const fakeEl = {
+        style: {
+          display: '',
+        },
+        querySelector: sandbox.stub().returns(fakeBody),
+      };
+      // Emulate settings screen attached
+      hookStub.onAttached.callArgWith(0, fakeEl);
+      assert.isTrue(callback.called);
+      const args = callback.args[0][0];
+      assert.strictEqual(args.body, fakeBody);
+      assert.equal(fakeEl.style.display, 'none');
+    });
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
index c8fb9b1..3ba2acc 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
@@ -19,15 +19,20 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-plugin-action-context</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html"/>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -35,126 +40,129 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-plugin-action-context tests', async () => {
-    await readyToTest();
-    let instance;
-    let sandbox;
-    let plugin;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+suite('gr-plugin-action-context tests', () => {
+  let instance;
+  let sandbox;
+  let plugin;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-      instance = new GrPluginActionContext(plugin);
-    });
+  setup(() => {
+    sandbox = sinon.sandbox.create();
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
+    instance = new GrPluginActionContext(plugin);
+  });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+  teardown(() => {
+    sandbox.restore();
+  });
 
-    test('popup() and hide()', () => {
-      const popupApiStub = {
-        close: sandbox.stub(),
-      };
-      sandbox.stub(plugin.deprecated, 'popup').returns(popupApiStub);
-      const el = {};
-      instance.popup(el);
-      assert.isTrue(instance.plugin.deprecated.popup.calledWith(el));
+  test('popup() and hide()', () => {
+    const popupApiStub = {
+      close: sandbox.stub(),
+    };
+    sandbox.stub(plugin.deprecated, 'popup').returns(popupApiStub);
+    const el = {};
+    instance.popup(el);
+    assert.isTrue(instance.plugin.deprecated.popup.calledWith(el));
 
-      instance.hide();
-      assert.isTrue(popupApiStub.close.called);
-    });
+    instance.hide();
+    assert.isTrue(popupApiStub.close.called);
+  });
 
-    test('textfield', () => {
-      assert.equal(instance.textfield().tagName, 'PAPER-INPUT');
-    });
+  test('textfield', () => {
+    assert.equal(instance.textfield().tagName, 'PAPER-INPUT');
+  });
 
-    test('br', () => {
-      assert.equal(instance.br().tagName, 'BR');
-    });
+  test('br', () => {
+    assert.equal(instance.br().tagName, 'BR');
+  });
 
-    test('msg', () => {
-      const el = instance.msg('foobar');
-      assert.equal(el.tagName, 'GR-LABEL');
-      assert.equal(el.textContent, 'foobar');
-    });
+  test('msg', () => {
+    const el = instance.msg('foobar');
+    assert.equal(el.tagName, 'GR-LABEL');
+    assert.equal(el.textContent, 'foobar');
+  });
 
-    test('div', () => {
-      const el1 = document.createElement('span');
-      el1.textContent = 'foo';
-      const el2 = document.createElement('div');
-      el2.textContent = 'bar';
-      const div = instance.div(el1, el2);
-      assert.equal(div.tagName, 'DIV');
-      assert.equal(div.textContent, 'foobar');
-    });
+  test('div', () => {
+    const el1 = document.createElement('span');
+    el1.textContent = 'foo';
+    const el2 = document.createElement('div');
+    el2.textContent = 'bar';
+    const div = instance.div(el1, el2);
+    assert.equal(div.tagName, 'DIV');
+    assert.equal(div.textContent, 'foobar');
+  });
 
-    test('button', done => {
-      const clickStub = sandbox.stub();
-      const button = instance.button('foo', {onclick: clickStub});
-      // If you don't attach a Polymer element to the DOM, then the ready()
-      // callback will not be called and then e.g. this.$ is undefined.
-      Polymer.dom(document.body).appendChild(button);
-      MockInteractions.tap(button);
-      flush(() => {
-        assert.isTrue(clickStub.called);
-        assert.equal(button.textContent, 'foo');
-        done();
-      });
-    });
-
-    test('checkbox', () => {
-      const el = instance.checkbox();
-      assert.equal(el.tagName, 'INPUT');
-      assert.equal(el.type, 'checkbox');
-    });
-
-    test('label', () => {
-      const fakeMsg = {};
-      const fakeCheckbox = {};
-      sandbox.stub(instance, 'div');
-      sandbox.stub(instance, 'msg').returns(fakeMsg);
-      instance.label(fakeCheckbox, 'foo');
-      assert.isTrue(instance.div.calledWithExactly(fakeCheckbox, fakeMsg));
-    });
-
-    test('call', () => {
-      instance.action = {
-        method: 'METHOD',
-        __key: 'key',
-        __url: '/changes/1/revisions/2/foo~bar',
-      };
-      const sendStub = sandbox.stub().returns(Promise.resolve());
-      sandbox.stub(plugin, 'restApi').returns({
-        send: sendStub,
-      });
-      const payload = {foo: 'foo'};
-      const successStub = sandbox.stub();
-      instance.call(payload, successStub);
-      assert.isTrue(sendStub.calledWith(
-          'METHOD', '/changes/1/revisions/2/foo~bar', payload));
-    });
-
-    test('call error', done => {
-      instance.action = {
-        method: 'METHOD',
-        __key: 'key',
-        __url: '/changes/1/revisions/2/foo~bar',
-      };
-      const sendStub = sandbox.stub().returns(Promise.reject(new Error('boom')));
-      sandbox.stub(plugin, 'restApi').returns({
-        send: sendStub,
-      });
-      const errorStub = sandbox.stub();
-      document.addEventListener('show-alert', errorStub);
-      instance.call();
-      flush(() => {
-        assert.isTrue(errorStub.calledOnce);
-        assert.equal(errorStub.args[0][0].detail.message,
-            'Plugin network error: Error: boom');
-        done();
-      });
+  test('button', done => {
+    const clickStub = sandbox.stub();
+    const button = instance.button('foo', {onclick: clickStub});
+    // If you don't attach a Polymer element to the DOM, then the ready()
+    // callback will not be called and then e.g. this.$ is undefined.
+    dom(document.body).appendChild(button);
+    MockInteractions.tap(button);
+    flush(() => {
+      assert.isTrue(clickStub.called);
+      assert.equal(button.textContent, 'foo');
+      done();
     });
   });
+
+  test('checkbox', () => {
+    const el = instance.checkbox();
+    assert.equal(el.tagName, 'INPUT');
+    assert.equal(el.type, 'checkbox');
+  });
+
+  test('label', () => {
+    const fakeMsg = {};
+    const fakeCheckbox = {};
+    sandbox.stub(instance, 'div');
+    sandbox.stub(instance, 'msg').returns(fakeMsg);
+    instance.label(fakeCheckbox, 'foo');
+    assert.isTrue(instance.div.calledWithExactly(fakeCheckbox, fakeMsg));
+  });
+
+  test('call', () => {
+    instance.action = {
+      method: 'METHOD',
+      __key: 'key',
+      __url: '/changes/1/revisions/2/foo~bar',
+    };
+    const sendStub = sandbox.stub().returns(Promise.resolve());
+    sandbox.stub(plugin, 'restApi').returns({
+      send: sendStub,
+    });
+    const payload = {foo: 'foo'};
+    const successStub = sandbox.stub();
+    instance.call(payload, successStub);
+    assert.isTrue(sendStub.calledWith(
+        'METHOD', '/changes/1/revisions/2/foo~bar', payload));
+  });
+
+  test('call error', done => {
+    instance.action = {
+      method: 'METHOD',
+      __key: 'key',
+      __url: '/changes/1/revisions/2/foo~bar',
+    };
+    const sendStub = sandbox.stub().returns(Promise.reject(new Error('boom')));
+    sandbox.stub(plugin, 'restApi').returns({
+      send: sendStub,
+    });
+    const errorStub = sandbox.stub();
+    document.addEventListener('show-alert', errorStub);
+    instance.call();
+    flush(() => {
+      assert.isTrue(errorStub.calledOnce);
+      assert.equal(errorStub.args[0][0].detail.message,
+          'Plugin network error: Error: boom');
+      done();
+    });
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
index 5c0d69a..94bb771 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
@@ -19,132 +19,139 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-plugin-endpoints</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html"/>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
-<script>
-  suite('gr-plugin-endpoints tests', async () => {
-    await readyToTest();
-    let sandbox;
-    let instance;
-    let pluginFoo;
-    let pluginBar;
-    let domHook;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+suite('gr-plugin-endpoints tests', () => {
+  let sandbox;
+  let instance;
+  let pluginFoo;
+  let pluginBar;
+  let domHook;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      domHook = {};
-      instance = new GrPluginEndpoints();
-      Gerrit.install(p => { pluginFoo = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/foo.html');
-      instance.registerModule(
-          pluginFoo, 'a-place', 'decorate', 'foo-module', domHook);
-      Gerrit.install(p => { pluginBar = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/bar.html');
-      instance.registerModule(
-          pluginBar, 'a-place', 'style', 'bar-module', domHook);
-      sandbox.stub(Gerrit, '_arePluginsLoaded').returns(true);
-    });
+  setup(() => {
+    sandbox = sinon.sandbox.create();
+    domHook = {};
+    instance = new GrPluginEndpoints();
+    Gerrit.install(p => { pluginFoo = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/foo.html');
+    instance.registerModule(
+        pluginFoo, 'a-place', 'decorate', 'foo-module', domHook);
+    Gerrit.install(p => { pluginBar = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/bar.html');
+    instance.registerModule(
+        pluginBar, 'a-place', 'style', 'bar-module', domHook);
+    sandbox.stub(Gerrit, '_arePluginsLoaded').returns(true);
+  });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+  teardown(() => {
+    sandbox.restore();
+  });
 
-    test('getDetails all', () => {
-      assert.deepEqual(instance.getDetails('a-place'), [
-        {
-          moduleName: 'foo-module',
-          plugin: pluginFoo,
-          pluginUrl: pluginFoo._url,
-          type: 'decorate',
-          domHook,
-        },
-        {
-          moduleName: 'bar-module',
-          plugin: pluginBar,
-          pluginUrl: pluginBar._url,
-          type: 'style',
-          domHook,
-        },
-      ]);
-    });
-
-    test('getDetails by type', () => {
-      assert.deepEqual(instance.getDetails('a-place', {type: 'style'}), [
-        {
-          moduleName: 'bar-module',
-          plugin: pluginBar,
-          pluginUrl: pluginBar._url,
-          type: 'style',
-          domHook,
-        },
-      ]);
-    });
-
-    test('getDetails by module', () => {
-      assert.deepEqual(
-          instance.getDetails('a-place', {moduleName: 'foo-module'}),
-          [
-            {
-              moduleName: 'foo-module',
-              plugin: pluginFoo,
-              pluginUrl: pluginFoo._url,
-              type: 'decorate',
-              domHook,
-            },
-          ]);
-    });
-
-    test('getModules', () => {
-      assert.deepEqual(
-          instance.getModules('a-place'), ['foo-module', 'bar-module']);
-    });
-
-    test('getPlugins', () => {
-      assert.deepEqual(
-          instance.getPlugins('a-place'), [pluginFoo._url]);
-    });
-
-    test('onNewEndpoint', () => {
-      const newModuleStub = sandbox.stub();
-      instance.onNewEndpoint('a-place', newModuleStub);
-      instance.registerModule(
-          pluginFoo, 'a-place', 'replace', 'zaz-module', domHook);
-      assert.deepEqual(newModuleStub.lastCall.args[0], {
-        moduleName: 'zaz-module',
+  test('getDetails all', () => {
+    assert.deepEqual(instance.getDetails('a-place'), [
+      {
+        moduleName: 'foo-module',
         plugin: pluginFoo,
         pluginUrl: pluginFoo._url,
-        type: 'replace',
+        type: 'decorate',
         domHook,
-      });
-    });
+      },
+      {
+        moduleName: 'bar-module',
+        plugin: pluginBar,
+        pluginUrl: pluginBar._url,
+        type: 'style',
+        domHook,
+      },
+    ]);
+  });
 
-    test('reuse dom hooks', () => {
-      instance.registerModule(
-          pluginFoo, 'a-place', 'decorate', 'foo-module', domHook);
-      assert.deepEqual(instance.getDetails('a-place'), [
-        {
-          moduleName: 'foo-module',
-          plugin: pluginFoo,
-          pluginUrl: pluginFoo._url,
-          type: 'decorate',
-          domHook,
-        },
-        {
-          moduleName: 'bar-module',
-          plugin: pluginBar,
-          pluginUrl: pluginBar._url,
-          type: 'style',
-          domHook,
-        },
-      ]);
+  test('getDetails by type', () => {
+    assert.deepEqual(instance.getDetails('a-place', {type: 'style'}), [
+      {
+        moduleName: 'bar-module',
+        plugin: pluginBar,
+        pluginUrl: pluginBar._url,
+        type: 'style',
+        domHook,
+      },
+    ]);
+  });
+
+  test('getDetails by module', () => {
+    assert.deepEqual(
+        instance.getDetails('a-place', {moduleName: 'foo-module'}),
+        [
+          {
+            moduleName: 'foo-module',
+            plugin: pluginFoo,
+            pluginUrl: pluginFoo._url,
+            type: 'decorate',
+            domHook,
+          },
+        ]);
+  });
+
+  test('getModules', () => {
+    assert.deepEqual(
+        instance.getModules('a-place'), ['foo-module', 'bar-module']);
+  });
+
+  test('getPlugins', () => {
+    assert.deepEqual(
+        instance.getPlugins('a-place'), [pluginFoo._url]);
+  });
+
+  test('onNewEndpoint', () => {
+    const newModuleStub = sandbox.stub();
+    instance.onNewEndpoint('a-place', newModuleStub);
+    instance.registerModule(
+        pluginFoo, 'a-place', 'replace', 'zaz-module', domHook);
+    assert.deepEqual(newModuleStub.lastCall.args[0], {
+      moduleName: 'zaz-module',
+      plugin: pluginFoo,
+      pluginUrl: pluginFoo._url,
+      type: 'replace',
+      domHook,
     });
   });
+
+  test('reuse dom hooks', () => {
+    instance.registerModule(
+        pluginFoo, 'a-place', 'decorate', 'foo-module', domHook);
+    assert.deepEqual(instance.getDetails('a-place'), [
+      {
+        moduleName: 'foo-module',
+        plugin: pluginFoo,
+        pluginUrl: pluginFoo._url,
+        type: 'decorate',
+        domHook,
+      },
+      {
+        moduleName: 'bar-module',
+        plugin: pluginBar,
+        pluginUrl: pluginBar._url,
+        type: 'style',
+        domHook,
+      },
+    ]);
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
index 1a9174f..46914dc 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
@@ -19,15 +19,20 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-plugin-host</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html">
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>void(0);</script>
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+void(0);
+</script>
 
 <test-fixture id="basic">
   <template>
@@ -35,531 +40,533 @@
   </template>
 </test-fixture>
 
-<script>
-  suite('gr-plugin-loader tests', async () => {
-    await readyToTest();
-    const {PRELOADED_PROTOCOL, PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
-    let plugin;
-    let sandbox;
-    let url;
-    let sendStub;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+suite('gr-plugin-loader tests', () => {
+  const {PRELOADED_PROTOCOL, PLUGIN_LOADING_TIMEOUT_MS} = window._apiUtils;
+  let plugin;
+  let sandbox;
+  let url;
+  let sendStub;
 
+  setup(() => {
+    window.clock = sinon.useFakeTimers();
+    sandbox = sinon.sandbox.create();
+    sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
+    stub('gr-rest-api-interface', {
+      getAccount() {
+        return Promise.resolve({name: 'Judy Hopps'});
+      },
+      send(...args) {
+        return sendStub(...args);
+      },
+    });
+    sandbox.stub(document.body, 'appendChild');
+    fixture('basic');
+    url = window.location.origin;
+  });
+
+  teardown(() => {
+    sandbox.restore();
+    window.clock.restore();
+    Gerrit._testOnly_resetPlugins();
+  });
+
+  test('reuse plugin for install calls', () => {
+    Gerrit.install(p => { plugin = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
+
+    let otherPlugin;
+    Gerrit.install(p => { otherPlugin = p; }, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
+    assert.strictEqual(plugin, otherPlugin);
+  });
+
+  test('flushes preinstalls if provided', () => {
+    assert.doesNotThrow(() => {
+      Gerrit._testOnly_flushPreinstalls();
+    });
+    window.Gerrit.flushPreinstalls = sandbox.stub();
+    Gerrit._testOnly_flushPreinstalls();
+    assert.isTrue(window.Gerrit.flushPreinstalls.calledOnce);
+    delete window.Gerrit.flushPreinstalls;
+  });
+
+  test('versioning', () => {
+    const callback = sandbox.spy();
+    Gerrit.install(callback, '0.0pre-alpha');
+    assert(callback.notCalled);
+  });
+
+  test('report pluginsLoaded', done => {
+    stub('gr-reporting', {
+      pluginsLoaded() {
+        done();
+      },
+    });
+    Gerrit._loadPlugins([]);
+  });
+
+  test('arePluginsLoaded', done => {
+    assert.isFalse(Gerrit._arePluginsLoaded());
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+
+    Gerrit._loadPlugins(plugins);
+    assert.isFalse(Gerrit._arePluginsLoaded());
+    // Timeout on loading plugins
+    window.clock.tick(PLUGIN_LOADING_TIMEOUT_MS * 2);
+
+    flush(() => {
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      done();
+    });
+  });
+
+  test('plugins installed successfully', done => {
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => void 0, undefined, url);
+    });
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+    Gerrit._loadPlugins(plugins);
+
+    flush(() => {
+      assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo', 'bar']));
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      done();
+    });
+  });
+
+  test('isPluginEnabled and isPluginLoaded', done => {
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => void 0, undefined, url);
+    });
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+      'bar/static/test.js',
+    ];
+    Gerrit._loadPlugins(plugins);
+    assert.isTrue(
+        plugins.every(plugin => Gerrit._pluginLoader.isPluginEnabled(plugin))
+    );
+
+    flush(() => {
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      assert.isTrue(
+          plugins.every(plugin => Gerrit._pluginLoader.isPluginLoaded(plugin))
+      );
+
+      done();
+    });
+  });
+
+  test('plugins installed mixed result, 1 fail 1 succeed', done => {
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+
+    const alertStub = sandbox.stub();
+    document.addEventListener('show-alert', alertStub);
+
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => {
+        if (url === plugins[0]) {
+          throw new Error('failed');
+        }
+      }, undefined, url);
+    });
+
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    Gerrit._loadPlugins(plugins);
+
+    flush(() => {
+      assert.isTrue(pluginsLoadedStub.calledWithExactly(['bar']));
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      assert.isTrue(alertStub.calledOnce);
+      done();
+    });
+  });
+
+  test('isPluginEnabled and isPluginLoaded for mixed results', done => {
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+
+    const alertStub = sandbox.stub();
+    document.addEventListener('show-alert', alertStub);
+
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => {
+        if (url === plugins[0]) {
+          throw new Error('failed');
+        }
+      }, undefined, url);
+    });
+
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    Gerrit._loadPlugins(plugins);
+    assert.isTrue(
+        plugins.every(plugin => Gerrit._pluginLoader.isPluginEnabled(plugin))
+    );
+
+    flush(() => {
+      assert.isTrue(pluginsLoadedStub.calledWithExactly(['bar']));
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      assert.isTrue(alertStub.calledOnce);
+      assert.isTrue(Gerrit._pluginLoader.isPluginLoaded(plugins[1]));
+      assert.isFalse(Gerrit._pluginLoader.isPluginLoaded(plugins[0]));
+      done();
+    });
+  });
+
+  test('plugins installed all failed', done => {
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+
+    const alertStub = sandbox.stub();
+    document.addEventListener('show-alert', alertStub);
+
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => {
+        throw new Error('failed');
+      }, undefined, url);
+    });
+
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    Gerrit._loadPlugins(plugins);
+
+    flush(() => {
+      assert.isTrue(pluginsLoadedStub.calledWithExactly([]));
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      assert.isTrue(alertStub.calledTwice);
+      done();
+    });
+  });
+
+  test('plugins installed failed becasue of wrong version', done => {
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+
+    const alertStub = sandbox.stub();
+    document.addEventListener('show-alert', alertStub);
+
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => {
+      }, url === plugins[0] ? '' : 'alpha', url);
+    });
+
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    Gerrit._loadPlugins(plugins);
+
+    flush(() => {
+      assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo']));
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      assert.isTrue(alertStub.calledOnce);
+      done();
+    });
+  });
+
+  test('multiple assets for same plugin installed successfully', done => {
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => void 0, undefined, url);
+    });
+    const pluginsLoadedStub = sandbox.stub();
+    stub('gr-reporting', {
+      pluginsLoaded: (...args) => pluginsLoadedStub(...args),
+    });
+
+    const plugins = [
+      'http://test.com/plugins/foo/static/test.js',
+      'http://test.com/plugins/foo/static/test2.js',
+      'http://test.com/plugins/bar/static/test.js',
+    ];
+    Gerrit._loadPlugins(plugins);
+
+    flush(() => {
+      assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo', 'bar']));
+      assert.isTrue(Gerrit._arePluginsLoaded());
+      done();
+    });
+  });
+
+  suite('plugin path and url', () => {
+    let importHtmlPluginStub;
+    let loadJsPluginStub;
     setup(() => {
-      window.clock = sinon.useFakeTimers();
-      sandbox = sinon.sandbox.create();
-      sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
-      stub('gr-rest-api-interface', {
-        getAccount() {
-          return Promise.resolve({name: 'Judy Hopps'});
-        },
-        send(...args) {
-          return sendStub(...args);
-        },
+      importHtmlPluginStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_loadHtmlPlugin', url => {
+        importHtmlPluginStub(url);
       });
-      sandbox.stub(document.body, 'appendChild');
-      fixture('basic');
-      url = window.location.origin;
+      loadJsPluginStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_createScriptTag', url => {
+        loadJsPluginStub(url);
+      });
+    });
+
+    test('invalid plugin path', () => {
+      const failToLoadStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_failToLoad', (...args) => {
+        failToLoadStub(...args);
+      });
+
+      Gerrit._loadPlugins([
+        'foo/bar',
+      ]);
+
+      assert.isTrue(failToLoadStub.calledOnce);
+      assert.isTrue(failToLoadStub.calledWithExactly(
+          'Unrecognized plugin path foo/bar',
+          'foo/bar'
+      ));
+    });
+
+    test('relative path for plugins', () => {
+      Gerrit._loadPlugins([
+        'foo/bar.js',
+        'foo/bar.html',
+      ]);
+
+      assert.isTrue(importHtmlPluginStub.calledOnce);
+      assert.isTrue(
+          importHtmlPluginStub.calledWithExactly(`${url}/foo/bar.html`)
+      );
+      assert.isTrue(loadJsPluginStub.calledOnce);
+      assert.isTrue(
+          loadJsPluginStub.calledWithExactly(`${url}/foo/bar.js`)
+      );
+    });
+
+    test('relative path should honor getBaseUrl', () => {
+      const testUrl = '/test';
+      sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl', () => testUrl);
+
+      Gerrit._loadPlugins([
+        'foo/bar.js',
+        'foo/bar.html',
+      ]);
+
+      assert.isTrue(importHtmlPluginStub.calledOnce);
+      assert.isTrue(loadJsPluginStub.calledOnce);
+      assert.isTrue(
+          importHtmlPluginStub.calledWithExactly(
+              `${url}${testUrl}/foo/bar.html`
+          )
+      );
+      assert.isTrue(
+          loadJsPluginStub.calledWithExactly(`${url}${testUrl}/foo/bar.js`)
+      );
+    });
+
+    test('absolute path for plugins', () => {
+      Gerrit._loadPlugins([
+        'http://e.com/foo/bar.js',
+        'http://e.com/foo/bar.html',
+      ]);
+
+      assert.isTrue(importHtmlPluginStub.calledOnce);
+      assert.isTrue(
+          importHtmlPluginStub.calledWithExactly(`http://e.com/foo/bar.html`)
+      );
+      assert.isTrue(loadJsPluginStub.calledOnce);
+      assert.isTrue(
+          loadJsPluginStub.calledWithExactly(`http://e.com/foo/bar.js`)
+      );
+    });
+  });
+
+  suite('With ASSETS_PATH', () => {
+    let importHtmlPluginStub;
+    let loadJsPluginStub;
+    setup(() => {
+      window.ASSETS_PATH = 'https://cdn.com';
+      importHtmlPluginStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_loadHtmlPlugin', url => {
+        importHtmlPluginStub(url);
+      });
+      loadJsPluginStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_createScriptTag', url => {
+        loadJsPluginStub(url);
+      });
     });
 
     teardown(() => {
-      sandbox.restore();
-      window.clock.restore();
-      Gerrit._testOnly_resetPlugins();
+      window.ASSETS_PATH = '';
     });
 
-    test('reuse plugin for install calls', () => {
-      Gerrit.install(p => { plugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-
-      let otherPlugin;
-      Gerrit.install(p => { otherPlugin = p; }, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-      assert.strictEqual(plugin, otherPlugin);
-    });
-
-    test('flushes preinstalls if provided', () => {
-      assert.doesNotThrow(() => {
-        Gerrit._testOnly_flushPreinstalls();
-      });
-      window.Gerrit.flushPreinstalls = sandbox.stub();
-      Gerrit._testOnly_flushPreinstalls();
-      assert.isTrue(window.Gerrit.flushPreinstalls.calledOnce);
-      delete window.Gerrit.flushPreinstalls;
-    });
-
-    test('versioning', () => {
-      const callback = sandbox.spy();
-      Gerrit.install(callback, '0.0pre-alpha');
-      assert(callback.notCalled);
-    });
-
-    test('report pluginsLoaded', done => {
-      stub('gr-reporting', {
-        pluginsLoaded() {
-          done();
-        },
-      });
-      Gerrit._loadPlugins([]);
-    });
-
-    test('arePluginsLoaded', done => {
-      assert.isFalse(Gerrit._arePluginsLoaded());
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-
-      Gerrit._loadPlugins(plugins);
-      assert.isFalse(Gerrit._arePluginsLoaded());
-      // Timeout on loading plugins
-      window.clock.tick(PLUGIN_LOADING_TIMEOUT_MS * 2);
-
-      flush(() => {
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        done();
-      });
-    });
-
-    test('plugins installed successfully', done => {
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => void 0, undefined, url);
-      });
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-      Gerrit._loadPlugins(plugins);
-
-      flush(() => {
-        assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo', 'bar']));
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        done();
-      });
-    });
-
-    test('isPluginEnabled and isPluginLoaded', done => {
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => void 0, undefined, url);
-      });
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-        'bar/static/test.js',
-      ];
-      Gerrit._loadPlugins(plugins);
-      assert.isTrue(
-          plugins.every(plugin => Gerrit._pluginLoader.isPluginEnabled(plugin))
-      );
-
-      flush(() => {
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        assert.isTrue(
-            plugins.every(plugin => Gerrit._pluginLoader.isPluginLoaded(plugin))
-        );
-
-        done();
-      });
-    });
-
-    test('plugins installed mixed result, 1 fail 1 succeed', done => {
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-
-      const alertStub = sandbox.stub();
-      document.addEventListener('show-alert', alertStub);
-
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => {
-          if (url === plugins[0]) {
-            throw new Error('failed');
-          }
-        }, undefined, url);
-      });
-
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      Gerrit._loadPlugins(plugins);
-
-      flush(() => {
-        assert.isTrue(pluginsLoadedStub.calledWithExactly(['bar']));
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        assert.isTrue(alertStub.calledOnce);
-        done();
-      });
-    });
-
-    test('isPluginEnabled and isPluginLoaded for mixed results', done => {
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-
-      const alertStub = sandbox.stub();
-      document.addEventListener('show-alert', alertStub);
-
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => {
-          if (url === plugins[0]) {
-            throw new Error('failed');
-          }
-        }, undefined, url);
-      });
-
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      Gerrit._loadPlugins(plugins);
-      assert.isTrue(
-          plugins.every(plugin => Gerrit._pluginLoader.isPluginEnabled(plugin))
-      );
-
-      flush(() => {
-        assert.isTrue(pluginsLoadedStub.calledWithExactly(['bar']));
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        assert.isTrue(alertStub.calledOnce);
-        assert.isTrue(Gerrit._pluginLoader.isPluginLoaded(plugins[1]));
-        assert.isFalse(Gerrit._pluginLoader.isPluginLoaded(plugins[0]));
-        done();
-      });
-    });
-
-    test('plugins installed all failed', done => {
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-
-      const alertStub = sandbox.stub();
-      document.addEventListener('show-alert', alertStub);
-
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => {
-          throw new Error('failed');
-        }, undefined, url);
-      });
-
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      Gerrit._loadPlugins(plugins);
-
-      flush(() => {
-        assert.isTrue(pluginsLoadedStub.calledWithExactly([]));
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        assert.isTrue(alertStub.calledTwice);
-        done();
-      });
-    });
-
-    test('plugins installed failed becasue of wrong version', done => {
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-
-      const alertStub = sandbox.stub();
-      document.addEventListener('show-alert', alertStub);
-
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => {
-        }, url === plugins[0] ? '' : 'alpha', url);
-      });
-
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      Gerrit._loadPlugins(plugins);
-
-      flush(() => {
-        assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo']));
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        assert.isTrue(alertStub.calledOnce);
-        done();
-      });
-    });
-
-    test('multiple assets for same plugin installed successfully', done => {
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => void 0, undefined, url);
-      });
-      const pluginsLoadedStub = sandbox.stub();
-      stub('gr-reporting', {
-        pluginsLoaded: (...args) => pluginsLoadedStub(...args),
-      });
-
-      const plugins = [
-        'http://test.com/plugins/foo/static/test.js',
-        'http://test.com/plugins/foo/static/test2.js',
-        'http://test.com/plugins/bar/static/test.js',
-      ];
-      Gerrit._loadPlugins(plugins);
-
-      flush(() => {
-        assert.isTrue(pluginsLoadedStub.calledWithExactly(['foo', 'bar']));
-        assert.isTrue(Gerrit._arePluginsLoaded());
-        done();
-      });
-    });
-
-    suite('plugin path and url', () => {
-      let importHtmlPluginStub;
-      let loadJsPluginStub;
-      setup(() => {
-        importHtmlPluginStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_loadHtmlPlugin', url => {
-          importHtmlPluginStub(url);
-        });
-        loadJsPluginStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_createScriptTag', url => {
-          loadJsPluginStub(url);
-        });
-      });
-
-      test('invalid plugin path', () => {
-        const failToLoadStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_failToLoad', (...args) => {
-          failToLoadStub(...args);
-        });
-
-        Gerrit._loadPlugins([
-          'foo/bar',
-        ]);
-
-        assert.isTrue(failToLoadStub.calledOnce);
-        assert.isTrue(failToLoadStub.calledWithExactly(
-            'Unrecognized plugin path foo/bar',
-            'foo/bar'
-        ));
-      });
-
-      test('relative path for plugins', () => {
-        Gerrit._loadPlugins([
-          'foo/bar.js',
-          'foo/bar.html',
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.calledOnce);
-        assert.isTrue(
-            importHtmlPluginStub.calledWithExactly(`${url}/foo/bar.html`)
-        );
-        assert.isTrue(loadJsPluginStub.calledOnce);
-        assert.isTrue(
-            loadJsPluginStub.calledWithExactly(`${url}/foo/bar.js`)
-        );
-      });
-
-      test('relative path should honor getBaseUrl', () => {
-        const testUrl = '/test';
-        sandbox.stub(Gerrit.BaseUrlBehavior, 'getBaseUrl', () => testUrl);
-
-        Gerrit._loadPlugins([
-          'foo/bar.js',
-          'foo/bar.html',
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.calledOnce);
-        assert.isTrue(loadJsPluginStub.calledOnce);
-        assert.isTrue(
-            importHtmlPluginStub.calledWithExactly(
-                `${url}${testUrl}/foo/bar.html`
-            )
-        );
-        assert.isTrue(
-            loadJsPluginStub.calledWithExactly(`${url}${testUrl}/foo/bar.js`)
-        );
-      });
-
-      test('absolute path for plugins', () => {
-        Gerrit._loadPlugins([
-          'http://e.com/foo/bar.js',
-          'http://e.com/foo/bar.html',
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.calledOnce);
-        assert.isTrue(
-            importHtmlPluginStub.calledWithExactly(`http://e.com/foo/bar.html`)
-        );
-        assert.isTrue(loadJsPluginStub.calledOnce);
-        assert.isTrue(
-            loadJsPluginStub.calledWithExactly(`http://e.com/foo/bar.js`)
-        );
-      });
-    });
-
-    suite('With ASSETS_PATH', () => {
-      let importHtmlPluginStub;
-      let loadJsPluginStub;
-      setup(() => {
-        window.ASSETS_PATH = 'https://cdn.com';
-        importHtmlPluginStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_loadHtmlPlugin', url => {
-          importHtmlPluginStub(url);
-        });
-        loadJsPluginStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_createScriptTag', url => {
-          loadJsPluginStub(url);
-        });
-      });
-
-      teardown(() => {
-        window.ASSETS_PATH = '';
-      });
-
-      test('Should try load plugins from assets path instead', () => {
-        Gerrit._loadPlugins([
-          'foo/bar.js',
-          'foo/bar.html',
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.calledOnce);
-        assert.isTrue(
-            importHtmlPluginStub.calledWithExactly(`https://cdn.com/foo/bar.html`)
-        );
-        assert.isTrue(loadJsPluginStub.calledOnce);
-        assert.isTrue(
-            loadJsPluginStub.calledWithExactly(`https://cdn.com/foo/bar.js`));
-      });
-
-      test('Should honor original path if exists', () => {
-        Gerrit._loadPlugins([
-          'http://e.com/foo/bar.html',
-          'http://e.com/foo/bar.js',
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.calledOnce);
-        assert.isTrue(
-            importHtmlPluginStub.calledWithExactly(`http://e.com/foo/bar.html`)
-        );
-        assert.isTrue(loadJsPluginStub.calledOnce);
-        assert.isTrue(
-            loadJsPluginStub.calledWithExactly(`http://e.com/foo/bar.js`));
-      });
-
-      test('Should try replace current host with assetsPath', () => {
-        const host = window.location.origin;
-        Gerrit._loadPlugins([
-          `${host}/foo/bar.html`,
-          `${host}/foo/bar.js`,
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.calledOnce);
-        assert.isTrue(
-            importHtmlPluginStub.calledWithExactly(`https://cdn.com/foo/bar.html`)
-        );
-        assert.isTrue(loadJsPluginStub.calledOnce);
-        assert.isTrue(
-            loadJsPluginStub.calledWithExactly(`https://cdn.com/foo/bar.js`));
-      });
-    });
-
-    test('adds js plugins will call the body', () => {
+    test('Should try load plugins from assets path instead', () => {
       Gerrit._loadPlugins([
-        'http://e.com/foo/bar.js',
-        'http://e.com/bar/foo.js',
+        'foo/bar.js',
+        'foo/bar.html',
       ]);
-      assert.isTrue(document.body.appendChild.calledTwice);
+
+      assert.isTrue(importHtmlPluginStub.calledOnce);
+      assert.isTrue(
+          importHtmlPluginStub.calledWithExactly(`https://cdn.com/foo/bar.html`)
+      );
+      assert.isTrue(loadJsPluginStub.calledOnce);
+      assert.isTrue(
+          loadJsPluginStub.calledWithExactly(`https://cdn.com/foo/bar.js`));
     });
 
-    test('can call awaitPluginsLoaded multiple times', done => {
-      const plugins = [
+    test('Should honor original path if exists', () => {
+      Gerrit._loadPlugins([
+        'http://e.com/foo/bar.html',
         'http://e.com/foo/bar.js',
-        'http://e.com/bar/foo.js',
-      ];
+      ]);
 
-      let installed = false;
-      function pluginCallback(url) {
-        if (url === plugins[1]) {
-          installed = true;
-        }
+      assert.isTrue(importHtmlPluginStub.calledOnce);
+      assert.isTrue(
+          importHtmlPluginStub.calledWithExactly(`http://e.com/foo/bar.html`)
+      );
+      assert.isTrue(loadJsPluginStub.calledOnce);
+      assert.isTrue(
+          loadJsPluginStub.calledWithExactly(`http://e.com/foo/bar.js`));
+    });
+
+    test('Should try replace current host with assetsPath', () => {
+      const host = window.location.origin;
+      Gerrit._loadPlugins([
+        `${host}/foo/bar.html`,
+        `${host}/foo/bar.js`,
+      ]);
+
+      assert.isTrue(importHtmlPluginStub.calledOnce);
+      assert.isTrue(
+          importHtmlPluginStub.calledWithExactly(`https://cdn.com/foo/bar.html`)
+      );
+      assert.isTrue(loadJsPluginStub.calledOnce);
+      assert.isTrue(
+          loadJsPluginStub.calledWithExactly(`https://cdn.com/foo/bar.js`));
+    });
+  });
+
+  test('adds js plugins will call the body', () => {
+    Gerrit._loadPlugins([
+      'http://e.com/foo/bar.js',
+      'http://e.com/bar/foo.js',
+    ]);
+    assert.isTrue(document.body.appendChild.calledTwice);
+  });
+
+  test('can call awaitPluginsLoaded multiple times', done => {
+    const plugins = [
+      'http://e.com/foo/bar.js',
+      'http://e.com/bar/foo.js',
+    ];
+
+    let installed = false;
+    function pluginCallback(url) {
+      if (url === plugins[1]) {
+        installed = true;
       }
-      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-        Gerrit.install(() => pluginCallback(url), undefined, url);
-      });
+    }
+    sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+      Gerrit.install(() => pluginCallback(url), undefined, url);
+    });
 
-      Gerrit._loadPlugins(plugins);
+    Gerrit._loadPlugins(plugins);
+
+    Gerrit.awaitPluginsLoaded().then(() => {
+      assert.isTrue(installed);
 
       Gerrit.awaitPluginsLoaded().then(() => {
-        assert.isTrue(installed);
-
-        Gerrit.awaitPluginsLoaded().then(() => {
-          done();
-        });
-      });
-    });
-
-    suite('preloaded plugins', () => {
-      test('skips preloaded plugins when load plugins', () => {
-        const importHtmlPluginStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_importHtmlPlugin', url => {
-          importHtmlPluginStub(url);
-        });
-        const loadJsPluginStub = sandbox.stub();
-        sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
-          loadJsPluginStub(url);
-        });
-
-        Gerrit._preloadedPlugins = {
-          foo: () => void 0,
-          bar: () => void 0,
-        };
-
-        Gerrit._loadPlugins([
-          'http://e.com/plugins/foo.js',
-          'plugins/bar.html',
-          'http://e.com/plugins/test/foo.js',
-        ]);
-
-        assert.isTrue(importHtmlPluginStub.notCalled);
-        assert.isTrue(loadJsPluginStub.calledOnce);
-      });
-
-      test('isPluginPreloaded', () => {
-        Gerrit._preloadedPlugins = {baz: ()=>{}};
-        assert.isFalse(Gerrit._pluginLoader.isPluginPreloaded('plugins/foo/bar'));
-        assert.isFalse(Gerrit._pluginLoader.isPluginPreloaded('http://a.com/42'));
-        assert.isTrue(
-            Gerrit._pluginLoader.isPluginPreloaded(PRELOADED_PROTOCOL + 'baz')
-        );
-        Gerrit._preloadedPlugins = null;
-      });
-
-      test('preloaded plugins are installed', () => {
-        const installStub = sandbox.stub();
-        Gerrit._preloadedPlugins = {foo: installStub};
-        Gerrit._pluginLoader.installPreloadedPlugins();
-        assert.isTrue(installStub.called);
-        const pluginApi = installStub.lastCall.args[0];
-        assert.strictEqual(pluginApi.getPluginName(), 'foo');
-      });
-
-      test('installing preloaded plugin', () => {
-        let plugin;
-        Gerrit.install(p => { plugin = p; }, '0.1', 'preloaded:foo');
-        assert.strictEqual(plugin.getPluginName(), 'foo');
-        assert.strictEqual(plugin.url('/some/thing.html'),
-            `${window.location.origin}/plugins/foo/some/thing.html`);
+        done();
       });
     });
   });
+
+  suite('preloaded plugins', () => {
+    test('skips preloaded plugins when load plugins', () => {
+      const importHtmlPluginStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_importHtmlPlugin', url => {
+        importHtmlPluginStub(url);
+      });
+      const loadJsPluginStub = sandbox.stub();
+      sandbox.stub(Gerrit._pluginLoader, '_loadJsPlugin', url => {
+        loadJsPluginStub(url);
+      });
+
+      Gerrit._preloadedPlugins = {
+        foo: () => void 0,
+        bar: () => void 0,
+      };
+
+      Gerrit._loadPlugins([
+        'http://e.com/plugins/foo.js',
+        'plugins/bar.html',
+        'http://e.com/plugins/test/foo.js',
+      ]);
+
+      assert.isTrue(importHtmlPluginStub.notCalled);
+      assert.isTrue(loadJsPluginStub.calledOnce);
+    });
+
+    test('isPluginPreloaded', () => {
+      Gerrit._preloadedPlugins = {baz: ()=>{}};
+      assert.isFalse(Gerrit._pluginLoader.isPluginPreloaded('plugins/foo/bar'));
+      assert.isFalse(Gerrit._pluginLoader.isPluginPreloaded('http://a.com/42'));
+      assert.isTrue(
+          Gerrit._pluginLoader.isPluginPreloaded(PRELOADED_PROTOCOL + 'baz')
+      );
+      Gerrit._preloadedPlugins = null;
+    });
+
+    test('preloaded plugins are installed', () => {
+      const installStub = sandbox.stub();
+      Gerrit._preloadedPlugins = {foo: installStub};
+      Gerrit._pluginLoader.installPreloadedPlugins();
+      assert.isTrue(installStub.called);
+      const pluginApi = installStub.lastCall.args[0];
+      assert.strictEqual(pluginApi.getPluginName(), 'foo');
+    });
+
+    test('installing preloaded plugin', () => {
+      let plugin;
+      Gerrit.install(p => { plugin = p; }, '0.1', 'preloaded:foo');
+      assert.strictEqual(plugin.getPluginName(), 'foo');
+      assert.strictEqual(plugin.url('/some/thing.html'),
+          `${window.location.origin}/plugins/foo/some/thing.html`);
+    });
+  });
+});
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
index a486bf1..64c31d7 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
@@ -19,139 +19,141 @@
 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 <title>gr-plugin-rest-api</title>
 
-<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
 
-<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
-<link rel="import" href="gr-js-api-interface.html"/>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+<script type="module" src="../../../test/test-pre-setup.js"></script>
+<script type="module" src="../../../test/common-test-setup.js"></script>
+<script type="module" src="./gr-js-api-interface.js"></script>
 
-<script>
-  suite('gr-plugin-rest-api tests', async () => {
-    await readyToTest();
-    let instance;
-    let sandbox;
-    let getResponseObjectStub;
-    let sendStub;
-    let restApiStub;
+<script type="module">
+import '../../../test/test-pre-setup.js';
+import '../../../test/common-test-setup.js';
+import './gr-js-api-interface.js';
+suite('gr-plugin-rest-api tests', () => {
+  let instance;
+  let sandbox;
+  let getResponseObjectStub;
+  let sendStub;
+  let restApiStub;
 
-    setup(() => {
-      sandbox = sinon.sandbox.create();
-      getResponseObjectStub = sandbox.stub().returns(Promise.resolve());
-      sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
-      restApiStub = {
-        getAccount: () => Promise.resolve({name: 'Judy Hopps'}),
-        getResponseObject: getResponseObjectStub,
-        send: sendStub,
-        getLoggedIn: sandbox.stub(),
-        getVersion: sandbox.stub(),
-        getConfig: sandbox.stub(),
-      };
-      stub('gr-rest-api-interface', Object.keys(restApiStub).reduce((a, k) => {
-        a[k] = (...args) => restApiStub[k](...args);
-        return a;
-      }, {}));
-      Gerrit.install(p => {}, '0.1',
-          'http://test.com/plugins/testplugin/static/test.js');
-      instance = new GrPluginRestApi();
-    });
+  setup(() => {
+    sandbox = sinon.sandbox.create();
+    getResponseObjectStub = sandbox.stub().returns(Promise.resolve());
+    sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
+    restApiStub = {
+      getAccount: () => Promise.resolve({name: 'Judy Hopps'}),
+      getResponseObject: getResponseObjectStub,
+      send: sendStub,
+      getLoggedIn: sandbox.stub(),
+      getVersion: sandbox.stub(),
+      getConfig: sandbox.stub(),
+    };
+    stub('gr-rest-api-interface', Object.keys(restApiStub).reduce((a, k) => {
+      a[k] = (...args) => restApiStub[k](...args);
+      return a;
+    }, {}));
+    Gerrit.install(p => {}, '0.1',
+        'http://test.com/plugins/testplugin/static/test.js');
+    instance = new GrPluginRestApi();
+  });
 
-    teardown(() => {
-      sandbox.restore();
-    });
+  teardown(() => {
+    sandbox.restore();
+  });
 
-    test('fetch', () => {
-      const payload = {foo: 'foo'};
-      return instance.fetch('HTTP_METHOD', '/url', payload).then(r => {
-        assert.isTrue(sendStub.calledWith('HTTP_METHOD', '/url', payload));
-        assert.equal(r.status, 200);
-        assert.isFalse(getResponseObjectStub.called);
-      });
-    });
-
-    test('send', () => {
-      const payload = {foo: 'foo'};
-      const response = {bar: 'bar'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return instance.send('HTTP_METHOD', '/url', payload).then(r => {
-        assert.isTrue(sendStub.calledWith('HTTP_METHOD', '/url', payload));
-        assert.strictEqual(r, response);
-      });
-    });
-
-    test('get', () => {
-      const response = {foo: 'foo'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return instance.get('/url').then(r => {
-        assert.isTrue(sendStub.calledWith('GET', '/url'));
-        assert.strictEqual(r, response);
-      });
-    });
-
-    test('post', () => {
-      const payload = {foo: 'foo'};
-      const response = {bar: 'bar'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return instance.post('/url', payload).then(r => {
-        assert.isTrue(sendStub.calledWith('POST', '/url', payload));
-        assert.strictEqual(r, response);
-      });
-    });
-
-    test('put', () => {
-      const payload = {foo: 'foo'};
-      const response = {bar: 'bar'};
-      getResponseObjectStub.returns(Promise.resolve(response));
-      return instance.put('/url', payload).then(r => {
-        assert.isTrue(sendStub.calledWith('PUT', '/url', payload));
-        assert.strictEqual(r, response);
-      });
-    });
-
-    test('delete works', () => {
-      const response = {status: 204};
-      sendStub.returns(Promise.resolve(response));
-      return instance.delete('/url').then(r => {
-        assert.isTrue(sendStub.calledWith('DELETE', '/url'));
-        assert.strictEqual(r, response);
-      });
-    });
-
-    test('delete fails', () => {
-      sendStub.returns(Promise.resolve(
-          {status: 400, text() { return Promise.resolve('text'); }}));
-      return instance.delete('/url').then(r => {
-        throw new Error('Should not resolve');
-      })
-          .catch(err => {
-            assert.isTrue(sendStub.calledWith('DELETE', '/url'));
-            assert.equal('text', err.message);
-          });
-    });
-
-    test('getLoggedIn', () => {
-      restApiStub.getLoggedIn.returns(Promise.resolve(true));
-      return instance.getLoggedIn().then(result => {
-        assert.isTrue(restApiStub.getLoggedIn.calledOnce);
-        assert.isTrue(result);
-      });
-    });
-
-    test('getVersion', () => {
-      restApiStub.getVersion.returns(Promise.resolve('foo bar'));
-      return instance.getVersion().then(result => {
-        assert.isTrue(restApiStub.getVersion.calledOnce);
-        assert.equal(result, 'foo bar');
-      });
-    });
-
-    test('getConfig', () => {
-      restApiStub.getConfig.returns(Promise.resolve('foo bar'));
-      return instance.getConfig().then(result => {
-        assert.isTrue(restApiStub.getConfig.calledOnce);
-        assert.equal(result, 'foo bar');
-      });
+  test('fetch', () => {
+    const payload = {foo: 'foo'};
+    return instance.fetch('HTTP_METHOD', '/url', payload).then(r => {
+      assert.isTrue(sendStub.calledWith('HTTP_METHOD', '/url', payload));
+      assert.equal(r.status, 200);
+      assert.isFalse(getResponseObjectStub.called);
     });
   });
+
+  test('send', () => {
+    const payload = {foo: 'foo'};
+    const response = {bar: 'bar'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return instance.send('HTTP_METHOD', '/url', payload).then(r => {
+      assert.isTrue(sendStub.calledWith('HTTP_METHOD', '/url', payload));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('get', () => {
+    const response = {foo: 'foo'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return instance.get('/url').then(r => {
+      assert.isTrue(sendStub.calledWith('GET', '/url'));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('post', () => {
+    const payload = {foo: 'foo'};
+    const response = {bar: 'bar'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return instance.post('/url', payload).then(r => {
+      assert.isTrue(sendStub.calledWith('POST', '/url', payload));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('put', () => {
+    const payload = {foo: 'foo'};
+    const response = {bar: 'bar'};
+    getResponseObjectStub.returns(Promise.resolve(response));
+    return instance.put('/url', payload).then(r => {
+      assert.isTrue(sendStub.calledWith('PUT', '/url', payload));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('delete works', () => {
+    const response = {status: 204};
+    sendStub.returns(Promise.resolve(response));
+    return instance.delete('/url').then(r => {
+      assert.isTrue(sendStub.calledWith('DELETE', '/url'));
+      assert.strictEqual(r, response);
+    });
+  });
+
+  test('delete fails', () => {
+    sendStub.returns(Promise.resolve(
+        {status: 400, text() { return Promise.resolve('text'); }}));
+    return instance.delete('/url').then(r => {
+      throw new Error('Should not resolve');
+    })
+        .catch(err => {
+          assert.isTrue(sendStub.calledWith('DELETE', '/url'));
+          assert.equal('text', err.message);
+        });
+  });
+
+  test('getLoggedIn', () => {
+    restApiStub.getLoggedIn.returns(Promise.resolve(true));
+    return instance.getLoggedIn().then(result => {
+      assert.isTrue(restApiStub.getLoggedIn.calledOnce);
+      assert.isTrue(result);
+    });
+  });
+
+  test('getVersion', () => {
+    restApiStub.getVersion.returns(Promise.resolve('foo bar'));
+    return instance.getVersion().then(result => {
+      assert.isTrue(restApiStub.getVersion.calledOnce);
+      assert.equal(result, 'foo bar');
+    });
+  });
+
+  test('getConfig', () => {
+    restApiStub.getConfig.returns(Promise.resolve('foo bar'));
+    return instance.getConfig().then(result => {
+      assert.isTrue(restApiStub.getConfig.calledOnce);
+      assert.equal(result, 'foo bar');
+    });
+  });
+});
 </script>