Merge "Revert "Revert "Support load from ASSETS_PATH for plugins if provided"""
diff --git a/Documentation/intro-user.txt b/Documentation/intro-user.txt
index b13ae83..16929ae 100644
--- a/Documentation/intro-user.txt
+++ b/Documentation/intro-user.txt
@@ -538,7 +538,9 @@
 ----
   $ git push origin HEAD:refs/for/master%wip
 ----
-Alternatively, click *WIP* from the Change screen.
+Alternatively, click *WIP* from the *More* menu on the Change screen.
+The Change screen updates with a yellow header, indicating that
+the change is in a Work-in-Progress state.
 
 To mark the change as ready for review, append `%ready` to your push
 request.
@@ -546,18 +548,12 @@
 ----
   $ git push origin HEAD:refs/for/master%ready
 ----
-Alternatively, click *Ready* from the Change screen.
+Alternatively, click *Start Review* from the Change screen.
 
 Change owners, project owners, site administrators and members of a group that
 was granted "Toggle Work In Progress state" permission can mark changes as
 `work-in-progress` and `ready`.
 
-[[wip-polygerrit]]
-In the new PolyGerrit UI, you can mark a change as WIP, by selecting *WIP* from
-the *More* menu. The Change screen updates with a yellow header, indicating that
-the change is in a Work-in-Progress state. To mark a change as ready for review,
-click *Start Review*.
-
 [[private-changes]]
 == Private Changes
 
diff --git a/java/com/google/gerrit/server/project/RefUtil.java b/java/com/google/gerrit/server/project/RefUtil.java
index 1dac751..5d6379a 100644
--- a/java/com/google/gerrit/server/project/RefUtil.java
+++ b/java/com/google/gerrit/server/project/RefUtil.java
@@ -19,6 +19,7 @@
 
 import com.google.common.collect.Iterables;
 import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -46,16 +47,15 @@
     try {
       ObjectId revid = repo.resolve(baseRevision);
       if (revid == null) {
-        throw new InvalidRevisionException();
+        throw new InvalidRevisionException(baseRevision);
       }
       return revid;
     } catch (IOException err) {
       logger.atSevere().withCause(err).log(
           "Cannot resolve \"%s\" in project \"%s\"", baseRevision, projectName.get());
-      throw new InvalidRevisionException();
+      throw new InvalidRevisionException(baseRevision);
     } catch (RevisionSyntaxException err) {
-      logger.atSevere().withCause(err).log("Invalid revision syntax \"%s\"", baseRevision);
-      throw new InvalidRevisionException();
+      throw new InvalidRevisionException(baseRevision);
     }
   }
 
@@ -66,7 +66,7 @@
       try {
         rw.markStart(rw.parseCommit(revid));
       } catch (IncorrectObjectTypeException err) {
-        throw new InvalidRevisionException();
+        throw new InvalidRevisionException(revid.name());
       }
       RefDatabase refDb = repo.getRefDatabase();
       Iterable<Ref> refs =
@@ -86,11 +86,11 @@
       rw.checkConnectivity();
       return rw;
     } catch (IncorrectObjectTypeException | MissingObjectException err) {
-      throw new InvalidRevisionException();
+      throw new InvalidRevisionException(revid.name());
     } catch (IOException err) {
       logger.atSevere().withCause(err).log(
           "Repository \"%s\" may be corrupt; suggest running git fsck", repo.getDirectory());
-      throw new InvalidRevisionException();
+      throw new InvalidRevisionException(revid.name());
     }
   }
 
@@ -125,8 +125,8 @@
 
     public static final String MESSAGE = "Invalid Revision";
 
-    InvalidRevisionException() {
-      super(MESSAGE);
+    InvalidRevisionException(@Nullable String invalidRevision) {
+      super(MESSAGE + ": " + invalidRevision);
     }
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/project/CreateBranch.java b/java/com/google/gerrit/server/restapi/project/CreateBranch.java
index 56948c1..67213c5 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateBranch.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateBranch.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.entities.RefNames.isConfigRef;
 
+import com.google.common.base.Strings;
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.RefNames;
@@ -93,7 +94,10 @@
     if (input.ref != null && !ref.equals(input.ref)) {
       throw new BadRequestException("ref must match URL");
     }
-    if (input.revision == null) {
+    if (input.revision != null) {
+      input.revision = input.revision.trim();
+    }
+    if (Strings.isNullOrEmpty(input.revision)) {
       input.revision = Constants.HEAD;
     }
     while (ref.startsWith("/")) {
diff --git a/java/com/google/gerrit/server/restapi/project/CreateTag.java b/java/com/google/gerrit/server/restapi/project/CreateTag.java
index dca6e9a..8fdf5e4 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateTag.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateTag.java
@@ -88,7 +88,10 @@
     if (input.ref != null && !ref.equals(input.ref)) {
       throw new BadRequestException("ref must match URL");
     }
-    if (input.revision == null) {
+    if (input.revision != null) {
+      input.revision = input.revision.trim();
+    }
+    if (Strings.isNullOrEmpty(input.revision)) {
       input.revision = Constants.HEAD;
     }
 
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
index e5ef5ba..85d383e 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
@@ -36,9 +36,11 @@
 import com.google.gerrit.extensions.api.projects.BranchInfo;
 import com.google.gerrit.extensions.api.projects.BranchInput;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.inject.Inject;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -146,6 +148,116 @@
         "Not allowed to create group branch.");
   }
 
+  @Test
+  public void createWithRevision() throws Exception {
+    RevCommit revision = projectOperations.project(project).getHead("master");
+
+    // update master so that points to a different revision than the revision on which we create the
+    // new branch
+    pushTo("refs/heads/master");
+    assertThat(projectOperations.project(project).getHead("master")).isNotEqualTo(revision);
+
+    BranchInput input = new BranchInput();
+    input.revision = revision.name();
+    BranchInfo created = branch(testBranch).create(input).get();
+    assertThat(created.ref).isEqualTo(testBranch.branch());
+    assertThat(created.revision).isEqualTo(revision.name());
+    assertThat(projectOperations.project(project).getHead(testBranch.branch())).isEqualTo(revision);
+  }
+
+  @Test
+  public void createWithoutSpecifyingRevision() throws Exception {
+    // If revision is not specified, the branch is created based on HEAD, which points to master.
+    RevCommit expectedRevision = projectOperations.project(project).getHead("master");
+
+    BranchInput input = new BranchInput();
+    input.revision = null;
+    BranchInfo created = branch(testBranch).create(input).get();
+    assertThat(created.ref).isEqualTo(testBranch.branch());
+    assertThat(created.revision).isEqualTo(expectedRevision.name());
+    assertThat(projectOperations.project(project).getHead(testBranch.branch()))
+        .isEqualTo(expectedRevision);
+  }
+
+  @Test
+  public void createWithEmptyRevision() throws Exception {
+    // If revision is not specified, the branch is created based on HEAD, which points to master.
+    RevCommit expectedRevision = projectOperations.project(project).getHead("master");
+
+    BranchInput input = new BranchInput();
+    input.revision = "";
+    BranchInfo created = branch(testBranch).create(input).get();
+    assertThat(created.ref).isEqualTo(testBranch.branch());
+    assertThat(created.revision).isEqualTo(expectedRevision.name());
+    assertThat(projectOperations.project(project).getHead(testBranch.branch()))
+        .isEqualTo(expectedRevision);
+  }
+
+  @Test
+  public void createRevisionIsTrimmed() throws Exception {
+    RevCommit revision = projectOperations.project(project).getHead("master");
+
+    BranchInput input = new BranchInput();
+    input.revision = "\t" + revision.name();
+    BranchInfo created = branch(testBranch).create(input).get();
+    assertThat(created.ref).isEqualTo(testBranch.branch());
+    assertThat(created.revision).isEqualTo(revision.name());
+    assertThat(projectOperations.project(project).getHead(testBranch.branch())).isEqualTo(revision);
+  }
+
+  @Test
+  public void createWithBranchNameAsRevision() throws Exception {
+    RevCommit expectedRevision = projectOperations.project(project).getHead("master");
+
+    BranchInput input = new BranchInput();
+    input.revision = "master";
+    BranchInfo created = branch(testBranch).create(input).get();
+    assertThat(created.ref).isEqualTo(testBranch.branch());
+    assertThat(created.revision).isEqualTo(expectedRevision.name());
+    assertThat(projectOperations.project(project).getHead(testBranch.branch()))
+        .isEqualTo(expectedRevision);
+  }
+
+  @Test
+  public void createWithFullBranchNameAsRevision() throws Exception {
+    RevCommit expectedRevision = projectOperations.project(project).getHead("master");
+
+    BranchInput input = new BranchInput();
+    input.revision = "refs/heads/master";
+    BranchInfo created = branch(testBranch).create(input).get();
+    assertThat(created.ref).isEqualTo(testBranch.branch());
+    assertThat(created.revision).isEqualTo(expectedRevision.name());
+    assertThat(projectOperations.project(project).getHead(testBranch.branch()))
+        .isEqualTo(expectedRevision);
+  }
+
+  @Test
+  public void cannotCreateWithNonExistingBranchNameAsRevision() throws Exception {
+    assertCreateFails(
+        testBranch,
+        "refs/heads/non-existing",
+        BadRequestException.class,
+        "invalid revision \"refs/heads/non-existing\"");
+  }
+
+  @Test
+  public void cannotCreateWithNonExistingRevision() throws Exception {
+    assertCreateFails(
+        testBranch,
+        "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+        BadRequestException.class,
+        "invalid revision \"deadbeefdeadbeefdeadbeefdeadbeefdeadbeef\"");
+  }
+
+  @Test
+  public void cannotCreateWithInvalidRevision() throws Exception {
+    assertCreateFails(
+        testBranch,
+        "invalid\trevision",
+        BadRequestException.class,
+        "invalid revision \"invalid\trevision\"");
+  }
+
   private void blockCreateReference() throws Exception {
     projectOperations
         .project(project)
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java b/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java
index 3d1a148..3becb81 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java
@@ -41,6 +41,7 @@
 import com.google.inject.Inject;
 import java.sql.Timestamp;
 import java.util.List;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Test;
 
 @NoHttpd
@@ -357,6 +358,53 @@
     assertThat(thrown).hasMessageThat().contains("Invalid base revision");
   }
 
+  @Test
+  public void noBaseRevision() throws Exception {
+    grantTagPermissions();
+
+    // If revision is not specified, the tag is created based on HEAD, which points to master.
+    RevCommit expectedRevision = projectOperations.project(project).getHead("master");
+
+    TagInput input = new TagInput();
+    input.ref = "test";
+    input.revision = null;
+
+    TagInfo result = tag(input.ref).create(input).get();
+    assertThat(result.ref).isEqualTo(R_TAGS + input.ref);
+    assertThat(result.revision).isEqualTo(expectedRevision.name());
+  }
+
+  @Test
+  public void emptyBaseRevision() throws Exception {
+    grantTagPermissions();
+
+    // If revision is not specified, the tag is created based on HEAD, which points to master.
+    RevCommit expectedRevision = projectOperations.project(project).getHead("master");
+
+    TagInput input = new TagInput();
+    input.ref = "test";
+    input.revision = "";
+
+    TagInfo result = tag(input.ref).create(input).get();
+    assertThat(result.ref).isEqualTo(R_TAGS + input.ref);
+    assertThat(result.revision).isEqualTo(expectedRevision.name());
+  }
+
+  @Test
+  public void baseRevisionIsTrimmed() throws Exception {
+    grantTagPermissions();
+
+    RevCommit revision = projectOperations.project(project).getHead("master");
+
+    TagInput input = new TagInput();
+    input.ref = "test";
+    input.revision = "\t" + revision.name();
+
+    TagInfo result = tag(input.ref).create(input).get();
+    assertThat(result.ref).isEqualTo(R_TAGS + input.ref);
+    assertThat(result.revision).isEqualTo(revision.name());
+  }
+
   private void assertTagList(FluentIterable<String> expected, List<TagInfo> actual)
       throws Exception {
     assertThat(actual).hasSize(expected.size());
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html
index 8f9bf00..67e4ca6 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html
@@ -81,6 +81,12 @@
       return path;
     },
 
+    isMagicPath(path) {
+      return !!path &&
+          (path === Gerrit.PathListBehavior.COMMIT_MESSAGE_PATH || path ===
+              Gerrit.PathListBehavior.MERGE_LIST_PATH);
+    },
+
     computeTruncatedPath(path) {
       return Gerrit.PathListBehavior.truncatePath(
           Gerrit.PathListBehavior.computeDisplayPath(path));
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
index 924c98c..12b981c 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
@@ -56,6 +56,14 @@
       assert.equal(name('/MERGE_LIST'), 'Merge list');
     });
 
+    test('isMagicPath', () => {
+      const isMagic = Gerrit.PathListBehavior.isMagicPath;
+      assert.isFalse(isMagic(undefined));
+      assert.isFalse(isMagic('/foo.cc'));
+      assert.isTrue(isMagic('/COMMIT_MSG'));
+      assert.isTrue(isMagic('/MERGE_LIST'));
+    });
+
     test('truncatePath with long path should add ellipsis', () => {
       const truncatePath = Gerrit.PathListBehavior.truncatePath;
       let path = 'level1/level2/level3/level4/file.js';
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
index e6eef75..04bdab7 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
@@ -197,7 +197,10 @@
         assert.equal(Polymer.dom(element.root)
             .querySelectorAll('.sectionTitle').length, 3);
         assert.equal(element.$$('.breadcrumbText').innerText, 'Test Repo');
-        assert.equal(element.$$('#pageSelect').items.length, 6);
+        assert.equal(
+            element.shadowRoot.querySelector('#pageSelect').items.length,
+            6
+        );
         done();
       });
     });
@@ -439,13 +442,16 @@
       element.reload().then(() => {
         assert.deepEqual(element._filteredLinks, expectedFilteredLinks);
         assert.deepEqual(element._subsectionLinks, expectedSubsectionLinks);
-        assert.equal(element.$$('#pageSelect').value, 'repoaccess');
+        assert.equal(
+            element.shadowRoot.querySelector('#pageSelect').value,
+            'repoaccess'
+        );
         assert.isTrue(element._selectedIsCurrentPage.calledOnce);
         // Doesn't trigger navigation from the page select menu.
         assert.isFalse(Gerrit.Nav.navigateToRelativeUrl.called);
 
         // When explicitly changed, navigation is called
-        element.$$('#pageSelect').value = 'repo';
+        element.shadowRoot.querySelector('#pageSelect').value = 'repo';
         assert.isTrue(element._selectedIsCurrentPage.calledTwice);
         assert.isTrue(Gerrit.Nav.navigateToRelativeUrl.calledOnce);
         done();
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
index 6cb7e4a..7919b28 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
@@ -385,7 +385,8 @@
 
         assert.isFalse(element._originalExclusiveValue);
         assert.isNotOk(element.permission.value.modified);
-        MockInteractions.tap(element.$$('#exclusiveToggle'));
+        MockInteractions.tap(element.shadowRoot
+            .querySelector('#exclusiveToggle'));
         flushAsynchronousOperations();
         assert.isTrue(element.permission.value.exclusive);
         assert.isTrue(element.permission.value.modified);
@@ -405,21 +406,25 @@
       });
 
       test('Exclusive hidden for owner permission', () => {
-        assert.equal(getComputedStyle(element.$$('#exclusiveToggle')).display,
-            'flex');
+        assert.equal(getComputedStyle(element.shadowRoot
+            .querySelector('#exclusiveToggle')).display,
+        'flex');
         element.set(['permission', 'id'], 'owner');
         flushAsynchronousOperations();
-        assert.equal(getComputedStyle(element.$$('#exclusiveToggle')).display,
-            'none');
+        assert.equal(getComputedStyle(element.shadowRoot
+            .querySelector('#exclusiveToggle')).display,
+        'none');
       });
 
       test('Exclusive hidden for any global permissions', () => {
-        assert.equal(getComputedStyle(element.$$('#exclusiveToggle')).display,
-            'flex');
+        assert.equal(getComputedStyle(element.shadowRoot
+            .querySelector('#exclusiveToggle')).display,
+        'flex');
         element.section = 'GLOBAL_CAPABILITIES';
         flushAsynchronousOperations();
-        assert.equal(getComputedStyle(element.$$('#exclusiveToggle')).display,
-            'none');
+        assert.equal(getComputedStyle(element.shadowRoot
+            .querySelector('#exclusiveToggle')).display,
+        'none');
       });
     });
   });
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
index 90eaba5..fc7dea8 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
@@ -282,7 +282,8 @@
           id: 'test-project',
         };
         flushAsynchronousOperations();
-        assert.equal(getComputedStyle(element.$$('#editInheritFromInput'))
+        assert.equal(getComputedStyle(element.shadowRoot
+            .querySelector('#editInheritFromInput'))
             .display, 'none');
 
         MockInteractions.tap(element.$.editBtn);
@@ -300,7 +301,8 @@
           assert.notEqual(getComputedStyle(element.$.saveBtn).display, 'none');
           assert.isTrue(element.$.saveBtn.disabled);
         }
-        assert.notEqual(getComputedStyle(element.$$('#editInheritFromInput'))
+        assert.notEqual(getComputedStyle(element.shadowRoot
+            .querySelector('#editInheritFromInput'))
             .display, 'none');
 
         // Save button should be enabled after access is modified
@@ -365,7 +367,7 @@
           id: 'test-project',
         };
         flushAsynchronousOperations();
-        element.$$('#editInheritFromInput').fire('commit');
+        element.shadowRoot.querySelector('#editInheritFromInput').fire('commit');
         sandbox.spy(element, '_handleAccessModified');
         element.fire('access-modified');
         assert.isTrue(element._handleAccessModified.called);
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index 532c573..d9b7986 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -466,7 +466,9 @@
         element._handleDeleteEditTap();
         assert.isFalse(element.$.confirmDeleteEditDialog.hidden);
         MockInteractions.tap(
-            element.$$('#confirmDeleteEditDialog').$$('gr-button[primary]'));
+            element.shadowRoot
+                .querySelector('#confirmDeleteEditDialog')
+                .$$('gr-button[primary]'));
         flushAsynchronousOperations();
 
         assert.equal(fireActionStub.lastCall.args[0], '/edit');
@@ -980,9 +982,12 @@
 
       test('shows confirm dialog', () => {
         element._handleDeleteTap();
-        assert.isFalse(element.$$('#confirmDeleteDialog').hidden);
+        assert.isFalse(element.shadowRoot
+            .querySelector('#confirmDeleteDialog').hidden);
         MockInteractions.tap(
-            element.$$('#confirmDeleteDialog').$$('gr-button[primary]'));
+            element.shadowRoot
+                .querySelector('#confirmDeleteDialog')
+                .$$('gr-button[primary]'));
         flushAsynchronousOperations();
         assert.isTrue(fireActionStub.calledWith('/', deleteAction, false));
       });
@@ -990,9 +995,12 @@
       test('hides delete confirm on cancel', () => {
         element._handleDeleteTap();
         MockInteractions.tap(
-            element.$$('#confirmDeleteDialog').$$('gr-button:not([primary])'));
+            element.shadowRoot
+                .querySelector('#confirmDeleteDialog')
+                .$$('gr-button:not([primary])'));
         flushAsynchronousOperations();
-        assert.isTrue(element.$$('#confirmDeleteDialog').hidden);
+        assert.isTrue(element.shadowRoot
+            .querySelector('#confirmDeleteDialog').hidden);
         assert.isFalse(fireActionStub.called);
       });
     });
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index 5de378b..b9e9e6c 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -437,7 +437,8 @@
     }
 
     _handleFileTabChange(e) {
-      const selectedIndex = this.$$('#primaryTabs').selected;
+      const selectedIndex = this.shadowRoot
+          .querySelector('#primaryTabs').selected;
       this._showFileTabContent = selectedIndex === 0;
       // Initial tab is the static files list.
       const newSelectedTab =
@@ -458,8 +459,8 @@
         console.warn(e.detail.tab + ' tab not found');
         return;
       }
-      this.$$('#primaryTabs').selected = idx + 1;
-      this.$$('#primaryTabs').scrollIntoView();
+      this.shadowRoot.querySelector('#primaryTabs').selected = idx + 1;
+      this.shadowRoot.querySelector('#primaryTabs').scrollIntoView();
       this.$.reporting.reportInteraction('show-tab', e.detail.tab);
     }
 
@@ -799,7 +800,7 @@
       // Selected has to be set after the paper-tabs are visible because
       // the selected underline depends on calculations made by the browser.
       this.$.commentTabs.selected = 0;
-      const primaryTabs = this.$$('#primaryTabs');
+      const primaryTabs = this.shadowRoot.querySelector('#primaryTabs');
       if (primaryTabs) primaryTabs.selected = 0;
     }
 
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index ab849de..9329ba5 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -68,7 +68,8 @@
     }
 
     getFocusStops() {
-      const links = this.$$('#archives').querySelectorAll('a');
+      const links = this.shadowRoot
+          .querySelector('#archives').querySelectorAll('a');
       return {
         start: this.$.closeButton,
         end: links[links.length - 1],
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
index ea7ea8f..10efaff 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
@@ -216,8 +216,8 @@
     test('expand/collapse buttons are toggled correctly', () => {
       element.shownFileCount = 10;
       flushAsynchronousOperations();
-      const expandBtn = element.$$('#expandBtn');
-      const collapseBtn = element.$$('#collapseBtn');
+      const expandBtn = element.shadowRoot.querySelector('#expandBtn');
+      const collapseBtn = element.shadowRoot.querySelector('#collapseBtn');
       assert.notEqual(getComputedStyle(expandBtn).display, 'none');
       assert.equal(getComputedStyle(collapseBtn).display, 'none');
       element.filesExpanded = GrFileListConstants.FilesExpandedState.SOME;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index fb57164..9943192 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -339,9 +339,9 @@
     }
 
     _calculatePatchChange(files) {
-      const magicFilesExcluded = files.filter(files => {
-        return files.__path !== '/COMMIT_MSG' && files.__path !== '/MERGE_LIST';
-      });
+      const magicFilesExcluded = files.filter(files =>
+        !this.isMagicPath(files.__path)
+      );
 
       return magicFilesExcluded.reduce((acc, obj) => {
         const inserted = obj.lines_inserted ? obj.lines_inserted : 0;
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
index 9caf13d..b0747f4 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
@@ -231,7 +231,8 @@
           .concat(_.times(11, randomMessage));
       flushAsynchronousOperations();
 
-      MockInteractions.tap(element.$$('#collapse-messages')); // Expand all.
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages')); // Expand all.
       flushAsynchronousOperations();
 
       let messages = getMessages();
@@ -255,8 +256,10 @@
           .concat(_.times(11, randomMessage));
       flushAsynchronousOperations();
 
-      MockInteractions.tap(element.$$('#collapse-messages')); // Expand all.
-      MockInteractions.tap(element.$$('#collapse-messages')); // Collapse all.
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages')); // Expand all.
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages')); // Collapse all.
       flushAsynchronousOperations();
 
       let messages = getMessages();
@@ -283,13 +286,15 @@
       MockInteractions.tap(allMessageEls[1]);
       assert.isTrue(allMessageEls[1]._expanded);
 
-      MockInteractions.tap(element.$$('#collapse-messages'));
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages'));
       allMessageEls = getMessages();
       for (const message of allMessageEls) {
         assert.isTrue(message._expanded);
       }
 
-      MockInteractions.tap(element.$$('#collapse-messages'));
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages'));
       allMessageEls = getMessages();
       for (const message of allMessageEls) {
         assert.isFalse(message._expanded);
@@ -297,28 +302,33 @@
     });
 
     test('expand/collapse from external keypress', () => {
-      MockInteractions.tap(element.$$('#collapse-messages'));
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages'));
       let allMessageEls = getMessages();
       for (const message of allMessageEls) {
         assert.isTrue(message._expanded);
       }
 
       // Expand/collapse all text also changes.
-      assert.equal(element.$$('#collapse-messages').textContent.trim(),
-          'Collapse all');
+      assert.equal(element.shadowRoot
+          .querySelector('#collapse-messages').textContent.trim(),
+      'Collapse all');
 
-      MockInteractions.tap(element.$$('#collapse-messages'));
+      MockInteractions.tap(element.shadowRoot
+          .querySelector('#collapse-messages'));
       allMessageEls = getMessages();
       for (const message of allMessageEls) {
         assert.isFalse(message._expanded);
       }
       // Expand/collapse all text also changes.
-      assert.equal(element.$$('#collapse-messages').textContent.trim(),
-          'Expand all');
+      assert.equal(element.shadowRoot
+          .querySelector('#collapse-messages').textContent.trim(),
+      'Expand all');
     });
 
     test('hide messages does not appear when no automated messages', () => {
-      assert.isOk(element.$$('#automatedMessageToggleContainer[hidden]'));
+      assert.isOk(element.shadowRoot
+          .querySelector('#automatedMessageToggleContainer[hidden]'));
     });
 
     test('scroll to message', () => {
@@ -476,7 +486,8 @@
     });
 
     test('hide autogenerated button is not hidden', () => {
-      assert.isNotOk(element.$$('#automatedMessageToggle[hidden]'));
+      assert.isNotOk(element.shadowRoot
+          .querySelector('#automatedMessageToggle[hidden]'));
     });
 
     test('autogenerated messages are not hidden initially', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
index badd62a..e44f669 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
@@ -187,7 +187,7 @@
     });
 
     test('keep drafts with reply', done => {
-      MockInteractions.tap(element.$$('#includeComments'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#includeComments'));
       assert.equal(element._includeComments, false);
 
       // Async tick is needed because iron-selector content is distributed and
@@ -460,7 +460,8 @@
       flushAsynchronousOperations();
       assert.isFalse(element._reviewersMutated);
       assert.isTrue(element.$.ccs.allowAnyInput);
-      assert.isFalse(element.$$('#reviewers').allowAnyInput);
+      assert.isFalse(element.shadowRoot
+          .querySelector('#reviewers').allowAnyInput);
       element.$.ccs.dispatchEvent(new CustomEvent('account-text-changed',
           {bubbles: true, composed: true}));
       assert.isTrue(element._reviewersMutated);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 40a02a3..cd53510 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -277,7 +277,7 @@
           </span>
         </div>
         <div class="rightControls">
-          <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff)]]">
+          <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff, _path)]]">
             <gr-button
                 link
                 disabled="[[_isBlameLoading]]"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 4c401cf..2f2b3863 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -1101,8 +1101,8 @@
           });
     }
 
-    _computeBlameLoaderClass(isImageDiff) {
-      return !isImageDiff ? 'show' : '';
+    _computeBlameLoaderClass(isImageDiff, path) {
+      return !this.isMagicPath(path) && !isImageDiff ? 'show' : '';
     }
 
     _getRevisionInfo(change) {
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
index 2d7dc9c..b7e52a1 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
@@ -82,7 +82,7 @@
     });
 
     test('open', () => {
-      MockInteractions.tap(element.$$('#open'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#open'));
       element.patchNum = 1;
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element._hideAllDialogs.called);
@@ -101,7 +101,7 @@
     });
 
     test('cancel', () => {
-      MockInteractions.tap(element.$$('#open'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#open'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.openDialog.disabled);
         openAutoCcmplete.noDebounce = true;
@@ -129,7 +129,7 @@
 
     test('delete', () => {
       deleteStub.returns(Promise.resolve({ok: true}));
-      MockInteractions.tap(element.$$('#delete'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.deleteDialog.disabled);
         assert.isFalse(queryStub.called);
@@ -152,7 +152,7 @@
 
     test('delete fails', () => {
       deleteStub.returns(Promise.resolve({ok: false}));
-      MockInteractions.tap(element.$$('#delete'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.deleteDialog.disabled);
         assert.isFalse(queryStub.called);
@@ -173,7 +173,7 @@
     });
 
     test('cancel', () => {
-      MockInteractions.tap(element.$$('#delete'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#delete'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.deleteDialog.disabled);
         element.$.deleteDialog.querySelector('gr-autocomplete').text =
@@ -204,7 +204,7 @@
 
     test('rename', () => {
       renameStub.returns(Promise.resolve({ok: true}));
-      MockInteractions.tap(element.$$('#rename'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.renameDialog.disabled);
         assert.isFalse(queryStub.called);
@@ -232,7 +232,7 @@
 
     test('rename fails', () => {
       renameStub.returns(Promise.resolve({ok: false}));
-      MockInteractions.tap(element.$$('#rename'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.renameDialog.disabled);
         assert.isFalse(queryStub.called);
@@ -258,7 +258,7 @@
     });
 
     test('cancel', () => {
-      MockInteractions.tap(element.$$('#rename'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#rename'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         assert.isTrue(element.$.renameDialog.disabled);
         element.$.renameDialog.querySelector('gr-autocomplete').text =
@@ -285,13 +285,14 @@
     });
 
     test('restore hidden by default', () => {
-      assert.isTrue(element.$$('#restore').classList.contains('invisible'));
+      assert.isTrue(element.shadowRoot
+          .querySelector('#restore').classList.contains('invisible'));
     });
 
     test('restore', () => {
       restoreStub.returns(Promise.resolve({ok: true}));
       element._path = 'src/test.cpp';
-      MockInteractions.tap(element.$$('#restore'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         MockInteractions.tap(element.$.restoreDialog.$$('gr-button[primary]'));
         flushAsynchronousOperations();
@@ -309,7 +310,7 @@
     test('restore fails', () => {
       restoreStub.returns(Promise.resolve({ok: false}));
       element._path = 'src/test.cpp';
-      MockInteractions.tap(element.$$('#restore'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         MockInteractions.tap(element.$.restoreDialog.$$('gr-button[primary]'));
         flushAsynchronousOperations();
@@ -325,7 +326,7 @@
 
     test('cancel', () => {
       element._path = 'src/test.cpp';
-      MockInteractions.tap(element.$$('#restore'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#restore'));
       return showDialogSpy.lastCall.returnValue.then(() => {
         MockInteractions.tap(element.$.restoreDialog.$$('gr-button'));
         assert.isFalse(navStub.called);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.html b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.html
index 89b28d5..0567777 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.html
@@ -90,6 +90,7 @@
           as="comment">
         <gr-comment
             comment="{{comment}}"
+            comments="{{comments}}"
             robot-button-disabled="[[_shouldDisableAction(_showActions, _lastComment)]]"
             change-num="[[changeNum]]"
             patch-num="[[patchNum]]"
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html
index cb87bd9..d1d60f1 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.html
@@ -60,7 +60,7 @@
         display: none;
       }
       .header {
-        align-items: baseline;
+        align-items: center;
         cursor: pointer;
         display: flex;
         margin: calc(0px - var(--spacing-m)) calc(0px - var(--spacing-m)) 0 calc(0px - var(--spacing-m));
@@ -271,7 +271,7 @@
             secondary
             class$="action delete [[_computeDeleteButtonClass(_isAdmin, draft)]]"
             on-click="_handleCommentDelete">
-          (Delete)
+          <iron-icon id="icon" icon="gr-icons:delete"></iron-icon>
         </gr-button>
         <span class="date" on-click="_handleAnchorClick">
           <gr-date-formatter
@@ -348,14 +348,16 @@
         </div>
         <div class="robotActions" hidden$="[[!_showRobotActions]]">
           <template is="dom-if" if="[[isRobotComment]]">
-            <gr-button
-                link
-                secondary
-                class="action fix"
-                on-click="_handleFix"
-                disabled="[[robotButtonDisabled]]">
-              Please Fix
-            </gr-button>
+            <template is="dom-if" if="[[!_hasHumanReply]]">
+              <gr-button
+                  link
+                  secondary
+                  class="action fix"
+                  on-click="_handleFix"
+                  disabled="[[robotButtonDisabled]]">
+                Please Fix
+              </gr-button>
+            </template>
             <gr-endpoint-decorator name="robot-comment-controls">
               <gr-endpoint-param name="comment" value="[[comment]]">
               </gr-endpoint-param>
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
index 053eeee..eb4081e 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
@@ -81,6 +81,9 @@
           notify: true,
           observer: '_commentChanged',
         },
+        comments: {
+          type: Array,
+        },
         isRobotComment: {
           type: Boolean,
           value: false,
@@ -119,6 +122,7 @@
         /** @type {?} */
         projectConfig: Object,
         robotButtonDisabled: Boolean,
+        _hasHumanReply: Boolean,
         _isAdmin: {
           type: Boolean,
           value: false,
@@ -165,6 +169,7 @@
         '_loadLocalDraft(changeNum, patchNum, comment)',
         '_isRobotComment(comment)',
         '_calculateActionstoShow(showActions, isRobotComment)',
+        '_computeHasHumanReply(comment, comments.*)',
       ];
     }
 
@@ -196,14 +201,15 @@
     }
 
     get textarea() {
-      return this.$$('#editTextarea');
+      return this.shadowRoot.querySelector('#editTextarea');
     }
 
     get confirmDeleteOverlay() {
       if (!this._overlays.confirmDelete) {
         this._enableOverlay = true;
         Polymer.dom.flush();
-        this._overlays.confirmDelete = this.$$('#confirmDeleteOverlay');
+        this._overlays.confirmDelete = this.shadowRoot
+            .querySelector('#confirmDeleteOverlay');
       }
       return this._overlays.confirmDelete;
     }
@@ -212,7 +218,8 @@
       if (!this._overlays.confirmDiscard) {
         this._enableOverlay = true;
         Polymer.dom.flush();
-        this._overlays.confirmDiscard = this.$$('#confirmDiscardOverlay');
+        this._overlays.confirmDiscard = this.shadowRoot
+            .querySelector('#confirmDiscardOverlay');
       }
       return this._overlays.confirmDiscard;
     }
@@ -308,6 +315,15 @@
       }
     }
 
+    _computeHasHumanReply() {
+      if (!this.comment || !this.comments) return;
+      // hide please fix button for robot comment that has human reply
+      this._hasHumanReply = this.comments.some(c => {
+        return c.in_reply_to && c.in_reply_to === this.comment.id
+            && !c.robot_id;
+      });
+    }
+
     /**
      * @param {!Object=} opt_mixin
      *
@@ -354,7 +370,7 @@
       if (editing) {
         this.async(() => {
           Polymer.dom.flush();
-          this.textarea.putCursorAtEnd();
+          this.textarea && this.textarea.putCursorAtEnd();
         }, 1);
       }
     }
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
index ad8b5e4..3111475 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
@@ -867,9 +867,145 @@
         done();
       });
       element.isRobotComment = true;
+      element.comments = [element.comment];
       flushAsynchronousOperations();
 
       MockInteractions.tap(element.$$('.fix'));
     });
+
+    test('do not show Please Fix button if human reply exists', () => {
+      element.comments = [
+        {
+          robot_id: 'happy_robot_id',
+          robot_run_id: '5838406743490560',
+          fix_suggestions: [
+            {
+              fix_id: '478ff847_3bf47aaf',
+              description: 'Make the smiley happier by giving it a nose.',
+              replacements: [
+                {
+                  path: 'Documentation/config-gerrit.txt',
+                  range: {
+                    start_line: 10,
+                    start_character: 7,
+                    end_line: 10,
+                    end_character: 9,
+                  },
+                  replacement: ':-)',
+                },
+              ],
+            },
+          ],
+          author: {
+            _account_id: 1030912,
+            name: 'Alice Kober-Sotzek',
+            email: 'aliceks@google.com',
+            avatars: [
+              {
+                url: '/s32-p/photo.jpg',
+                height: 32,
+              },
+              {
+                url: '/AaAdOFzPlFI/s56-p/photo.jpg',
+                height: 56,
+              },
+              {
+                url: '/AaAdOFzPlFI/s100-p/photo.jpg',
+                height: 100,
+              },
+              {
+                url: '/AaAdOFzPlFI/s120-p/photo.jpg',
+                height: 120,
+              },
+            ],
+          },
+          patch_set: 1,
+          id: 'eb0d03fd_5e95904f',
+          line: 10,
+          updated: '2017-04-04 15:36:17.000000000',
+          message: 'This is a robot comment with a fix.',
+          unresolved: false,
+          __commentSide: 'right',
+          collapsed: false,
+        },
+        {
+          __draft: true,
+          __draftID: '0.wbrfbwj89sa',
+          __date: '2019-12-04T13:41:03.689Z',
+          path: 'Documentation/config-gerrit.txt',
+          patchNum: 1,
+          side: 'REVISION',
+          __commentSide: 'right',
+          line: 10,
+          in_reply_to: 'eb0d03fd_5e95904f',
+          message: '> This is a robot comment with a fix.\n\nPlease Fix',
+          unresolved: true,
+        },
+      ];
+      element.comment = element.comments[0];
+      flushAsynchronousOperations();
+      assert.isNull(element.$$('robotActions gr-button'));
+    });
+
+    test('show Please Fix if no human reply', () => {
+      element.comments = [
+        {
+          robot_id: 'happy_robot_id',
+          robot_run_id: '5838406743490560',
+          fix_suggestions: [
+            {
+              fix_id: '478ff847_3bf47aaf',
+              description: 'Make the smiley happier by giving it a nose.',
+              replacements: [
+                {
+                  path: 'Documentation/config-gerrit.txt',
+                  range: {
+                    start_line: 10,
+                    start_character: 7,
+                    end_line: 10,
+                    end_character: 9,
+                  },
+                  replacement: ':-)',
+                },
+              ],
+            },
+          ],
+          author: {
+            _account_id: 1030912,
+            name: 'Alice Kober-Sotzek',
+            email: 'aliceks@google.com',
+            avatars: [
+              {
+                url: '/s32-p/photo.jpg',
+                height: 32,
+              },
+              {
+                url: '/AaAdOFzPlFI/s56-p/photo.jpg',
+                height: 56,
+              },
+              {
+                url: '/AaAdOFzPlFI/s100-p/photo.jpg',
+                height: 100,
+              },
+              {
+                url: '/AaAdOFzPlFI/s120-p/photo.jpg',
+                height: 120,
+              },
+            ],
+          },
+          patch_set: 1,
+          id: 'eb0d03fd_5e95904f',
+          line: 10,
+          updated: '2017-04-04 15:36:17.000000000',
+          message: 'This is a robot comment with a fix.',
+          unresolved: false,
+          __commentSide: 'right',
+          collapsed: false,
+        },
+      ];
+      element.comment = element.comments[0];
+      flushAsynchronousOperations();
+      assert.isNotNull(element.$$('.robotActions gr-button'));
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
index 8f87b38..f99d5d9 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
@@ -126,11 +126,13 @@
     });
 
     test('createNew link appears correctly', () => {
-      assert.isFalse(element.$$('#createNewContainer').classList
+      assert.isFalse(element.shadowRoot
+          .querySelector('#createNewContainer').classList
           .contains('show'));
       element.createNew = true;
       flushAsynchronousOperations();
-      assert.isTrue(element.$$('#createNewContainer').classList
+      assert.isTrue(element.shadowRoot
+          .querySelector('#createNewContainer').classList
           .contains('show'));
     });
 
@@ -139,7 +141,7 @@
       element.addEventListener('create-clicked', clickHandler);
       element.createNew = true;
       flushAsynchronousOperations();
-      MockInteractions.tap(element.$$('#createNew'));
+      MockInteractions.tap(element.shadowRoot.querySelector('#createNew'));
       assert.isTrue(clickHandler.called);
     });
 
diff --git a/polygerrit-ui/app/styles/themes/app-theme.html b/polygerrit-ui/app/styles/themes/app-theme.html
index 3a620d2..7bb8fff 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.html
+++ b/polygerrit-ui/app/styles/themes/app-theme.html
@@ -164,9 +164,13 @@
   --syntax-title-color: #0000c0;
   --syntax-type-color: #2a66d9;
   --syntax-variable-color: var(--primary-text-color);
+
   /* misc */
   --border-radius: 4px;
   --reply-overlay-z-index: 1000;
+
+  /* paper and iron component overrides */
+  --iron-overlay-backdrop-background-color: black;
   --iron-overlay-backdrop-opacity: 0.32;
   --iron-overlay-backdrop: {
     transition: none;
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.html b/polygerrit-ui/app/styles/themes/dark-theme.html
index 4a91774..732ad2e 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.html
+++ b/polygerrit-ui/app/styles/themes/dark-theme.html
@@ -137,6 +137,9 @@
 
       /* misc */
 
+      /* paper and iron component overrides */
+      --iron-overlay-backdrop-background-color: white;
+
       /* rules applied to <html> */
       background-color: var(--view-background-color);
     }