Merge "Migrate gr-dialog to Lit."
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
index 96a19e0..aa76347 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
@@ -128,7 +128,7 @@
// Open confirmation dialog and tap confirm button.
await element.$.confirmDeleteOverlay.open();
- MockInteractions.tap(element.$.confirmDeleteDialog.$.confirm);
+ MockInteractions.tap(element.$.confirmDeleteDialog.confirmButton);
flush();
assert.isTrue(deleteStub.calledWithExactly('-is:open'));
assert.isTrue(element.$.confirmDeleteDialog.disabled);
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
index 1256cc1..3df997f8 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
@@ -123,10 +123,11 @@
test('cherry pick topic submit', async () => {
element.branch = 'master';
+ await flush();
const executeChangeActionStub = stubRestApi(
'executeChangeAction').returns(Promise.resolve([]));
MockInteractions.tap(element.shadowRoot.
- querySelector('gr-dialog').$.confirm);
+ querySelector('gr-dialog').confirmButton);
await flush();
const args = executeChangeActionStub.args[0];
assert.equal(args[0], 1);
@@ -137,26 +138,29 @@
assert.isTrue(args[4].allow_empty);
});
- test('deselecting a change removes it from being cherry picked', () => {
- const duplicateChangesStub = sinon.stub(element,
- 'containsDuplicateProject');
- element.branch = 'master';
- const executeChangeActionStub = stubRestApi(
- 'executeChangeAction').returns(Promise.resolve([]));
- const checkboxes = element.shadowRoot.querySelectorAll(
- 'input[type="checkbox"]');
- assert.equal(checkboxes.length, 2);
- assert.isTrue(checkboxes[0].checked);
- MockInteractions.tap(checkboxes[0]);
- MockInteractions.tap(element.shadowRoot.
- querySelector('gr-dialog').$.confirm);
- flush();
- assert.equal(executeChangeActionStub.callCount, 1);
- assert.isTrue(duplicateChangesStub.called);
- });
+ test('deselecting a change removes it from being cherry picked',
+ async () => {
+ const duplicateChangesStub = sinon.stub(element,
+ 'containsDuplicateProject');
+ element.branch = 'master';
+ await flush();
+ const executeChangeActionStub = stubRestApi(
+ 'executeChangeAction').returns(Promise.resolve([]));
+ const checkboxes = element.shadowRoot.querySelectorAll(
+ 'input[type="checkbox"]');
+ assert.equal(checkboxes.length, 2);
+ assert.isTrue(checkboxes[0].checked);
+ MockInteractions.tap(checkboxes[0]);
+ MockInteractions.tap(element.shadowRoot.
+ querySelector('gr-dialog').confirmButton);
+ await flush();
+ assert.equal(executeChangeActionStub.callCount, 1);
+ assert.isTrue(duplicateChangesStub.called);
+ });
- test('deselecting all change shows error message', () => {
+ test('deselecting all change shows error message', async () => {
element.branch = 'master';
+ await flush();
const executeChangeActionStub = stubRestApi(
'executeChangeAction').returns(Promise.resolve([]));
const checkboxes = element.shadowRoot.querySelectorAll(
@@ -165,8 +169,8 @@
MockInteractions.tap(checkboxes[0]);
MockInteractions.tap(checkboxes[1]);
MockInteractions.tap(element.shadowRoot.
- querySelector('gr-dialog').$.confirm);
- flush();
+ querySelector('gr-dialog').confirmButton);
+ await flush();
assert.equal(executeChangeActionStub.callCount, 0);
assert.equal(element.shadowRoot.querySelector('.error-message').innerText
, 'No change selected');
@@ -180,8 +184,8 @@
});
test('submit button is blocked while cherry picks is running', async () => {
- const confirmButton = element.shadowRoot.querySelector('gr-dialog').$
- .confirm;
+ const confirmButton = element.shadowRoot.querySelector('gr-dialog')
+ .confirmButton;
assert.isTrue(confirmButton.hasAttribute('disabled'));
element.branch = 'b';
await flush();
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
index 2dec8d2..c51988e 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
@@ -26,15 +26,16 @@
suite('gr-error-dialog tests', () => {
let element: GrErrorDialog;
- setup(() => {
+ setup(async () => {
element = basicFixture.instantiate();
+ await flush();
});
test('dismiss tap fires event', async () => {
const dismissCalled = mockPromise();
element.addEventListener('dismiss', () => dismissCalled.resolve());
MockInteractions.tap(
- (queryAndAssert(element, '#dialog') as GrDialog).$.confirm
+ (queryAndAssert(element, '#dialog') as GrDialog).confirmButton!
);
await dismissCalled;
});
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
index 2e1fc21..0ba68e2 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
@@ -76,33 +76,33 @@
assert.isTrue(element._isValidPath('test.js'));
});
- test('open', () => {
+ test('open', async () => {
assert.isFalse(hideDialogStub.called);
MockInteractions.tap(queryAndAssert(element, '#open'));
element.patchNum = 1 as PatchSetNum;
- return showDialogSpy.lastCall.returnValue.then(() => {
- assert.isTrue(hideDialogStub.called);
- assert.isTrue(element.$.openDialog.disabled);
- assert.isFalse(queryStub.called);
- // Setup _focused manually - in headless mode Chrome sometimes don't
- // setup focus. flush and/or flushAsynchronousOperations don't help
- openAutoComplete._focused = true;
- openAutoComplete.noDebounce = true;
- openAutoComplete.text = 'src/test.cpp';
- assert.isTrue(queryStub.called);
- assert.isFalse(element.$.openDialog.disabled);
- MockInteractions.tap(
- queryAndAssert(element.$.openDialog, 'gr-button[primary]')
- );
- assert.isTrue(editDiffStub.called);
- assert.isTrue(navStub.called);
- assert.deepEqual(editDiffStub.lastCall.args, [
- element.change,
- 'src/test.cpp',
- element.patchNum,
- ]);
- assert.isTrue(closeDialogSpy.called);
- });
+ await showDialogSpy.lastCall.returnValue;
+ assert.isTrue(hideDialogStub.called);
+ assert.isTrue(element.$.openDialog.disabled);
+ assert.isFalse(queryStub.called);
+ // Setup _focused manually - in headless mode Chrome sometimes don't
+ // setup focus. flush and/or flushAsynchronousOperations don't help
+ openAutoComplete._focused = true;
+ openAutoComplete.noDebounce = true;
+ openAutoComplete.text = 'src/test.cpp';
+ await flush();
+ assert.isTrue(queryStub.called);
+ assert.isFalse(element.$.openDialog.disabled);
+ MockInteractions.tap(
+ queryAndAssert(element.$.openDialog, 'gr-button[primary]')
+ );
+ assert.isTrue(editDiffStub.called);
+ assert.isTrue(navStub.called);
+ assert.deepEqual(editDiffStub.lastCall.args, [
+ element.change,
+ 'src/test.cpp',
+ element.patchNum,
+ ]);
+ assert.isTrue(closeDialogSpy.called);
});
test('cancel', () => {
@@ -133,59 +133,56 @@
element.$.deleteDialog!.querySelector('gr-autocomplete')!;
});
- test('delete', () => {
+ test('delete', async () => {
deleteStub.returns(Promise.resolve({ok: true}));
MockInteractions.tap(queryAndAssert(element, '#delete'));
- return showDialogSpy.lastCall.returnValue.then(() => {
- assert.isTrue(element.$.deleteDialog.disabled);
- assert.isFalse(queryStub.called);
- // Setup _focused manually - in headless mode Chrome sometimes don't
- // setup focus. flush and/or flushAsynchronousOperations don't help
- deleteAutocomplete._focused = true;
- deleteAutocomplete.noDebounce = true;
- deleteAutocomplete.text = 'src/test.cpp';
- assert.isTrue(queryStub.called);
- assert.isFalse(element.$.deleteDialog.disabled);
- MockInteractions.tap(
- queryAndAssert(element.$.deleteDialog, 'gr-button[primary]')
- );
- flush();
+ await showDialogSpy.lastCall.returnValue;
+ assert.isTrue(element.$.deleteDialog.disabled);
+ assert.isFalse(queryStub.called);
+ // Setup _focused manually - in headless mode Chrome sometimes don't
+ // setup focus. flush and/or flushAsynchronousOperations don't help
+ deleteAutocomplete._focused = true;
+ deleteAutocomplete.noDebounce = true;
+ deleteAutocomplete.text = 'src/test.cpp';
+ await flush();
+ assert.isTrue(queryStub.called);
+ assert.isFalse(element.$.deleteDialog.disabled);
+ MockInteractions.tap(
+ queryAndAssert(element.$.deleteDialog, 'gr-button[primary]')
+ );
+ await flush();
- assert.isTrue(deleteStub.called);
-
- return deleteStub.lastCall.returnValue.then(() => {
- assert.equal(element._path, '');
- assert.isTrue(navStub.called);
- assert.isTrue(closeDialogSpy.called);
- });
- });
+ assert.isTrue(deleteStub.called);
+ await deleteStub.lastCall.returnValue;
+ assert.equal(element._path, '');
+ assert.isTrue(navStub.called);
+ assert.isTrue(closeDialogSpy.called);
});
- test('delete fails', () => {
+ test('delete fails', async () => {
deleteStub.returns(Promise.resolve({ok: false}));
MockInteractions.tap(queryAndAssert(element, '#delete'));
- return showDialogSpy.lastCall.returnValue.then(() => {
- assert.isTrue(element.$.deleteDialog.disabled);
- assert.isFalse(queryStub.called);
- // Setup _focused manually - in headless mode Chrome sometimes don't
- // setup focus. flush and/or flushAsynchronousOperations don't help
- deleteAutocomplete._focused = true;
- deleteAutocomplete.noDebounce = true;
- deleteAutocomplete.text = 'src/test.cpp';
- assert.isTrue(queryStub.called);
- assert.isFalse(element.$.deleteDialog.disabled);
- MockInteractions.tap(
- queryAndAssert(element.$.deleteDialog, 'gr-button[primary]')
- );
- flush();
+ await showDialogSpy.lastCall.returnValue;
+ assert.isTrue(element.$.deleteDialog.disabled);
+ assert.isFalse(queryStub.called);
+ // Setup _focused manually - in headless mode Chrome sometimes don't
+ // setup focus. flush and/or flushAsynchronousOperations don't help
+ deleteAutocomplete._focused = true;
+ deleteAutocomplete.noDebounce = true;
+ deleteAutocomplete.text = 'src/test.cpp';
+ await flush();
+ assert.isTrue(queryStub.called);
+ assert.isFalse(element.$.deleteDialog.disabled);
+ MockInteractions.tap(
+ queryAndAssert(element.$.deleteDialog, 'gr-button[primary]')
+ );
+ await flush();
- assert.isTrue(deleteStub.called);
+ assert.isTrue(deleteStub.called);
- return deleteStub.lastCall.returnValue.then(() => {
- assert.isFalse(navStub.called);
- assert.isFalse(closeDialogSpy.called);
- });
- });
+ await deleteStub.lastCall.returnValue;
+ assert.isFalse(navStub.called);
+ assert.isFalse(closeDialogSpy.called);
});
test('cancel', () => {
@@ -217,67 +214,66 @@
element.$.renameDialog!.querySelector('gr-autocomplete')!;
});
- test('rename', () => {
+ test('rename', async () => {
renameStub.returns(Promise.resolve({ok: true}));
MockInteractions.tap(queryAndAssert(element, '#rename'));
- return showDialogSpy.lastCall.returnValue.then(() => {
- assert.isTrue(element.$.renameDialog.disabled);
- assert.isFalse(queryStub.called);
- // Setup _focused manually - in headless mode Chrome sometimes don't
- // setup focus. flush and/or flushAsynchronousOperations don't help
- renameAutocomplete._focused = true;
- renameAutocomplete.noDebounce = true;
- renameAutocomplete.text = 'src/test.cpp';
- assert.isTrue(queryStub.called);
- assert.isTrue(element.$.renameDialog.disabled);
+ await showDialogSpy.lastCall.returnValue;
+ assert.isTrue(element.$.renameDialog.disabled);
+ assert.isFalse(queryStub.called);
+ // Setup _focused manually - in headless mode Chrome sometimes don't
+ // setup focus. flush and/or flushAsynchronousOperations don't help
+ renameAutocomplete._focused = true;
+ renameAutocomplete.noDebounce = true;
+ renameAutocomplete.text = 'src/test.cpp';
+ await flush();
+ assert.isTrue(queryStub.called);
+ assert.isTrue(element.$.renameDialog.disabled);
- element.$.newPathIronInput.bindValue = 'src/test.newPath';
+ element.$.newPathIronInput.bindValue = 'src/test.newPath';
+ await flush();
- assert.isFalse(element.$.renameDialog.disabled);
- MockInteractions.tap(
- queryAndAssert(element.$.renameDialog, 'gr-button[primary]')
- );
- flush();
+ assert.isFalse(element.$.renameDialog.disabled);
+ MockInteractions.tap(
+ queryAndAssert(element.$.renameDialog, 'gr-button[primary]')
+ );
+ await flush();
+ assert.isTrue(renameStub.called);
- assert.isTrue(renameStub.called);
-
- return renameStub.lastCall.returnValue.then(() => {
- assert.equal(element._path, '');
- assert.isTrue(navStub.called);
- assert.isTrue(closeDialogSpy.called);
- });
- });
+ await renameStub.lastCall.returnValue;
+ assert.equal(element._path, '');
+ assert.isTrue(navStub.called);
+ assert.isTrue(closeDialogSpy.called);
});
- test('rename fails', () => {
+ test('rename fails', async () => {
renameStub.returns(Promise.resolve({ok: false}));
MockInteractions.tap(queryAndAssert(element, '#rename'));
- return showDialogSpy.lastCall.returnValue.then(() => {
- assert.isTrue(element.$.renameDialog.disabled);
- assert.isFalse(queryStub.called);
- // Setup _focused manually - in headless mode Chrome sometimes don't
- // setup focus. flush and/or flushAsynchronousOperations don't help
- renameAutocomplete._focused = true;
- renameAutocomplete.noDebounce = true;
- renameAutocomplete.text = 'src/test.cpp';
- assert.isTrue(queryStub.called);
- assert.isTrue(element.$.renameDialog.disabled);
+ await showDialogSpy.lastCall.returnValue;
+ assert.isTrue(element.$.renameDialog.disabled);
+ assert.isFalse(queryStub.called);
+ // Setup _focused manually - in headless mode Chrome sometimes don't
+ // setup focus. flush and/or flushAsynchronousOperations don't help
+ renameAutocomplete._focused = true;
+ renameAutocomplete.noDebounce = true;
+ renameAutocomplete.text = 'src/test.cpp';
+ await flush();
+ assert.isTrue(queryStub.called);
+ assert.isTrue(element.$.renameDialog.disabled);
- element.$.newPathIronInput.bindValue = 'src/test.newPath';
+ element.$.newPathIronInput.bindValue = 'src/test.newPath';
+ await flush();
- assert.isFalse(element.$.renameDialog.disabled);
- MockInteractions.tap(
- queryAndAssert(element.$.renameDialog, 'gr-button[primary]')
- );
- flush();
+ assert.isFalse(element.$.renameDialog.disabled);
+ MockInteractions.tap(
+ queryAndAssert(element.$.renameDialog, 'gr-button[primary]')
+ );
+ await flush();
- assert.isTrue(renameStub.called);
+ assert.isTrue(renameStub.called);
- return renameStub.lastCall.returnValue.then(() => {
- assert.isFalse(navStub.called);
- assert.isFalse(closeDialogSpy.called);
- });
- });
+ await renameStub.lastCall.returnValue;
+ assert.isFalse(navStub.called);
+ assert.isFalse(closeDialogSpy.called);
});
test('cancel', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index 74e34a0..97ee39e 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -15,12 +15,11 @@
* limitations under the License.
*/
import '../gr-button/gr-button';
-import '../../../styles/gr-font-styles';
-import '../../../styles/shared-styles';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-dialog_html';
-import {customElement, property, observe} from '@polymer/decorators';
+import {customElement, property, query} from 'lit/decorators';
import {GrButton} from '../gr-button/gr-button';
+import {css, html, LitElement, PropertyValues} from 'lit';
+import {sharedStyles} from '../../../styles/shared-styles';
+import {fontStyles} from '../../../styles/gr-font-styles';
declare global {
interface HTMLElementTagNameMap {
@@ -28,18 +27,8 @@
}
}
-export interface GrDialog {
- $: {
- confirm: GrButton;
- };
-}
-
@customElement('gr-dialog')
-export class GrDialog extends PolymerElement {
- static get template() {
- return htmlTemplate;
- }
-
+export class GrDialog extends LitElement {
/**
* Fired when the confirm button is pressed.
*
@@ -52,33 +41,132 @@
* @event cancel
*/
- @property({type: String})
+ @query('#confirm')
+ confirmButton?: GrButton;
+
+ @property({type: String, attribute: 'confirm-label'})
confirmLabel = 'Confirm';
// Supplying an empty cancel label will hide the button completely.
- @property({type: String})
+ @property({type: String, attribute: 'cancel-label'})
cancelLabel = 'Cancel';
@property({type: Boolean})
disabled = false;
- @property({type: Boolean})
+ @property({type: Boolean, attribute: 'confirm-on-enter'})
confirmOnEnter = false;
- @property({type: String})
+ @property({type: String, attribute: 'confirm-tooltip'})
confirmTooltip?: string;
- override ready() {
- super.ready();
- this._ensureAttribute('role', 'dialog');
+ override firstUpdated(changedProperties: PropertyValues) {
+ super.firstUpdated(changedProperties);
+ if (!this.getAttribute('role')) this.setAttribute('role', 'dialog');
}
- @observe('confirmTooltip')
- _handleConfirmTooltipUpdate(confirmTooltip?: string) {
- if (confirmTooltip) {
- this.$.confirm.setAttribute('has-tooltip', 'true');
+ static override get styles() {
+ return [
+ sharedStyles,
+ fontStyles,
+ css`
+ :host {
+ color: var(--primary-text-color);
+ display: block;
+ max-height: 90vh;
+ overflow: auto;
+ }
+ .container {
+ display: flex;
+ flex-direction: column;
+ max-height: 90vh;
+ padding: var(--spacing-xl);
+ }
+ header {
+ flex-shrink: 0;
+ padding-bottom: var(--spacing-xl);
+ }
+ main {
+ display: flex;
+ flex-shrink: 1;
+ width: 100%;
+ flex: 1;
+ /* IMPORTANT: required for firefox */
+ min-height: 0px;
+ }
+ main .overflow-container {
+ flex: 1;
+ overflow: auto;
+ }
+ footer {
+ display: flex;
+ flex-shrink: 0;
+ justify-content: flex-end;
+ padding-top: var(--spacing-xl);
+ }
+ gr-button {
+ margin-left: var(--spacing-l);
+ }
+ .hidden {
+ display: none;
+ }
+ `,
+ ];
+ }
+
+ override render() {
+ // Note that we are using (e: Event) => this._handleKeyDown because the
+ // tests mock out _handleKeydown so the lookup needs to be dynamic, not
+ // bound statically here.
+ return html`
+ <div
+ class="container"
+ @keydown=${(e: KeyboardEvent) => this._handleKeydown(e)}
+ >
+ <header class="heading-3"><slot name="header"></slot></header>
+ <main>
+ <div class="overflow-container">
+ <slot name="main"></slot>
+ </div>
+ </main>
+ <footer>
+ <slot name="footer"></slot>
+ <gr-button
+ id="cancel"
+ class="${this.cancelLabel.length ? '' : 'hidden'}"
+ link
+ @click=${(e: Event) => this.handleCancelTap(e)}
+ >
+ ${this.cancelLabel}
+ </gr-button>
+ <gr-button
+ id="confirm"
+ link
+ primary
+ @click=${(e: Event) => this._handleConfirm(e)}
+ ?disabled=${this.disabled}
+ title=${this.confirmTooltip ?? ''}
+ >
+ ${this.confirmLabel}
+ </gr-button>
+ </footer>
+ </div>
+ `;
+ }
+
+ override updated(changedProperties: PropertyValues) {
+ if (changedProperties.has('confirmTooltip')) {
+ this.updateTooltip();
+ }
+ }
+
+ private updateTooltip() {
+ const confirmButton = this.confirmButton;
+ if (!confirmButton) return;
+ if (this.confirmTooltip) {
+ confirmButton.setAttribute('has-tooltip', 'true');
} else {
- this.$.confirm.removeAttribute('has-tooltip');
+ confirmButton.removeAttribute('has-tooltip');
}
}
@@ -97,7 +185,7 @@
);
}
- _handleCancelTap(e: Event) {
+ private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
this.dispatchEvent(
@@ -115,10 +203,6 @@
}
resetFocus() {
- this.$.confirm.focus();
- }
-
- _computeCancelClass(cancelLabel: string) {
- return cancelLabel.length ? '' : 'hidden';
+ this.confirmButton!.focus();
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
deleted file mode 100644
index a5cf8f1..0000000
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
+++ /dev/null
@@ -1,94 +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="gr-font-styles">
- /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
- </style>
- <style include="shared-styles">
- :host {
- color: var(--primary-text-color);
- display: block;
- max-height: 90vh;
- overflow: auto;
- }
- .container {
- display: flex;
- flex-direction: column;
- max-height: 90vh;
- padding: var(--spacing-xl);
- }
- header {
- flex-shrink: 0;
- padding-bottom: var(--spacing-xl);
- }
- main {
- display: flex;
- flex-shrink: 1;
- width: 100%;
- flex: 1;
- /* IMPORTANT: required for firefox */
- min-height: 0px;
- }
- main .overflow-container {
- flex: 1;
- overflow: auto;
- }
- footer {
- display: flex;
- flex-shrink: 0;
- justify-content: flex-end;
- padding-top: var(--spacing-xl);
- }
- gr-button {
- margin-left: var(--spacing-l);
- }
- .hidden {
- display: none;
- }
- </style>
- <div class="container" on-keydown="_handleKeydown">
- <header class="heading-3"><slot name="header"></slot></header>
- <main>
- <div class="overflow-container">
- <slot name="main"></slot>
- </div>
- </main>
- <footer>
- <slot name="footer"></slot>
- <gr-button
- id="cancel"
- class$="[[_computeCancelClass(cancelLabel)]]"
- link=""
- on-click="_handleCancelTap"
- >
- [[cancelLabel]]
- </gr-button>
- <gr-button
- id="confirm"
- link=""
- primary=""
- on-click="_handleConfirm"
- disabled="[[disabled]]"
- title$="[[confirmTooltip]]"
- >
- [[confirmLabel]]
- </gr-button>
- </footer>
- </div>
-`;
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts
index e7b7130..171fc6c 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts
@@ -17,6 +17,7 @@
import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
import '../../../test/common-test-setup-karma';
+import './gr-dialog';
import {GrDialog} from './gr-dialog';
import {isHidden, queryAndAssert} from '../../../test/test-utils';
@@ -25,8 +26,9 @@
suite('gr-dialog tests', () => {
let element: GrDialog;
- setup(() => {
+ setup(async () => {
element = basicFixture.instantiate();
+ await element.updateComplete;
});
test('events', () => {
@@ -42,56 +44,59 @@
assert.equal(cancel.callCount, 1);
});
- test('confirmOnEnter', () => {
+ test('confirmOnEnter', async () => {
element.confirmOnEnter = false;
+ await element.updateComplete;
const handleConfirmStub = sinon.stub(element, '_handleConfirm');
const handleKeydownSpy = sinon.spy(element, '_handleKeydown');
- MockInteractions.pressAndReleaseKeyOn(
+ MockInteractions.keyDownOn(
queryAndAssert(element, 'main'),
13,
null,
'enter'
);
- flush();
+ await flush();
assert.isTrue(handleKeydownSpy.called);
assert.isFalse(handleConfirmStub.called);
element.confirmOnEnter = true;
- MockInteractions.pressAndReleaseKeyOn(
+ await element.updateComplete;
+
+ MockInteractions.keyDownOn(
queryAndAssert(element, 'main'),
13,
null,
'enter'
);
- flush();
+ await flush();
assert.isTrue(handleConfirmStub.called);
});
test('resetFocus', () => {
- const focusStub = sinon.stub(element.$.confirm, 'focus');
+ const focusStub = sinon.stub(element.confirmButton!, 'focus');
element.resetFocus();
assert.isTrue(focusStub.calledOnce);
});
suite('tooltip', () => {
test('tooltip not added by default', () => {
- assert.isNull(element.$.confirm.getAttribute('has-tooltip'));
+ assert.isNull(element.confirmButton!.getAttribute('has-tooltip'));
});
- test('tooltip added if confirm tooltip is passed', () => {
+ test('tooltip added if confirm tooltip is passed', async () => {
element.confirmTooltip = 'confirm tooltip';
- flush();
- assert(element.$.confirm.getAttribute('has-tooltip'));
+ await element.updateComplete;
+ assert(element.confirmButton!.getAttribute('has-tooltip'));
});
});
- test('empty cancel label hides cancel btn', () => {
+ test('empty cancel label hides cancel btn', async () => {
const cancelButton = queryAndAssert(element, '#cancel');
assert.isFalse(isHidden(cancelButton));
element.cancelLabel = '';
- flush();
+ await element.updateComplete;
assert.isTrue(isHidden(cancelButton));
});