Convert gr-textarea_test.js to typescript
Change-Id: I87b6035a680ee3c7122fb3b0cee7b65e18bee9fd
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index 4b6eceb..17c46c6 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -33,6 +33,7 @@
Item,
ItemSelectedEvent,
} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
+import {CustomKeyboardEvent} from '../../../types/events';
const MAX_ITEMS_DROPDOWN = 10;
@@ -235,11 +236,14 @@
this._setEmoji(this.$.emojiSuggestions.getCurrentText());
}
- _handleEnterByKey(e: CustomEvent<{keyboardEvent: KeyboardEvent}>) {
+ _handleEnterByKey(e: CustomKeyboardEvent) {
// Enter should have newline behavior if the picker is closed or if the user
// has only typed ':'. Also make sure that shortcuts aren't clobbered.
if (this._hideEmojiAutocomplete || this.disableEnterKeyForSelectingEmoji) {
- if (!e.detail.keyboardEvent.metaKey && !e.detail.keyboardEvent.ctrlKey) {
+ if (
+ !e.detail.keyboardEvent?.metaKey &&
+ !e.detail.keyboardEvent?.ctrlKey
+ ) {
this.indent(e);
}
return;
@@ -414,7 +418,7 @@
);
}
- private indent(e: CustomEvent<{keyboardEvent: KeyboardEvent}>): void {
+ private indent(e: CustomKeyboardEvent): void {
if (!document.queryCommandSupported('insertText')) {
return;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.js b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.js
deleted file mode 100644
index 7c2f209..0000000
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.js
+++ /dev/null
@@ -1,373 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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 '../../../test/common-test-setup-karma.js';
-import './gr-textarea.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromElement('gr-textarea');
-
-const monospaceFixture = fixtureFromTemplate(html`
-<gr-textarea monospace="true"></gr-textarea>
-`);
-
-const hideBorderFixture = fixtureFromTemplate(html`
-<gr-textarea hide-border="true"></gr-textarea>
-`);
-
-suite('gr-textarea tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- sinon.stub(element.reporting, 'reportInteraction');
- });
-
- test('monospace is set properly', () => {
- assert.isFalse(element.classList.contains('monospace'));
- });
-
- test('hideBorder is set properly', () => {
- assert.isFalse(element.$.textarea.classList.contains('noBorder'));
- });
-
- test('emoji selector is not open with the textarea lacks focus', () => {
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 1;
- element.text = ':';
- assert.isFalse(!element.$.emojiSuggestions.isHidden);
- });
-
- test('emoji selector is not open when a general text is entered', () => {
- MockInteractions.focus(element.$.textarea);
- element.$.textarea.selectionStart = 9;
- element.$.textarea.selectionEnd = 9;
- element.text = 'some text';
- assert.isFalse(!element.$.emojiSuggestions.isHidden);
- });
-
- test('emoji selector opens when a colon is typed & the textarea has focus',
- () => {
- MockInteractions.focus(element.$.textarea);
- // Needed for Safari tests. selectionStart is not updated when text is
- // updated.
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 1;
- element.text = ':';
- flush();
- assert.isFalse(element.$.emojiSuggestions.isHidden);
- assert.equal(element._colonIndex, 0);
- assert.isFalse(element._hideEmojiAutocomplete);
- assert.equal(element._currentSearchString, '');
- });
-
- test('emoji selector opens when a colon is typed after space',
- () => {
- MockInteractions.focus(element.$.textarea);
- // Needed for Safari tests. selectionStart is not updated when text is
- // updated.
- element.$.textarea.selectionStart = 2;
- element.$.textarea.selectionEnd = 2;
- element.text = ' :';
- flush();
- assert.isFalse(element.$.emojiSuggestions.isHidden);
- assert.equal(element._colonIndex, 1);
- assert.isFalse(element._hideEmojiAutocomplete);
- assert.equal(element._currentSearchString, '');
- });
-
- test('emoji selector doesn\`t open when a colon is typed after character',
- () => {
- MockInteractions.focus(element.$.textarea);
- // Needed for Safari tests. selectionStart is not updated when text is
- // updated.
- element.$.textarea.selectionStart = 5;
- element.$.textarea.selectionEnd = 5;
- element.text = 'test:';
- flush();
- assert.isTrue(element.$.emojiSuggestions.isHidden);
- assert.isTrue(element._hideEmojiAutocomplete);
- });
-
- test('emoji selector opens when a colon is typed and some substring',
- () => {
- MockInteractions.focus(element.$.textarea);
- // Needed for Safari tests. selectionStart is not updated when text is
- // updated.
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 1;
- element.text = ':';
- element.$.textarea.selectionStart = 2;
- element.$.textarea.selectionEnd = 2;
- element.text = ':t';
- flush();
- assert.isFalse(element.$.emojiSuggestions.isHidden);
- assert.equal(element._colonIndex, 0);
- assert.isFalse(element._hideEmojiAutocomplete);
- assert.equal(element._currentSearchString, 't');
- });
-
- test('emoji selector opens when a colon is typed in middle of text',
- () => {
- MockInteractions.focus(element.$.textarea);
- // Needed for Safari tests. selectionStart is not updated when text is
- // updated.
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 1;
- // Since selectionStart is on Chrome set always on end of text, we
- // stub it to 1
- const text = ': hello';
- sinon.stub(element.$, 'textarea').value( {
- selectionStart: 1,
- value: text,
- textarea: {
- focus: () => {},
- },
- });
- element.text = text;
- flush();
- assert.isFalse(element.$.emojiSuggestions.isHidden);
- assert.equal(element._colonIndex, 0);
- assert.isFalse(element._hideEmojiAutocomplete);
- assert.equal(element._currentSearchString, '');
- });
- test('emoji selector closes when text changes before the colon', () => {
- const resetStub = sinon.stub(element, '_resetEmojiDropdown');
- MockInteractions.focus(element.$.textarea);
- flush();
- element.$.textarea.selectionStart = 10;
- element.$.textarea.selectionEnd = 10;
- element.text = 'test test ';
- element.$.textarea.selectionStart = 12;
- element.$.textarea.selectionEnd = 12;
- element.text = 'test test :';
- element.$.textarea.selectionStart = 15;
- element.$.textarea.selectionEnd = 15;
- element.text = 'test test :smi';
-
- assert.equal(element._currentSearchString, 'smi');
- assert.isFalse(resetStub.called);
- element.text = 'test test test :smi';
- assert.isTrue(resetStub.called);
- });
-
- test('_resetEmojiDropdown', () => {
- const closeSpy = sinon.spy(element, 'closeDropdown');
- element._resetEmojiDropdown();
- assert.equal(element._currentSearchString, '');
- assert.isTrue(element._hideEmojiAutocomplete);
- assert.equal(element._colonIndex, null);
-
- element.$.emojiSuggestions.open();
- flush();
- element._resetEmojiDropdown();
- assert.isTrue(closeSpy.called);
- });
-
- test('_determineSuggestions', () => {
- const emojiText = 'tear';
- const formatSpy = sinon.spy(element, '_formatSuggestions');
- element._determineSuggestions(emojiText);
- assert.isTrue(formatSpy.called);
- assert.isTrue(formatSpy.lastCall.calledWithExactly(
- [{dataValue: '😂', value: '😂', match: 'tears :\')',
- text: '😂 tears :\')'},
- {dataValue: '😢', value: '😢', match: 'tear', text: '😢 tear'},
- ]));
- });
-
- test('_formatSuggestions', () => {
- const matchedSuggestions = [{value: '😢', match: 'tear'},
- {value: '😂', match: 'tears'}];
- element._formatSuggestions(matchedSuggestions);
- assert.deepEqual(
- [{value: '😢', dataValue: '😢', match: 'tear', text: '😢 tear'},
- {value: '😂', dataValue: '😂', match: 'tears', text: '😂 tears'}],
- element._suggestions);
- });
-
- test('_handleEmojiSelect', () => {
- element.$.textarea.selectionStart = 16;
- element.$.textarea.selectionEnd = 16;
- element.text = 'test test :tears';
- element._colonIndex = 10;
- const selectedItem = {dataset: {value: '😂'}};
- const event = {detail: {selected: selectedItem}};
- element._handleEmojiSelect(event);
- assert.equal(element.text, 'test test 😂');
- });
-
- test('_updateCaratPosition', () => {
- element.$.textarea.selectionStart = 4;
- element.$.textarea.selectionEnd = 4;
- element.text = 'test';
- element._updateCaratPosition();
- assert.deepEqual(element.$.hiddenText.innerHTML, element.text +
- element.$.caratSpan.outerHTML);
- });
-
- test('newline receives matching indentation', async () => {
- const indentCommand = sinon.stub(document, 'execCommand');
- element.$.textarea.value = ' a';
- element._handleEnterByKey(
- new CustomEvent('keydown', {detail: {keyboardEvent: {keyCode: 13}}})
- );
- await flush();
- assert.deepEqual(indentCommand.args[0], ['insertText', false, '\n ']);
- });
-
- test('ctrl+enter and meta+enter do not indent', async () => {
- const indentCommand = sinon.stub(document, 'execCommand');
- element.$.textarea.value = ' a';
- element._handleEnterByKey(
- new CustomEvent('keydown', {
- detail: {keyboardEvent: {keyCode: 13, ctrlKey: true}},
- })
- );
- await flush();
- assert.isTrue(indentCommand.notCalled);
-
- element._handleEnterByKey(
- new CustomEvent('keydown', {
- detail: {keyboardEvent: {keyCode: 13, metaKey: true}},
- })
- );
- await flush();
- assert.isTrue(indentCommand.notCalled);
- });
-
- test('emoji dropdown is closed when iron-overlay-closed is fired', () => {
- const resetSpy = sinon.spy(element, '_resetEmojiDropdown');
- element.$.emojiSuggestions.dispatchEvent(
- new CustomEvent('dropdown-closed', {
- composed: true, bubbles: true,
- }));
- assert.isTrue(resetSpy.called);
- });
-
- test('_onValueChanged fires bind-value-changed', () => {
- const listenerStub = sinon.stub();
- const eventObject = {currentTarget: {focused: false}};
- element.addEventListener('bind-value-changed', listenerStub);
- element._onValueChanged(eventObject);
- assert.isTrue(listenerStub.called);
- });
-
- suite('keyboard shortcuts', () => {
- function setupDropdown(callback) {
- MockInteractions.focus(element.$.textarea);
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 1;
- element.text = ':';
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 2;
- element.text = ':1';
- flush();
- }
-
- test('escape key', () => {
- const resetSpy = sinon.spy(element, '_resetEmojiDropdown');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 27);
- assert.isFalse(resetSpy.called);
- setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 27);
- assert.isTrue(resetSpy.called);
- assert.isFalse(!element.$.emojiSuggestions.isHidden);
- });
-
- test('up key', () => {
- const upSpy = sinon.spy(element.$.emojiSuggestions, 'cursorUp');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 38);
- assert.isFalse(upSpy.called);
- setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 38);
- assert.isTrue(upSpy.called);
- });
-
- test('down key', () => {
- const downSpy = sinon.spy(element.$.emojiSuggestions, 'cursorDown');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 40);
- assert.isFalse(downSpy.called);
- setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 40);
- assert.isTrue(downSpy.called);
- });
-
- test('enter key', () => {
- const enterSpy = sinon.spy(element.$.emojiSuggestions,
- 'getCursorTarget');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
- assert.isFalse(enterSpy.called);
- setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
- assert.isTrue(enterSpy.called);
- flush();
- assert.equal(element.text, '💯');
- });
-
- test('enter key - ignored on just colon without more information', () => {
- const enterSpy = sinon.spy(element.$.emojiSuggestions,
- 'getCursorTarget');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
- assert.isFalse(enterSpy.called);
- MockInteractions.focus(element.$.textarea);
- element.$.textarea.selectionStart = 1;
- element.$.textarea.selectionEnd = 1;
- element.text = ':';
- flush();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
- assert.isFalse(enterSpy.called);
- });
- });
-
- suite('gr-textarea monospace', () => {
- // gr-textarea set monospace class in the ready() method.
- // In Polymer2, ready() is called from the fixture(...) method,
- // If ready() is called again later, some nested elements doesn't
- // handle it correctly. A separate test-fixture is used to set
- // properties before ready() is called.
-
- let element;
-
- setup(() => {
- element = monospaceFixture.instantiate();
- });
-
- test('monospace is set properly', () => {
- assert.isTrue(element.classList.contains('monospace'));
- });
- });
-
- suite('gr-textarea hideBorder', () => {
- // gr-textarea set noBorder class in the ready() method.
- // In Polymer2, ready() is called from the fixture(...) method,
- // If ready() is called again later, some nested elements doesn't
- // handle it correctly. A separate test-fixture is used to set
- // properties before ready() is called.
-
- let element;
-
- setup(() => {
- element = hideBorderFixture.instantiate();
- });
-
- test('hideBorder is set properly', () => {
- assert.isTrue(element.$.textarea.classList.contains('noBorder'));
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
new file mode 100644
index 0000000..506c348
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
@@ -0,0 +1,390 @@
+/**
+ * @license
+ * Copyright (C) 2017 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 '../../../test/common-test-setup-karma';
+import './gr-textarea';
+import {GrTextarea} from './gr-textarea';
+import {html} from '@polymer/polymer/lib/utils/html-tag';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import {CustomKeyboardEvent} from '../../../types/events';
+import {ItemSelectedEvent} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
+
+const basicFixture = fixtureFromElement('gr-textarea');
+
+const monospaceFixture = fixtureFromTemplate(html`
+ <gr-textarea monospace="true"></gr-textarea>
+`);
+
+const hideBorderFixture = fixtureFromTemplate(html`
+ <gr-textarea hide-border="true"></gr-textarea>
+`);
+
+suite('gr-textarea tests', () => {
+ let element: GrTextarea;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ sinon.stub(element.reporting, 'reportInteraction');
+ });
+
+ test('monospace is set properly', () => {
+ assert.isFalse(element.classList.contains('monospace'));
+ });
+
+ test('hideBorder is set properly', () => {
+ assert.isFalse(element.$.textarea.classList.contains('noBorder'));
+ });
+
+ test('emoji selector is not open with the textarea lacks focus', () => {
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 1;
+ element.text = ':';
+ assert.isFalse(!element.$.emojiSuggestions.isHidden);
+ });
+
+ test('emoji selector is not open when a general text is entered', () => {
+ MockInteractions.focus(element.$.textarea);
+ element.$.textarea.selectionStart = 9;
+ element.$.textarea.selectionEnd = 9;
+ element.text = 'some text';
+ assert.isFalse(!element.$.emojiSuggestions.isHidden);
+ });
+
+ test('emoji selector opens when a colon is typed & the textarea has focus', () => {
+ MockInteractions.focus(element.$.textarea);
+ // Needed for Safari tests. selectionStart is not updated when text is
+ // updated.
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 1;
+ element.text = ':';
+ flush();
+ assert.isFalse(element.$.emojiSuggestions.isHidden);
+ assert.equal(element._colonIndex, 0);
+ assert.isFalse(element._hideEmojiAutocomplete);
+ assert.equal(element._currentSearchString, '');
+ });
+
+ test('emoji selector opens when a colon is typed after space', () => {
+ MockInteractions.focus(element.$.textarea);
+ // Needed for Safari tests. selectionStart is not updated when text is
+ // updated.
+ element.$.textarea.selectionStart = 2;
+ element.$.textarea.selectionEnd = 2;
+ element.text = ' :';
+ flush();
+ assert.isFalse(element.$.emojiSuggestions.isHidden);
+ assert.equal(element._colonIndex, 1);
+ assert.isFalse(element._hideEmojiAutocomplete);
+ assert.equal(element._currentSearchString, '');
+ });
+
+ test('emoji selector doesn`t open when a colon is typed after character', () => {
+ MockInteractions.focus(element.$.textarea);
+ // Needed for Safari tests. selectionStart is not updated when text is
+ // updated.
+ element.$.textarea.selectionStart = 5;
+ element.$.textarea.selectionEnd = 5;
+ element.text = 'test:';
+ flush();
+ assert.isTrue(element.$.emojiSuggestions.isHidden);
+ assert.isTrue(element._hideEmojiAutocomplete);
+ });
+
+ test('emoji selector opens when a colon is typed and some substring', () => {
+ MockInteractions.focus(element.$.textarea);
+ // Needed for Safari tests. selectionStart is not updated when text is
+ // updated.
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 1;
+ element.text = ':';
+ element.$.textarea.selectionStart = 2;
+ element.$.textarea.selectionEnd = 2;
+ element.text = ':t';
+ flush();
+ assert.isFalse(element.$.emojiSuggestions.isHidden);
+ assert.equal(element._colonIndex, 0);
+ assert.isFalse(element._hideEmojiAutocomplete);
+ assert.equal(element._currentSearchString, 't');
+ });
+
+ test('emoji selector opens when a colon is typed in middle of text', () => {
+ MockInteractions.focus(element.$.textarea);
+ // Needed for Safari tests. selectionStart is not updated when text is
+ // updated.
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 1;
+ // Since selectionStart is on Chrome set always on end of text, we
+ // stub it to 1
+ const text = ': hello';
+ sinon.stub(element.$, 'textarea').value({
+ selectionStart: 1,
+ value: text,
+ textarea: {
+ focus: () => {},
+ },
+ });
+ element.text = text;
+ flush();
+ assert.isFalse(element.$.emojiSuggestions.isHidden);
+ assert.equal(element._colonIndex, 0);
+ assert.isFalse(element._hideEmojiAutocomplete);
+ assert.equal(element._currentSearchString, '');
+ });
+ test('emoji selector closes when text changes before the colon', () => {
+ const resetStub = sinon.stub(element, '_resetEmojiDropdown');
+ MockInteractions.focus(element.$.textarea);
+ flush();
+ element.$.textarea.selectionStart = 10;
+ element.$.textarea.selectionEnd = 10;
+ element.text = 'test test ';
+ element.$.textarea.selectionStart = 12;
+ element.$.textarea.selectionEnd = 12;
+ element.text = 'test test :';
+ element.$.textarea.selectionStart = 15;
+ element.$.textarea.selectionEnd = 15;
+ element.text = 'test test :smi';
+
+ assert.equal(element._currentSearchString, 'smi');
+ assert.isFalse(resetStub.called);
+ element.text = 'test test test :smi';
+ assert.isTrue(resetStub.called);
+ });
+
+ test('_resetEmojiDropdown', () => {
+ const closeSpy = sinon.spy(element, 'closeDropdown');
+ element._resetEmojiDropdown();
+ assert.equal(element._currentSearchString, '');
+ assert.isTrue(element._hideEmojiAutocomplete);
+ assert.equal(element._colonIndex, null);
+
+ element.$.emojiSuggestions.open();
+ flush();
+ element._resetEmojiDropdown();
+ assert.isTrue(closeSpy.called);
+ });
+
+ test('_determineSuggestions', () => {
+ const emojiText = 'tear';
+ const formatSpy = sinon.spy(element, '_formatSuggestions');
+ element._determineSuggestions(emojiText);
+ assert.isTrue(formatSpy.called);
+ assert.isTrue(
+ formatSpy.lastCall.calledWithExactly([
+ {
+ dataValue: '😂',
+ value: '😂',
+ match: "tears :')",
+ text: "😂 tears :')",
+ },
+ {dataValue: '😢', value: '😢', match: 'tear', text: '😢 tear'},
+ ])
+ );
+ });
+
+ test('_formatSuggestions', () => {
+ const matchedSuggestions = [
+ {value: '😢', match: 'tear'},
+ {value: '😂', match: 'tears'},
+ ];
+ element._formatSuggestions(matchedSuggestions);
+ assert.deepEqual(
+ [
+ {value: '😢', dataValue: '😢', match: 'tear', text: '😢 tear'},
+ {value: '😂', dataValue: '😂', match: 'tears', text: '😂 tears'},
+ ],
+ element._suggestions
+ );
+ });
+
+ test('_handleEmojiSelect', () => {
+ element.$.textarea.selectionStart = 16;
+ element.$.textarea.selectionEnd = 16;
+ element.text = 'test test :tears';
+ element._colonIndex = 10;
+ const selectedItem = ({dataset: {value: '😂'}} as unknown) as HTMLElement;
+ const event = new CustomEvent<ItemSelectedEvent>('item-selected', {
+ detail: {trigger: 'click', selected: selectedItem},
+ });
+ element._handleEmojiSelect(event);
+ assert.equal(element.text, 'test test 😂');
+ });
+
+ test('_updateCaratPosition', () => {
+ element.$.textarea.selectionStart = 4;
+ element.$.textarea.selectionEnd = 4;
+ element.text = 'test';
+ element._updateCaratPosition();
+ assert.deepEqual(
+ element.$.hiddenText.innerHTML,
+ element.text + element.$.caratSpan.outerHTML
+ );
+ });
+
+ test('newline receives matching indentation', async () => {
+ const indentCommand = sinon.stub(document, 'execCommand');
+ element.$.textarea.value = ' a';
+ element._handleEnterByKey(
+ new CustomEvent('keydown', {
+ detail: {keyboardEvent: {keyCode: 13}},
+ }) as CustomKeyboardEvent
+ );
+ await flush();
+ assert.deepEqual(indentCommand.args[0], ['insertText', false, '\n ']);
+ });
+
+ test('ctrl+enter and meta+enter do not indent', async () => {
+ const indentCommand = sinon.stub(document, 'execCommand');
+ element.$.textarea.value = ' a';
+ element._handleEnterByKey(
+ new CustomEvent('keydown', {
+ detail: {keyboardEvent: {keyCode: 13, ctrlKey: true}},
+ }) as CustomKeyboardEvent
+ );
+ await flush();
+ assert.isTrue(indentCommand.notCalled);
+
+ element._handleEnterByKey(
+ new CustomEvent('keydown', {
+ detail: {keyboardEvent: {keyCode: 13, metaKey: true}},
+ }) as CustomKeyboardEvent
+ );
+ await flush();
+ assert.isTrue(indentCommand.notCalled);
+ });
+
+ test('emoji dropdown is closed when iron-overlay-closed is fired', () => {
+ const resetSpy = sinon.spy(element, '_resetEmojiDropdown');
+ element.$.emojiSuggestions.dispatchEvent(
+ new CustomEvent('dropdown-closed', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isTrue(resetSpy.called);
+ });
+
+ test('_onValueChanged fires bind-value-changed', () => {
+ const listenerStub = sinon.stub();
+ const eventObject = new CustomEvent('bind-value-changed', {
+ detail: {currentTarget: {focused: false}, value: ''},
+ });
+ element.addEventListener('bind-value-changed', listenerStub);
+ element._onValueChanged(eventObject);
+ assert.isTrue(listenerStub.called);
+ });
+
+ suite('keyboard shortcuts', () => {
+ function setupDropdown() {
+ MockInteractions.focus(element.$.textarea);
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 1;
+ element.text = ':';
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 2;
+ element.text = ':1';
+ flush();
+ }
+
+ test('escape key', () => {
+ const resetSpy = sinon.spy(element, '_resetEmojiDropdown');
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 27);
+ assert.isFalse(resetSpy.called);
+ setupDropdown();
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 27);
+ assert.isTrue(resetSpy.called);
+ assert.isFalse(!element.$.emojiSuggestions.isHidden);
+ });
+
+ test('up key', () => {
+ const upSpy = sinon.spy(element.$.emojiSuggestions, 'cursorUp');
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 38);
+ assert.isFalse(upSpy.called);
+ setupDropdown();
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 38);
+ assert.isTrue(upSpy.called);
+ });
+
+ test('down key', () => {
+ const downSpy = sinon.spy(element.$.emojiSuggestions, 'cursorDown');
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 40);
+ assert.isFalse(downSpy.called);
+ setupDropdown();
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 40);
+ assert.isTrue(downSpy.called);
+ });
+
+ test('enter key', () => {
+ const enterSpy = sinon.spy(element.$.emojiSuggestions, 'getCursorTarget');
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
+ assert.isFalse(enterSpy.called);
+ setupDropdown();
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
+ assert.isTrue(enterSpy.called);
+ flush();
+ assert.equal(element.text, '💯');
+ });
+
+ test('enter key - ignored on just colon without more information', () => {
+ const enterSpy = sinon.spy(element.$.emojiSuggestions, 'getCursorTarget');
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
+ assert.isFalse(enterSpy.called);
+ MockInteractions.focus(element.$.textarea);
+ element.$.textarea.selectionStart = 1;
+ element.$.textarea.selectionEnd = 1;
+ element.text = ':';
+ flush();
+ MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
+ assert.isFalse(enterSpy.called);
+ });
+ });
+
+ suite('gr-textarea monospace', () => {
+ // gr-textarea set monospace class in the ready() method.
+ // In Polymer2, ready() is called from the fixture(...) method,
+ // If ready() is called again later, some nested elements doesn't
+ // handle it correctly. A separate test-fixture is used to set
+ // properties before ready() is called.
+
+ let element: GrTextarea;
+
+ setup(() => {
+ element = monospaceFixture.instantiate() as GrTextarea;
+ });
+
+ test('monospace is set properly', () => {
+ assert.isTrue(element.classList.contains('monospace'));
+ });
+ });
+
+ suite('gr-textarea hideBorder', () => {
+ // gr-textarea set noBorder class in the ready() method.
+ // In Polymer2, ready() is called from the fixture(...) method,
+ // If ready() is called again later, some nested elements doesn't
+ // handle it correctly. A separate test-fixture is used to set
+ // properties before ready() is called.
+
+ let element: GrTextarea;
+
+ setup(() => {
+ element = hideBorderFixture.instantiate() as GrTextarea;
+ });
+
+ test('hideBorder is set properly', () => {
+ assert.isTrue(element.$.textarea.classList.contains('noBorder'));
+ });
+ });
+});