| /** |
| * @license |
| * Copyright 2017 Google LLC |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| import '../../../test/common-test-setup'; |
| import './gr-autocomplete-dropdown'; |
| import { |
| AutocompleteQueryStatusType, |
| GrAutocompleteDropdown, |
| } from './gr-autocomplete-dropdown'; |
| import { |
| pressKey, |
| queryAll, |
| queryAndAssert, |
| waitEventLoop, |
| waitUntil, |
| } from '../../../test/test-utils'; |
| import {assertIsDefined} from '../../../utils/common-util'; |
| import {fixture, html, assert} from '@open-wc/testing'; |
| import {Key} from '../../../utils/dom-util'; |
| |
| suite('gr-autocomplete-dropdown', () => { |
| suite('suggestion tests', () => { |
| let element: GrAutocompleteDropdown; |
| |
| const suggestionsEl = () => queryAndAssert(element, '#suggestions'); |
| |
| setup(async () => { |
| element = await fixture( |
| html`<gr-autocomplete-dropdown></gr-autocomplete-dropdown>` |
| ); |
| element.open(); |
| element.suggestions = [ |
| { |
| dataValue: 'test value 1', |
| name: 'test name 1', |
| text: '1', |
| label: 'hi', |
| }, |
| {dataValue: 'test value 2', name: 'test name 2', text: '2'}, |
| ]; |
| await waitEventLoop(); |
| }); |
| |
| teardown(() => { |
| element.close(); |
| }); |
| |
| test('renders', () => { |
| assert.shadowDom.equal( |
| element, |
| /* HTML */ ` |
| <div class="dropdown-content" id="suggestions" role="listbox"> |
| <ul> |
| <li |
| aria-label="test name 1" |
| class="autocompleteOption selected" |
| data-index="0" |
| data-value="test value 1" |
| role="option" |
| tabindex="-1" |
| > |
| <span> 1 </span> |
| <span class="label"> hi </span> |
| </li> |
| <li |
| aria-label="test name 2" |
| class="autocompleteOption" |
| data-index="1" |
| data-value="test value 2" |
| role="option" |
| tabindex="-1" |
| > |
| <span> 2 </span> |
| <span class="hide label"> </span> |
| </li> |
| </ul> |
| </div> |
| ` |
| ); |
| }); |
| |
| test('shows labels', () => { |
| const els = queryAll<HTMLElement>(suggestionsEl(), 'li'); |
| assert.equal(els[0].innerText.trim(), '1\nhi'); |
| assert.equal(els[1].innerText.trim(), '2'); |
| }); |
| |
| test('escape key close suggestions', async () => { |
| const closeSpy = sinon.spy(element, 'close'); |
| pressKey(element, Key.ESC); |
| await waitEventLoop(); |
| assert.isTrue(closeSpy.called); |
| }); |
| |
| test('tab key', () => { |
| const handleTabSpy = sinon.spy(element, 'handleTab'); |
| const itemSelectedStub = sinon.stub(); |
| element.addEventListener('item-selected', itemSelectedStub); |
| pressKey(element, Key.TAB); |
| assert.isTrue(handleTabSpy.called); |
| assert.equal(element.cursor.index, 0); |
| assert.isTrue(itemSelectedStub.called); |
| assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, { |
| trigger: 'tab', |
| selected: element.getCursorTarget(), |
| }); |
| }); |
| |
| test('enter key', () => { |
| const handleEnterSpy = sinon.spy(element, 'handleEnter'); |
| const itemSelectedStub = sinon.stub(); |
| element.addEventListener('item-selected', itemSelectedStub); |
| pressKey(element, Key.ENTER); |
| assert.isTrue(handleEnterSpy.called); |
| assert.equal(element.cursor.index, 0); |
| assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, { |
| trigger: 'enter', |
| selected: element.getCursorTarget(), |
| }); |
| }); |
| |
| test('down key', () => { |
| element.isHidden = true; |
| const nextSpy = sinon.spy(element.cursor, 'next'); |
| pressKey(element, 'ArrowDown'); |
| assert.isFalse(nextSpy.called); |
| assert.equal(element.cursor.index, 0); |
| element.isHidden = false; |
| pressKey(element, 'ArrowDown'); |
| assert.isTrue(nextSpy.called); |
| assert.equal(element.cursor.index, 1); |
| }); |
| |
| test('up key', () => { |
| element.isHidden = true; |
| const prevSpy = sinon.spy(element.cursor, 'previous'); |
| pressKey(element, 'ArrowUp'); |
| assert.isFalse(prevSpy.called); |
| assert.equal(element.cursor.index, 0); |
| element.isHidden = false; |
| element.cursor.setCursorAtIndex(1); |
| assert.equal(element.cursor.index, 1); |
| pressKey(element, 'ArrowUp'); |
| assert.isTrue(prevSpy.called); |
| assert.equal(element.cursor.index, 0); |
| }); |
| |
| test('tapping selects item', async () => { |
| const itemSelectedStub = sinon.stub(); |
| element.addEventListener('item-selected', itemSelectedStub); |
| |
| suggestionsEl().querySelectorAll('li')[1].click(); |
| await waitEventLoop(); |
| assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, { |
| trigger: 'click', |
| selected: suggestionsEl().querySelectorAll('li')[1], |
| }); |
| }); |
| |
| test('tapping child still selects item', async () => { |
| const itemSelectedStub = sinon.stub(); |
| element.addEventListener('item-selected', itemSelectedStub); |
| const lastElChild = queryAll<HTMLLIElement>(suggestionsEl(), 'li')[0] |
| ?.lastElementChild; |
| assertIsDefined(lastElChild); |
| (lastElChild as HTMLSpanElement).click(); |
| await waitEventLoop(); |
| assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, { |
| trigger: 'click', |
| selected: queryAll<HTMLElement>(suggestionsEl(), 'li')[0], |
| }); |
| }); |
| |
| test('updated suggestions resets cursor stops', async () => { |
| const resetStopsSpy = sinon.spy(element, 'computeCursorStopsAndRefit'); |
| element.suggestions = []; |
| await waitUntil(() => resetStopsSpy.called); |
| }); |
| }); |
| |
| suite('status tests', () => { |
| let element: GrAutocompleteDropdown; |
| |
| setup(async () => { |
| element = await fixture( |
| html`<gr-autocomplete-dropdown></gr-autocomplete-dropdown>` |
| ); |
| element.open(); |
| element.queryStatus = { |
| type: AutocompleteQueryStatusType.ERROR, |
| message: 'Failed query error', |
| }; |
| await waitEventLoop(); |
| }); |
| |
| teardown(() => { |
| element.close(); |
| }); |
| |
| test('renders error', () => { |
| assert.shadowDom.equal( |
| element, |
| /* HTML */ ` |
| <div class="dropdown-content" id="suggestions" role="listbox"> |
| <ul> |
| <li |
| aria-label="autocomplete query status" |
| class="query-status error" |
| tabindex="-1" |
| > |
| <span>Failed query error</span> |
| <span class="label">ERROR</span> |
| </li> |
| </ul> |
| </div> |
| ` |
| ); |
| }); |
| |
| test('renders loading', async () => { |
| element.queryStatus = { |
| type: AutocompleteQueryStatusType.LOADING, |
| message: 'Loading...', |
| }; |
| await waitEventLoop(); |
| assert.shadowDom.equal( |
| element, |
| /* HTML */ ` |
| <div class="dropdown-content" id="suggestions" role="listbox"> |
| <ul> |
| <li |
| aria-label="autocomplete query status" |
| class="query-status loading" |
| tabindex="-1" |
| > |
| <span>Loading...</span> |
| <span class="label"></span> |
| </li> |
| </ul> |
| </div> |
| ` |
| ); |
| }); |
| |
| test('escape key close dropdown with error', async () => { |
| const closeSpy = sinon.spy(element, 'close'); |
| pressKey(element, Key.ESC); |
| await waitEventLoop(); |
| assert.isTrue(closeSpy.called); |
| }); |
| |
| test('tab key when error shown sends no event', () => { |
| const handleTabSpy = sinon.spy(element, 'handleTab'); |
| const itemSelectedStub = sinon.stub(); |
| element.addEventListener('item-selected', itemSelectedStub); |
| pressKey(element, Key.TAB); |
| assert.isTrue(handleTabSpy.called); |
| assert.isFalse(itemSelectedStub.called); |
| }); |
| |
| test('enter key when error shown sends no event', () => { |
| const handleEnterSpy = sinon.spy(element, 'handleEnter'); |
| const itemSelectedStub = sinon.stub(); |
| element.addEventListener('item-selected', itemSelectedStub); |
| pressKey(element, Key.ENTER); |
| assert.isTrue(handleEnterSpy.called); |
| assert.isFalse(itemSelectedStub.called); |
| }); |
| |
| test('up/down disabled when error', () => { |
| const nextSpy = sinon.spy(element.cursor, 'next'); |
| const prevSpy = sinon.spy(element.cursor, 'previous'); |
| pressKey(element, 'ArrowUp'); |
| pressKey(element, 'ArrowDown'); |
| assert.isFalse(nextSpy.called); |
| assert.isFalse(prevSpy.called); |
| }); |
| }); |
| }); |