Merge "Convert gr-file-list-header to lit" into stable-3.6
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index b708020..32dde8c 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -1870,7 +1870,7 @@
     assert.equal(element._patchRange.patchNum, 5 as RevisionPatchSetNum);
   });
 
-  test('file-action-tap handling', () => {
+  test('file-action-tap handling', async () => {
     element._patchRange = {
       basePatchNum: ParentPatchSetNum,
       patchNum: 1 as RevisionPatchSetNum,
@@ -1881,10 +1881,12 @@
     const fileList = element.$.fileList;
     const Actions = GrEditConstants.Actions;
     element.$.fileListHeader.editMode = true;
+    await element.$.fileListHeader.updateComplete;
     flush();
-    const controls = element.$.fileListHeader.shadowRoot!.querySelector(
+    const controls = queryAndAssert<GrEditControls>(
+      element.$.fileListHeader,
       '#editControls'
-    ) as GrEditControls;
+    );
     const openDeleteDialogStub = sinon.stub(controls, 'openDeleteDialog');
     const openRenameDialogStub = sinon.stub(controls, 'openRenameDialog');
     const openRestoreDialogStub = sinon.stub(controls, 'openRestoreDialog');
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index 56949fa..a711680 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import '../../../styles/shared-styles';
 import '../../../embed/diff/gr-diff-mode-selector/gr-diff-mode-selector';
 import '../../diff/gr-patch-range-select/gr-patch-range-select';
 import '../../edit/gr-edit-controls/gr-edit-controls';
@@ -22,12 +21,10 @@
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-icons/gr-icons';
 import '../gr-commit-info/gr-commit-info';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-file-list-header_html';
 import {FilesExpandedState} from '../gr-file-list-constants';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {computeLatestPatchNum, PatchSet} from '../../../utils/patch-set-util';
-import {property, customElement} from '@polymer/decorators';
+import {property, customElement, query} from 'lit/decorators';
 import {
   AccountInfo,
   ChangeInfo,
@@ -47,27 +44,13 @@
   ShortcutSection,
 } from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {getAppContext} from '../../../services/app-context';
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-file-list-header': GrFileListHeader;
-  }
-}
-
-export interface GrFileListHeader {
-  $: {
-    modeSelect: GrDiffModeSelector;
-    expandBtn: GrButton;
-    collapseBtn: GrButton;
-  };
-}
+import {css, html, LitElement} from 'lit';
+import {sharedStyles} from '../../../styles/shared-styles';
+import {when} from 'lit/directives/when';
+import {ifDefined} from 'lit/directives/if-defined';
 
 @customElement('gr-file-list-header')
-export class GrFileListHeader extends PolymerElement {
-  static get template() {
-    return htmlTemplate;
-  }
-
+export class GrFileListHeader extends LitElement {
   /**
    * @event expand-diffs
    */
@@ -112,7 +95,7 @@
   serverConfig?: ServerInfo;
 
   @property({type: Number})
-  shownFileCount?: number;
+  shownFileCount = 0;
 
   @property({type: Object})
   diffPrefs?: DiffPreferencesInfo;
@@ -126,25 +109,273 @@
   @property({type: String})
   filesExpanded?: FilesExpandedState;
 
-  // Caps the number of files that can be shown and have the 'show diffs' /
-  // 'hide diffs' buttons still be functional.
-  @property({type: Number})
-  readonly _maxFilesForBulkActions = 225;
-
   @property({type: Object})
   revisionInfo?: RevisionInfo;
 
+  @query('#modeSelect')
+  modeSelect?: GrDiffModeSelector;
+
+  @query('#expandBtn')
+  expandBtn?: GrButton;
+
+  @query('#collapseBtn')
+  collapseBtn?: GrButton;
+
   private readonly shortcuts = getAppContext().shortcutsService;
 
-  _expandAllDiffs() {
+  // Caps the number of files that can be shown and have the 'show diffs' /
+  // 'hide diffs' buttons still be functional.
+  private readonly maxFilesForBulkActions = 225;
+
+  static override styles = [
+    sharedStyles,
+    css`
+      .prefsButton {
+        float: right;
+      }
+      .patchInfoOldPatchSet.patchInfo-header {
+        background-color: var(--emphasis-color);
+      }
+      .patchInfo-header {
+        align-items: center;
+        display: flex;
+        padding: var(--spacing-s) var(--spacing-l);
+      }
+      .patchInfo-left {
+        align-items: baseline;
+        display: flex;
+      }
+      .patchInfoContent {
+        align-items: center;
+        display: flex;
+        flex-wrap: wrap;
+      }
+      .patchInfo-header .container.latestPatchContainer {
+        display: none;
+      }
+      .patchInfoOldPatchSet .container.latestPatchContainer {
+        display: initial;
+      }
+      .editMode.patchInfoOldPatchSet .container.latestPatchContainer {
+        display: none;
+      }
+      .latestPatchContainer a {
+        text-decoration: none;
+      }
+      .mobile {
+        display: none;
+      }
+      .patchInfo-header .container {
+        align-items: center;
+        display: flex;
+      }
+      .downloadContainer,
+      .uploadContainer {
+        margin-right: 16px;
+      }
+      .uploadContainer.hide {
+        display: none;
+      }
+      .rightControls {
+        align-self: flex-end;
+        margin: auto 0 auto auto;
+        align-items: center;
+        display: flex;
+        flex-wrap: wrap;
+        font-weight: var(--font-weight-normal);
+        justify-content: flex-end;
+      }
+      #collapseBtn,
+      .allExpanded #expandBtn,
+      .fileViewActions {
+        display: none;
+      }
+      .someExpanded #expandBtn {
+        margin-right: 8px;
+      }
+      .someExpanded #collapseBtn,
+      .allExpanded #collapseBtn,
+      .openFile .fileViewActions {
+        align-items: center;
+        display: flex;
+      }
+      .rightControls gr-button,
+      gr-patch-range-select {
+        margin: 0 -4px;
+      }
+      .fileViewActions gr-button {
+        margin: 0;
+        --gr-button-padding: 2px 4px;
+      }
+      .editMode .hideOnEdit {
+        display: none;
+      }
+      .showOnEdit {
+        display: none;
+      }
+      .editMode .showOnEdit {
+        display: initial;
+      }
+      .editMode .showOnEdit.flexContainer {
+        align-items: center;
+        display: flex;
+      }
+      .label {
+        font-weight: var(--font-weight-bold);
+        margin-right: 24px;
+      }
+      gr-commit-info,
+      gr-edit-controls {
+        margin-right: -5px;
+      }
+      .fileViewActionsLabel {
+        margin-right: var(--spacing-xs);
+      }
+      @media screen and (max-width: 50em) {
+        .patchInfo-header .desktop {
+          display: none;
+        }
+      }
+    `,
+  ];
+
+  override render() {
+    if (!this.change || !this.diffPrefs) {
+      return;
+    }
+    const editModeClass = this.computeEditModeClass(this.editMode);
+    const patchInfoClass = this.computePatchInfoClass(
+      this.patchNum,
+      this.allPatchSets
+    );
+    const expandedClass = this.computeExpandedClass(this.filesExpanded);
+    const prefsButtonHidden = this.computePrefsButtonHidden(
+      this.diffPrefs,
+      this.loggedIn
+    );
+    return html`
+      <div class="patchInfo-header ${editModeClass} ${patchInfoClass}">
+        <div class="patchInfo-left">
+          <div class="patchInfoContent">
+            <gr-patch-range-select
+              id="rangeSelect"
+              .changeNum=${this.changeNum}
+              .patchNum=${this.patchNum}
+              .basePatchNum=${this.basePatchNum}
+              .availablePatches=${this.allPatchSets}
+              .revisions=${this.change.revisions}
+              .revisionInfo=${this.revisionInfo}
+              @patch-range-change=${this.handlePatchChange}
+            >
+            </gr-patch-range-select>
+            <span class="separator"></span>
+            <gr-commit-info
+              .change=${this.change}
+              .serverConfig=${this.serverConfig}
+              .commitInfo=${this.commitInfo}
+            ></gr-commit-info>
+            <span class="container latestPatchContainer">
+              <span class="separator"></span>
+              <a href=${ifDefined(this.changeUrl)}>Go to latest patch set</a>
+            </span>
+          </div>
+        </div>
+        <div class="rightControls ${expandedClass}">
+          ${when(
+            this.editMode,
+            () => html`
+              <span class="showOnEdit flexContainer">
+                <gr-edit-controls
+                  id="editControls"
+                  .patchNum=${this.patchNum}
+                  .change=${this.change}
+                ></gr-edit-controls>
+                <span class="separator"></span>
+              </span>
+            `
+          )}
+          <div class="fileViewActions">
+            <span class="fileViewActionsLabel">Diff view:</span>
+            <gr-diff-mode-selector
+              id="modeSelect"
+              .saveOnChange=${this.loggedIn ?? false}
+            ></gr-diff-mode-selector>
+            <span
+              id="diffPrefsContainer"
+              class="hideOnEdit"
+              ?hidden=${prefsButtonHidden}
+            >
+              <gr-tooltip-content has-tooltip title="Diff preferences">
+                <gr-button
+                  link
+                  class="prefsButton desktop"
+                  @click=${this.handlePrefsTap}
+                  ><iron-icon icon="gr-icons:settings"></iron-icon
+                ></gr-button>
+              </gr-tooltip-content>
+            </span>
+            <span class="separator"></span>
+          </div>
+          <span class="downloadContainer desktop">
+            <gr-tooltip-content
+              has-tooltip
+              title=${this.createTitle(
+                Shortcut.OPEN_DOWNLOAD_DIALOG,
+                ShortcutSection.ACTIONS
+              )}
+            >
+              <gr-button link class="download" @click=${this.handleDownloadTap}
+                >Download</gr-button
+              >
+            </gr-tooltip-content>
+          </span>
+          ${when(
+            this.fileListActionsVisible(
+              this.shownFileCount,
+              this.maxFilesForBulkActions
+            ),
+            () => html` <gr-tooltip-content
+                has-tooltip
+                title=${this.createTitle(
+                  Shortcut.TOGGLE_ALL_INLINE_DIFFS,
+                  ShortcutSection.FILE_LIST
+                )}
+              >
+                <gr-button id="expandBtn" link @click=${this.expandAllDiffs}
+                  >Expand All</gr-button
+                >
+              </gr-tooltip-content>
+              <gr-tooltip-content
+                has-tooltip
+                title=${this.createTitle(
+                  Shortcut.TOGGLE_ALL_INLINE_DIFFS,
+                  ShortcutSection.FILE_LIST
+                )}
+              >
+                <gr-button id="collapseBtn" link @click=${this.collapseAllDiffs}
+                  >Collapse All</gr-button
+                >
+              </gr-tooltip-content>`,
+            () => html`
+              <div class="warning">
+                Bulk actions disabled because there are too many files.
+              </div>
+            `
+          )}
+        </div>
+      </div>
+    `;
+  }
+
+  private expandAllDiffs() {
     fireEvent(this, 'expand-diffs');
   }
 
-  _collapseAllDiffs() {
+  private collapseAllDiffs() {
     fireEvent(this, 'collapse-diffs');
   }
 
-  _computeExpandedClass(filesExpanded: FilesExpandedState) {
+  private computeExpandedClass(filesExpanded?: FilesExpandedState) {
     const classes = [];
     if (filesExpanded === FilesExpandedState.ALL) {
       classes.push('openFile');
@@ -156,18 +387,21 @@
     return classes.join(' ');
   }
 
-  _computePrefsButtonHidden(prefs: DiffPreferencesInfo, loggedIn: boolean) {
+  private computePrefsButtonHidden(
+    prefs: DiffPreferencesInfo,
+    loggedIn?: boolean
+  ) {
     return !loggedIn || !prefs;
   }
 
-  _fileListActionsVisible(
+  private fileListActionsVisible(
     shownFileCount: number,
     maxFilesForBulkActions: number
   ) {
     return shownFileCount <= maxFilesForBulkActions;
   }
 
-  _handlePatchChange(e: CustomEvent) {
+  handlePatchChange(e: CustomEvent) {
     const {basePatchNum, patchNum} = e.detail;
     if (
       (basePatchNum === this.basePatchNum && patchNum === this.patchNum) ||
@@ -178,12 +412,12 @@
     GerritNav.navigateToChange(this.change, {patchNum, basePatchNum});
   }
 
-  _handlePrefsTap(e: Event) {
+  private handlePrefsTap(e: Event) {
     e.preventDefault();
     fireEvent(this, 'open-diff-prefs');
   }
 
-  _handleDownloadTap(e: Event) {
+  private handleDownloadTap(e: Event) {
     e.preventDefault();
     e.stopPropagation();
     this.dispatchEvent(
@@ -191,11 +425,11 @@
     );
   }
 
-  _computeEditModeClass(editMode?: boolean) {
+  private computeEditModeClass(editMode?: boolean) {
     return editMode ? 'editMode' : '';
   }
 
-  _computePatchInfoClass(patchNum?: PatchSetNum, allPatchSets?: PatchSet[]) {
+  computePatchInfoClass(patchNum?: PatchSetNum, allPatchSets?: PatchSet[]) {
     const latestNum = computeLatestPatchNum(allPatchSets);
     if (patchNum === latestNum) {
       return '';
@@ -203,7 +437,13 @@
     return 'patchInfoOldPatchSet';
   }
 
-  createTitle(shortcutName: Shortcut, section: ShortcutSection) {
+  private createTitle(shortcutName: Shortcut, section: ShortcutSection) {
     return this.shortcuts.createTitle(shortcutName, section);
   }
 }
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-file-list-header': GrFileListHeader;
+  }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
deleted file mode 100644
index fbba2fc..0000000
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
+++ /dev/null
@@ -1,234 +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.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
-  <style include="shared-styles">
-    .prefsButton {
-      float: right;
-    }
-    .patchInfoOldPatchSet.patchInfo-header {
-      background-color: var(--emphasis-color);
-    }
-    .patchInfo-header {
-      align-items: center;
-      display: flex;
-      padding: var(--spacing-s) var(--spacing-l);
-    }
-    .patchInfo-left {
-      align-items: baseline;
-      display: flex;
-    }
-    .patchInfoContent {
-      align-items: center;
-      display: flex;
-      flex-wrap: wrap;
-    }
-    .patchInfo-header .container.latestPatchContainer {
-      display: none;
-    }
-    .patchInfoOldPatchSet .container.latestPatchContainer {
-      display: initial;
-    }
-    .editMode.patchInfoOldPatchSet .container.latestPatchContainer {
-      display: none;
-    }
-    .latestPatchContainer a {
-      text-decoration: none;
-    }
-    .mobile {
-      display: none;
-    }
-    .patchInfo-header .container {
-      align-items: center;
-      display: flex;
-    }
-    .downloadContainer,
-    .uploadContainer {
-      margin-right: 16px;
-    }
-    .uploadContainer.hide {
-      display: none;
-    }
-    .rightControls {
-      align-self: flex-end;
-      margin: auto 0 auto auto;
-      align-items: center;
-      display: flex;
-      flex-wrap: wrap;
-      font-weight: var(--font-weight-normal);
-      justify-content: flex-end;
-    }
-    #collapseBtn,
-    .allExpanded #expandBtn,
-    .fileViewActions {
-      display: none;
-    }
-    .someExpanded #expandBtn {
-      margin-right: 8px;
-    }
-    .someExpanded #collapseBtn,
-    .allExpanded #collapseBtn,
-    .openFile .fileViewActions {
-      align-items: center;
-      display: flex;
-    }
-    .rightControls gr-button,
-    gr-patch-range-select {
-      margin: 0 -4px;
-    }
-    .fileViewActions gr-button {
-      margin: 0;
-      --gr-button-padding: 2px 4px;
-    }
-    .editMode .hideOnEdit {
-      display: none;
-    }
-    .showOnEdit {
-      display: none;
-    }
-    .editMode .showOnEdit {
-      display: initial;
-    }
-    .editMode .showOnEdit.flexContainer {
-      align-items: center;
-      display: flex;
-    }
-    .label {
-      font-weight: var(--font-weight-bold);
-      margin-right: 24px;
-    }
-    gr-commit-info,
-    gr-edit-controls {
-      margin-right: -5px;
-    }
-    .fileViewActionsLabel {
-      margin-right: var(--spacing-xs);
-    }
-    @media screen and (max-width: 50em) {
-      .patchInfo-header .desktop {
-        display: none;
-      }
-    }
-  </style>
-  <div
-    class$="patchInfo-header [[_computeEditModeClass(editMode)]] [[_computePatchInfoClass(patchNum, allPatchSets)]]"
-  >
-    <div class="patchInfo-left">
-      <div class="patchInfoContent">
-        <gr-patch-range-select
-          id="rangeSelect"
-          change-num="[[changeNum]]"
-          patch-num="[[patchNum]]"
-          base-patch-num="[[basePatchNum]]"
-          available-patches="[[allPatchSets]]"
-          revisions="[[change.revisions]]"
-          revision-info="[[revisionInfo]]"
-          on-patch-range-change="_handlePatchChange"
-        >
-        </gr-patch-range-select>
-        <span class="separator"></span>
-        <gr-commit-info
-          change="[[change]]"
-          server-config="[[serverConfig]]"
-          commit-info="[[commitInfo]]"
-        ></gr-commit-info>
-        <span class="container latestPatchContainer">
-          <span class="separator"></span>
-          <a href$="[[changeUrl]]">Go to latest patch set</a>
-        </span>
-      </div>
-    </div>
-    <div class$="rightControls [[_computeExpandedClass(filesExpanded)]]">
-      <template is="dom-if" if="[[editMode]]">
-        <span class="showOnEdit flexContainer">
-          <gr-edit-controls
-            id="editControls"
-            patch-num="[[patchNum]]"
-            change="[[change]]"
-          ></gr-edit-controls>
-          <span class="separator"></span>
-        </span>
-      </template>
-      <div class="fileViewActions">
-        <span class="fileViewActionsLabel">Diff view:</span>
-        <gr-diff-mode-selector
-          id="modeSelect"
-          save-on-change="[[loggedIn]]"
-        ></gr-diff-mode-selector>
-        <span
-          id="diffPrefsContainer"
-          class="hideOnEdit"
-          hidden$="[[_computePrefsButtonHidden(diffPrefs, loggedIn)]]"
-          hidden=""
-        >
-          <gr-tooltip-content has-tooltip title="Diff preferences">
-            <gr-button
-              link=""
-              class="prefsButton desktop"
-              on-click="_handlePrefsTap"
-              ><iron-icon icon="gr-icons:settings"></iron-icon
-            ></gr-button>
-          </gr-tooltip-content>
-        </span>
-        <span class="separator"></span>
-      </div>
-      <span class="downloadContainer desktop">
-        <gr-tooltip-content
-          has-tooltip
-          title="[[createTitle(Shortcut.OPEN_DOWNLOAD_DIALOG,
-                   ShortcutSection.ACTIONS)]]"
-        >
-          <gr-button link="" class="download" on-click="_handleDownloadTap"
-            >Download</gr-button
-          >
-        </gr-tooltip-content>
-      </span>
-      <template
-        is="dom-if"
-        if="[[_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]"
-      >
-        <gr-tooltip-content
-          has-tooltip
-          title="[[createTitle(Shortcut.TOGGLE_ALL_INLINE_DIFFS,
-                  ShortcutSection.FILE_LIST)]]"
-        >
-          <gr-button id="expandBtn" link="" on-click="_expandAllDiffs"
-            >Expand All</gr-button
-          >
-        </gr-tooltip-content>
-        <gr-tooltip-content
-          has-tooltip
-          title="[[createTitle(Shortcut.TOGGLE_ALL_INLINE_DIFFS,
-                  ShortcutSection.FILE_LIST)]]"
-        >
-          <gr-button id="collapseBtn" link="" on-click="_collapseAllDiffs"
-            >Collapse All</gr-button
-          >
-        </gr-tooltip-content>
-      </template>
-      <template
-        is="dom-if"
-        if="[[!_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]"
-      >
-        <div class="warning">
-          Bulk actions disabled because there are too many files.
-        </div>
-      </template>
-    </div>
-  </div>
-`;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.ts
index 821c7c5..ac2b4d4 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.ts
@@ -19,11 +19,9 @@
 import './gr-file-list-header';
 import {FilesExpandedState} from '../gr-file-list-constants';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
-import 'lodash/lodash';
 import {createChange, createRevision} from '../../../test/test-data-generators';
 import {query, queryAndAssert, stubRestApi} from '../../../test/test-utils';
 import {GrFileListHeader} from './gr-file-list-header';
-import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
 import {
   BasePatchSetNum,
   ChangeId,
@@ -33,19 +31,33 @@
 import {ChangeInfo, ChangeStatus} from '../../../api/rest-api.js';
 import {PatchSet} from '../../../utils/patch-set-util';
 import {createDefaultDiffPrefs} from '../../../constants/constants.js';
-
-const basicFixture = fixtureFromElement('gr-file-list-header');
+import {fixture, html} from '@open-wc/testing-helpers';
+import {GrButton} from '../../shared/gr-button/gr-button';
 
 suite('gr-file-list-header tests', () => {
   let element: GrFileListHeader;
+  const change: ChangeInfo = {
+    ...createChange(),
+    change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca' as ChangeId,
+    revisions: {
+      rev2: createRevision(2),
+      rev1: createRevision(1),
+      rev13: createRevision(13),
+      rev3: createRevision(3),
+    },
+    status: 'NEW' as ChangeStatus,
+    labels: {},
+  };
 
-  setup(() => {
-    stubRestApi('getAccount').returns(Promise.resolve(undefined));
-    element = basicFixture.instantiate();
-  });
-
-  teardown(async () => {
-    await flush();
+  setup(async () => {
+    stubRestApi('getAccount').resolves(undefined);
+    element = await fixture(
+      html`<gr-file-list-header
+        .change=${change}
+        .diffPrefs=${createDefaultDiffPrefs()}
+        .shownFileCount=${3}
+      ></gr-file-list-header>`
+    );
   });
 
   test('Diff preferences hidden when no prefs', async () => {
@@ -55,53 +67,63 @@
 
     element.diffPrefs = createDefaultDiffPrefs();
     element.loggedIn = true;
-    await flush();
+    await element.updateComplete;
+
     assert.isFalse(
       queryAndAssert<HTMLElement>(element, '#diffPrefsContainer').hidden
     );
   });
 
   test('expandAllDiffs called when expand button clicked', async () => {
-    element.shownFileCount = 1;
-    await flush();
-    const expandAllDiffsStub = sinon.stub(element, '_expandAllDiffs');
-    MockInteractions.tap(queryAndAssert(element, '#expandBtn'));
-    assert.isTrue(expandAllDiffsStub.called);
+    const expandDiffsListener = sinon.stub();
+    element.addEventListener('expand-diffs', expandDiffsListener);
+
+    queryAndAssert<GrButton>(element, 'gr-button#expandBtn').click();
+    await element.updateComplete;
+
+    assert.isTrue(expandDiffsListener.called);
   });
 
   test('collapseAllDiffs called when collapse button clicked', async () => {
-    element.shownFileCount = 1;
-    await flush();
-    const collapseAllDiffsStub = sinon.stub(element, '_collapseAllDiffs');
-    MockInteractions.tap(queryAndAssert(element, '#collapseBtn'));
-    assert.isTrue(collapseAllDiffsStub.called);
+    const collapseAllDiffsListener = sinon.stub();
+    element.addEventListener('collapse-diffs', collapseAllDiffsListener);
+
+    queryAndAssert<GrButton>(element, 'gr-button#collapseBtn').click();
+    await element.updateComplete;
+
+    assert.isTrue(collapseAllDiffsListener.called);
   });
 
   test('show/hide diffs disabled for large amounts of files', async () => {
-    const computeSpy = sinon.spy(element, '_fileListActionsVisible');
     element.changeNum = 42 as NumericChangeId;
     element.basePatchNum = 'PARENT' as BasePatchSetNum;
     element.patchNum = '2' as PatchSetNum;
     element.shownFileCount = 1;
-    await flush();
-    assert.isTrue(computeSpy.lastCall.returnValue);
-    _.times(element._maxFilesForBulkActions + 1, () => {
-      element.shownFileCount = element.shownFileCount! + 1;
-    });
-    assert.isFalse(computeSpy.lastCall.returnValue);
+    await element.updateComplete;
+
+    queryAndAssert(element, 'gr-button#expandBtn');
+    queryAndAssert(element, 'gr-button#collapseBtn');
+    assert.isNotOk(query(element, '.warning'));
+
+    element.shownFileCount = 226; // more than element.maxFilesForBulkActions
+    await element.updateComplete;
+
+    assert.isNotOk(query(element, 'gr-button#expandBtn'));
+    assert.isNotOk(query(element, 'gr-button#collapseBtn'));
+    queryAndAssert(element, '.warning');
   });
 
   test('fileViewActions are properly hidden', async () => {
     const actions = queryAndAssert(element, '.fileViewActions');
     assert.equal(getComputedStyle(actions).display, 'none');
     element.filesExpanded = FilesExpandedState.SOME;
-    await flush();
+    await element.updateComplete;
     assert.notEqual(getComputedStyle(actions).display, 'none');
     element.filesExpanded = FilesExpandedState.ALL;
-    await flush();
+    await element.updateComplete;
     assert.notEqual(getComputedStyle(actions).display, 'none');
     element.filesExpanded = FilesExpandedState.NONE;
-    await flush();
+    await element.updateComplete;
     assert.equal(getComputedStyle(actions).display, 'none');
   });
 
@@ -109,7 +131,7 @@
     // Only the expand button should be visible in the initial state when
     // NO files are expanded.
     element.shownFileCount = 10;
-    await flush();
+    await element.updateComplete;
     const expandBtn = queryAndAssert(element, '#expandBtn');
     const collapseBtn = queryAndAssert(element, '#collapseBtn');
     assert.notEqual(getComputedStyle(expandBtn).display, 'none');
@@ -118,46 +140,37 @@
     // Both expand and collapse buttons should be visible when SOME files are
     // expanded.
     element.filesExpanded = FilesExpandedState.SOME;
-    await flush();
+    await element.updateComplete;
     assert.notEqual(getComputedStyle(expandBtn).display, 'none');
     assert.notEqual(getComputedStyle(collapseBtn).display, 'none');
 
     // Only the collapse button should be visible when ALL files are expanded.
     element.filesExpanded = FilesExpandedState.ALL;
-    await flush();
+    await element.updateComplete;
     assert.equal(getComputedStyle(expandBtn).display, 'none');
     assert.notEqual(getComputedStyle(collapseBtn).display, 'none');
 
     // Only the expand button should be visible when NO files are expanded.
     element.filesExpanded = FilesExpandedState.NONE;
-    await flush();
+    await element.updateComplete;
     assert.notEqual(getComputedStyle(expandBtn).display, 'none');
     assert.equal(getComputedStyle(collapseBtn).display, 'none');
   });
 
-  test('navigateToChange called when range select changes', () => {
+  test('navigateToChange called when range select changes', async () => {
     const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange');
-    element.change = {
-      ...createChange(),
-      change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca' as ChangeId,
-      revisions: {
-        rev2: createRevision(2),
-        rev1: createRevision(1),
-        rev13: createRevision(13),
-        rev3: createRevision(3),
-      },
-      status: 'NEW' as ChangeStatus,
-      labels: {},
-    } as ChangeInfo;
     element.basePatchNum = 1 as BasePatchSetNum;
     element.patchNum = 2 as PatchSetNum;
+    await element.updateComplete;
 
-    element._handlePatchChange({
+    element.handlePatchChange({
       detail: {basePatchNum: 1, patchNum: 3},
     } as CustomEvent);
+    await element.updateComplete;
+
     assert.equal(navigateToChangeStub.callCount, 1);
     assert.isTrue(
-      navigateToChangeStub.lastCall.calledWithExactly(element.change, {
+      navigateToChangeStub.lastCall.calledWithExactly(change, {
         patchNum: 3 as PatchSetNum,
         basePatchNum: 1 as BasePatchSetNum,
       })
@@ -171,29 +184,29 @@
       {num: 1 as PatchSetNum, desc: undefined, sha: ''},
     ];
     assert.equal(
-      element._computePatchInfoClass(1 as PatchSetNum, allPatchSets),
+      element.computePatchInfoClass(1 as PatchSetNum, allPatchSets),
       'patchInfoOldPatchSet'
     );
     assert.equal(
-      element._computePatchInfoClass(2 as PatchSetNum, allPatchSets),
+      element.computePatchInfoClass(2 as PatchSetNum, allPatchSets),
       'patchInfoOldPatchSet'
     );
     assert.equal(
-      element._computePatchInfoClass(4 as PatchSetNum, allPatchSets),
+      element.computePatchInfoClass(4 as PatchSetNum, allPatchSets),
       ''
     );
   });
 
   suite('editMode behavior', () => {
-    setup(() => {
+    setup(async () => {
       element.loggedIn = true;
-      element.diffPrefs = createDefaultDiffPrefs();
+      await element.updateComplete;
     });
 
-    const isVisible = (el: HTMLElement) => {
+    function isVisible(el: HTMLElement) {
       assert.ok(el);
       return getComputedStyle(el).getPropertyValue('display') !== 'none';
-    };
+    }
 
     test('patch specific elements', async () => {
       element.editMode = true;
@@ -202,14 +215,14 @@
         {num: 2 as PatchSetNum, desc: undefined, sha: ''},
         {num: 3 as PatchSetNum, desc: undefined, sha: ''},
       ];
-      await flush();
+      await element.updateComplete;
 
       assert.isFalse(
         isVisible(queryAndAssert<HTMLElement>(element, '#diffPrefsContainer'))
       );
 
       element.editMode = false;
-      await flush();
+      await element.updateComplete;
 
       assert.isTrue(
         isVisible(queryAndAssert<HTMLElement>(element, '#diffPrefsContainer'))
@@ -218,27 +231,21 @@
 
     test('edit-controls visibility', async () => {
       element.editMode = false;
-      await flush();
-      // on the first render, when editMode is false, editControls are not
-      // in the DOM to reduce size of DOM and make first render faster.
-      assert.isUndefined(query(element, '#editControls'));
+      await element.updateComplete;
+
+      assert.isNotOk(query(element, '#editControls'));
 
       element.editMode = true;
-      await flush();
-      queryAndAssert<HTMLElement>(element, '#editControls').parentElement;
+      await element.updateComplete;
+
       assert.isTrue(
-        isVisible(
-          queryAndAssert<HTMLElement>(element, '#editControls').parentElement!
-        )
+        isVisible(queryAndAssert<HTMLElement>(element, '#editControls'))
       );
 
       element.editMode = false;
-      await flush();
-      assert.isFalse(
-        isVisible(
-          queryAndAssert<HTMLElement>(element, '#editControls').parentElement!
-        )
-      );
+      await element.updateComplete;
+
+      assert.isNotOk(query<HTMLElement>(element, '#editControls'));
     });
   });
 });