diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 4615a7378415cf..a198aec1d16960 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -6,301 +6,301 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; import { WebElementWrapper } from './lib/web_element_wrapper'; // @ts-ignore not supported yet import { scrollIntoViewIfNecessary } from './lib/web_element_wrapper/scroll_into_view_if_necessary'; -export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderContext) { - const config = getService('config'); - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const log = getService('log'); - const retry = getService('retry'); - const browser = getService('browser'); - const PageObjects = getPageObjects(['common']); +/** + * wrapper around EuiComboBox interactions + */ +export class ComboBoxService extends FtrService { + private readonly config = this.ctx.getService('config'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly browser = this.ctx.getService('browser'); + private readonly PageObjects = this.ctx.getPageObjects(['common']); - const WAIT_FOR_EXISTS_TIME: number = config.get('timeouts.waitForExists'); + private readonly WAIT_FOR_EXISTS_TIME: number = this.config.get('timeouts.waitForExists'); - // wrapper around EuiComboBox interactions - class ComboBox { - /** - * Finds combobox element and sets specified value - * - * @param comboBoxSelector data-test-subj selector - * @param value option text - */ + /** + * Finds combobox element and sets specified value + * + * @param comboBoxSelector data-test-subj selector + * @param value option text + */ - public async set(comboBoxSelector: string, value: string): Promise { - log.debug(`comboBox.set, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - await this.setElement(comboBox, value); - } + public async set(comboBoxSelector: string, value: string): Promise { + this.log.debug(`comboBox.set, comboBoxSelector: ${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + await this.setElement(comboBox, value); + } - /** - * Clicks option in combobox dropdown - * - * @param isMouseClick if 'true', click will be done with mouse - * @param element element that wraps up option - */ - private async clickOption(isMouseClick: boolean, element: WebElementWrapper): Promise { - // element.click causes scrollIntoView which causes combobox to close, using _webElement.click instead - return isMouseClick ? await element.clickMouseButton() : await element._webElement.click(); - } + /** + * Clicks option in combobox dropdown + * + * @param isMouseClick if 'true', click will be done with mouse + * @param element element that wraps up option + */ + private async clickOption(isMouseClick: boolean, element: WebElementWrapper): Promise { + // element.click causes scrollIntoView which causes combobox to close, using _webElement.click instead + return isMouseClick ? await element.clickMouseButton() : await element._webElement.click(); + } - /** - * Finds combobox element options - * - * @param comboBoxSelector data-test-subj selector - */ - public async getOptions(comboBoxSelector: string) { - const comboBoxElement = await testSubjects.find(comboBoxSelector); - await this.openOptionsList(comboBoxElement); - return await find.allByCssSelector('.euiFilterSelectItem', WAIT_FOR_EXISTS_TIME); - } + /** + * Finds combobox element options + * + * @param comboBoxSelector data-test-subj selector + */ + public async getOptions(comboBoxSelector: string) { + const comboBoxElement = await this.testSubjects.find(comboBoxSelector); + await this.openOptionsList(comboBoxElement); + return await this.find.allByCssSelector('.euiFilterSelectItem', this.WAIT_FOR_EXISTS_TIME); + } - /** - * Sets value for specified combobox element - * - * @param comboBoxElement element that wraps up EuiComboBox - * @param value - */ - public async setElement( - comboBoxElement: WebElementWrapper, - value: string, - options = { clickWithMouse: false } - ): Promise { - log.debug(`comboBox.setElement, value: ${value}`); - const isOptionSelected = await this.isOptionSelected(comboBoxElement, value); + /** + * Sets value for specified combobox element + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param value + */ + public async setElement( + comboBoxElement: WebElementWrapper, + value: string, + options = { clickWithMouse: false } + ): Promise { + this.log.debug(`comboBox.setElement, value: ${value}`); + const isOptionSelected = await this.isOptionSelected(comboBoxElement, value); - if (isOptionSelected) { - return; - } + if (isOptionSelected) { + return; + } - await comboBoxElement.scrollIntoViewIfNecessary(); - await this.setFilterValue(comboBoxElement, value); - await this.openOptionsList(comboBoxElement); + await comboBoxElement.scrollIntoViewIfNecessary(); + await this.setFilterValue(comboBoxElement, value); + await this.openOptionsList(comboBoxElement); - if (value !== undefined) { - const selectOptions = await find.allByCssSelector( - `.euiFilterSelectItem[title^="${value.toString().trim()}"]`, - WAIT_FOR_EXISTS_TIME - ); + if (value !== undefined) { + const selectOptions = await this.find.allByCssSelector( + `.euiFilterSelectItem[title^="${value.toString().trim()}"]`, + this.WAIT_FOR_EXISTS_TIME + ); - if (selectOptions.length > 0) { - await this.clickOption(options.clickWithMouse, selectOptions[0]); - } else { - // if it doesn't find the item which text starts with value, it will choose the first option - const firstOption = await find.byCssSelector('.euiFilterSelectItem', 5000); - await this.clickOption(options.clickWithMouse, firstOption); - } + if (selectOptions.length > 0) { + await this.clickOption(options.clickWithMouse, selectOptions[0]); } else { - const firstOption = await find.byCssSelector('.euiFilterSelectItem'); + // if it doesn't find the item which text starts with value, it will choose the first option + const firstOption = await this.find.byCssSelector('.euiFilterSelectItem', 5000); await this.clickOption(options.clickWithMouse, firstOption); } - await this.closeOptionsList(comboBoxElement); - } - - /** - * Finds combobox element and sets custom value - * It applies changes by pressing Enter key. Sometimes it may lead to auto-submitting a form. - * - * @param comboBoxSelector data-test-subj selector - * @param value option text - */ - public async setCustom(comboBoxSelector: string, value: string): Promise { - log.debug(`comboBox.setCustom, comboBoxSelector: ${comboBoxSelector}, value: ${value}`); - const comboBoxElement = await testSubjects.find(comboBoxSelector); - await this.setFilterValue(comboBoxElement, value); - await PageObjects.common.pressEnterKey(); - await this.closeOptionsList(comboBoxElement); + } else { + const firstOption = await this.find.byCssSelector('.euiFilterSelectItem'); + await this.clickOption(options.clickWithMouse, firstOption); } + await this.closeOptionsList(comboBoxElement); + } - /** - * Finds combobox element and sets filter value - * - * @param comboBoxSelector data-test-subj selector - * @param filterValue text - */ - public async filterOptionsList(comboBoxSelector: string, filterValue: string): Promise { - log.debug( - `comboBox.filterOptionsList, comboBoxSelector: ${comboBoxSelector}, filter: ${filterValue}` - ); - const comboBox = await testSubjects.find(comboBoxSelector); - await this.setFilterValue(comboBox, filterValue); - await this.closeOptionsList(comboBox); - } + /** + * Finds combobox element and sets custom value + * It applies changes by pressing Enter key. Sometimes it may lead to auto-submitting a form. + * + * @param comboBoxSelector data-test-subj selector + * @param value option text + */ + public async setCustom(comboBoxSelector: string, value: string): Promise { + this.log.debug(`comboBox.setCustom, comboBoxSelector: ${comboBoxSelector}, value: ${value}`); + const comboBoxElement = await this.testSubjects.find(comboBoxSelector); + await this.setFilterValue(comboBoxElement, value); + await this.PageObjects.common.pressEnterKey(); + await this.closeOptionsList(comboBoxElement); + } - /** - * Sets new filter value in specified combobox element - * - * @param comboBoxElement element that wraps up EuiComboBox - * @param filterValue text - */ - private async setFilterValue( - comboBoxElement: WebElementWrapper, - filterValue: string - ): Promise { - const input = await comboBoxElement.findByTagName('input'); - await input.clearValue(); - await this.waitForOptionsListLoading(comboBoxElement); - await input.type(filterValue); - await this.waitForOptionsListLoading(comboBoxElement); - } + /** + * Finds combobox element and sets filter value + * + * @param comboBoxSelector data-test-subj selector + * @param filterValue text + */ + public async filterOptionsList(comboBoxSelector: string, filterValue: string): Promise { + this.log.debug( + `comboBox.filterOptionsList, comboBoxSelector: ${comboBoxSelector}, filter: ${filterValue}` + ); + const comboBox = await this.testSubjects.find(comboBoxSelector); + await this.setFilterValue(comboBox, filterValue); + await this.closeOptionsList(comboBox); + } - /** - * Waits options list to be loaded - * - * @param comboBoxElement element that wraps up EuiComboBox - */ - private async waitForOptionsListLoading(comboBoxElement: WebElementWrapper): Promise { - await comboBoxElement.waitForDeletedByCssSelector('.euiLoadingSpinner'); - } + /** + * Sets new filter value in specified combobox element + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param filterValue text + */ + private async setFilterValue( + comboBoxElement: WebElementWrapper, + filterValue: string + ): Promise { + const input = await comboBoxElement.findByTagName('input'); + await input.clearValue(); + await this.waitForOptionsListLoading(comboBoxElement); + await input.type(filterValue); + await this.waitForOptionsListLoading(comboBoxElement); + } - /** - * Returns options list as a single string - * - * @param comboBoxSelector data-test-subj selector - */ - public async getOptionsList(comboBoxSelector: string): Promise { - log.debug(`comboBox.getOptionsList, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - const menu = await retry.try(async () => { - await testSubjects.click(comboBoxSelector); - await this.waitForOptionsListLoading(comboBox); - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); - if (!isOptionsListOpen) { - throw new Error('Combo box options list did not open on click'); - } - return await testSubjects.find('~comboBoxOptionsList'); - }); - const optionsText = await menu.getVisibleText(); - await this.closeOptionsList(comboBox); - return optionsText; - } + /** + * Waits options list to be loaded + * + * @param comboBoxElement element that wraps up EuiComboBox + */ + private async waitForOptionsListLoading(comboBoxElement: WebElementWrapper): Promise { + await comboBoxElement.waitForDeletedByCssSelector('.euiLoadingSpinner'); + } - /** - * Finds combobox element and checks if it has selected options - * - * @param comboBoxSelector data-test-subj selector - */ - public async doesComboBoxHaveSelectedOptions(comboBoxSelector: string): Promise { - log.debug(`comboBox.doesComboBoxHaveSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - const $ = await comboBox.parseDomContent(); - return $('.euiComboBoxPill').toArray().length > 0; - } + /** + * Returns options list as a single string + * + * @param comboBoxSelector data-test-subj selector + */ + public async getOptionsList(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.getOptionsList, comboBoxSelector: ${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + const menu = await this.retry.try(async () => { + await this.testSubjects.click(comboBoxSelector); + await this.waitForOptionsListLoading(comboBox); + const isOptionsListOpen = await this.testSubjects.exists('~comboBoxOptionsList'); + if (!isOptionsListOpen) { + throw new Error('Combo box options list did not open on click'); + } + return await this.testSubjects.find('~comboBoxOptionsList'); + }); + const optionsText = await menu.getVisibleText(); + await this.closeOptionsList(comboBox); + return optionsText; + } - /** - * Returns selected options - * @param comboBoxSelector data-test-subj selector - */ - public async getComboBoxSelectedOptions(comboBoxSelector: string): Promise { - log.debug(`comboBox.getComboBoxSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - const $ = await comboBox.parseDomContent(); - return $('.euiComboBoxPill') - .toArray() - .map((option) => $(option).text()); - } + /** + * Finds combobox element and checks if it has selected options + * + * @param comboBoxSelector data-test-subj selector + */ + public async doesComboBoxHaveSelectedOptions(comboBoxSelector: string): Promise { + this.log.debug( + `comboBox.doesComboBoxHaveSelectedOptions, comboBoxSelector: ${comboBoxSelector}` + ); + const comboBox = await this.testSubjects.find(comboBoxSelector); + const $ = await comboBox.parseDomContent(); + return $('.euiComboBoxPill').toArray().length > 0; + } - /** - * Finds combobox element and clears value in the input field by clicking clear button - * - * @param comboBoxSelector data-test-subj selector - */ - public async clear(comboBoxSelector: string): Promise { - log.debug(`comboBox.clear, comboBoxSelector:${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - await retry.try(async () => { - const clearButtonExists = await this.doesClearButtonExist(comboBox); - if (!clearButtonExists) { - log.debug('Unable to clear comboBox, comboBoxClearButton does not exist'); - return; - } + /** + * Returns selected options + * @param comboBoxSelector data-test-subj selector + */ + public async getComboBoxSelectedOptions(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.getComboBoxSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + const $ = await comboBox.parseDomContent(); + return $('.euiComboBoxPill') + .toArray() + .map((option) => $(option).text()); + } - const clearBtn = await comboBox.findByTestSubject('comboBoxClearButton'); - await clearBtn.click(); + /** + * Finds combobox element and clears value in the input field by clicking clear button + * + * @param comboBoxSelector data-test-subj selector + */ + public async clear(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.clear, comboBoxSelector:${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + await this.retry.try(async () => { + const clearButtonExists = await this.doesClearButtonExist(comboBox); + if (!clearButtonExists) { + this.log.debug('Unable to clear comboBox, comboBoxClearButton does not exist'); + return; + } - const clearButtonStillExists = await this.doesClearButtonExist(comboBox); - if (clearButtonStillExists) { - throw new Error('Failed to clear comboBox'); - } - }); - await this.closeOptionsList(comboBox); - } + const clearBtn = await comboBox.findByTestSubject('comboBoxClearButton'); + await clearBtn.click(); - public async doesClearButtonExist(comboBoxElement: WebElementWrapper): Promise { - const found = await comboBoxElement.findAllByTestSubject( - 'comboBoxClearButton', - WAIT_FOR_EXISTS_TIME - ); - return found.length > 0; - } + const clearButtonStillExists = await this.doesClearButtonExist(comboBox); + if (clearButtonStillExists) { + throw new Error('Failed to clear comboBox'); + } + }); + await this.closeOptionsList(comboBox); + } - public async checkValidity(comboBoxElement: WebElementWrapper): Promise { - const invalidClassName = 'euiComboBox-isInvalid'; + public async doesClearButtonExist(comboBoxElement: WebElementWrapper): Promise { + const found = await comboBoxElement.findAllByTestSubject( + 'comboBoxClearButton', + this.WAIT_FOR_EXISTS_TIME + ); + return found.length > 0; + } - return !(await comboBoxElement.elementHasClass(invalidClassName)); - } + public async checkValidity(comboBoxElement: WebElementWrapper): Promise { + const invalidClassName = 'euiComboBox-isInvalid'; - /** - * Closes options list - * - * @param comboBoxElement element that wraps up EuiComboBox - */ - public async closeOptionsList(comboBoxElement: WebElementWrapper): Promise { - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); - if (isOptionsListOpen) { - const input = await comboBoxElement.findByTagName('input'); - await input.pressKeys(browser.keys.ESCAPE); - } - } + return !(await comboBoxElement.elementHasClass(invalidClassName)); + } - /** - * Opens options list - * - * @param comboBoxElement element that wraps up EuiComboBox - */ - public async openOptionsList(comboBoxElement: WebElementWrapper): Promise { - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); - if (!isOptionsListOpen) { - await retry.try(async () => { - const toggleBtn = await comboBoxElement.findByTestSubject('comboBoxInput'); - await toggleBtn.click(); - }); - } + /** + * Closes options list + * + * @param comboBoxElement element that wraps up EuiComboBox + */ + public async closeOptionsList(comboBoxElement: WebElementWrapper): Promise { + const isOptionsListOpen = await this.testSubjects.exists('~comboBoxOptionsList'); + if (isOptionsListOpen) { + const input = await comboBoxElement.findByTagName('input'); + await input.pressKeys(this.browser.keys.ESCAPE); } + } - /** - * Checks if specified option is already selected - * - * @param comboBoxElement element that wraps up EuiComboBox - * @param value option text - */ - public async isOptionSelected( - comboBoxElement: WebElementWrapper, - value: string - ): Promise { - log.debug(`comboBox.isOptionSelected, value: ${value}`); - const $ = await comboBoxElement.parseDomContent(); - const selectedOptions = $('.euiComboBoxPill') - .toArray() - .map((option) => $(option).text()); - return selectedOptions.length === 1 && selectedOptions[0] === value; + /** + * Opens options list + * + * @param comboBoxElement element that wraps up EuiComboBox + */ + public async openOptionsList(comboBoxElement: WebElementWrapper): Promise { + const isOptionsListOpen = await this.testSubjects.exists('~comboBoxOptionsList'); + if (!isOptionsListOpen) { + await this.retry.try(async () => { + const toggleBtn = await comboBoxElement.findByTestSubject('comboBoxInput'); + await toggleBtn.click(); + }); } + } - /** - * Clears input field - * @param comboBoxSelector data-test-subj selector - */ - public async clearInputField(comboBoxSelector: string): Promise { - log.debug(`comboBox.clearInputField, comboBoxSelector:${comboBoxSelector}`); - const comboBoxElement = await testSubjects.find(comboBoxSelector); - const input = await comboBoxElement.findByTagName('input'); - await input.clearValueWithKeyboard(); - } + /** + * Checks if specified option is already selected + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param value option text + */ + public async isOptionSelected( + comboBoxElement: WebElementWrapper, + value: string + ): Promise { + this.log.debug(`comboBox.isOptionSelected, value: ${value}`); + const $ = await comboBoxElement.parseDomContent(); + const selectedOptions = $('.euiComboBoxPill') + .toArray() + .map((option) => $(option).text()); + return selectedOptions.length === 1 && selectedOptions[0] === value; } - return new ComboBox(); + /** + * Clears input field + * @param comboBoxSelector data-test-subj selector + */ + public async clearInputField(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.clearInputField, comboBoxSelector:${comboBoxSelector}`); + const comboBoxElement = await this.testSubjects.find(comboBoxSelector); + const input = await comboBoxElement.findByTagName('input'); + await input.clearValueWithKeyboard(); + } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 294b68c5488658..03c43ffc302146 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -17,7 +17,7 @@ import { SnapshotsService, TestSubjects, } from './common'; -import { ComboBoxProvider } from './combo_box'; +import { ComboBoxService } from './combo_box'; import { DashboardAddPanelService, DashboardReplacePanelService, @@ -68,7 +68,7 @@ export const services = { dashboardReplacePanel: DashboardReplacePanelService, dashboardPanelActions: DashboardPanelActionsService, flyout: FlyoutService, - comboBox: ComboBoxProvider, + comboBox: ComboBoxService, dataGrid: DataGridService, embedding: EmbeddingProvider, renderable: RenderableProvider,