diff --git a/test/functional/apps/visualize/_tag_cloud.js b/test/functional/apps/visualize/_tag_cloud.js index 998019c98c1d819..4ed95214550c15b 100644 --- a/test/functional/apps/visualize/_tag_cloud.js +++ b/test/functional/apps/visualize/_tag_cloud.js @@ -124,7 +124,7 @@ export default function ({ getService, getPageObjects }) { ]; await inspector.open(); - await await inspector.setTablePageSize('50'); + await await inspector.setTablePageSize(50); await inspector.expectTableData(expectedTableData); }); diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 5ecd8cd883c8ada..c3a8c73a8031146 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -35,25 +35,32 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont // wrapper around EuiComboBox interactions class ComboBox { /** - * set value inside combobox + * Sets value inside combobox * - * @param comboBoxSelector test subject selector - * @param 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); } + /** + * 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) { return isMouseClick ? await element.clickMouseButton() : await element.click(); } /** - * set value inside combobox element + * Sets value inside combobox element * - * @param comboBoxElement + * @param comboBoxElement element that wraps up EuiComboBox * @param value */ public async setElement( @@ -69,7 +76,7 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont } comboBoxElement.scrollIntoViewIfNecessary(); - await this._filterOptionsList(comboBoxElement, value); + await this.setFilterValue(comboBoxElement, value); await this.openOptionsList(comboBoxElement); if (value !== undefined) { @@ -93,30 +100,42 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont } /** - * This method set custom value to comboBox. - * It applies changes by pressing Enter key. Sometimes it may lead to auto-submitting a form. + * Sets custom value in combobox * - * @param comboBoxSelector test subject selector - * @param 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 */ - async setCustom(comboBoxSelector: string, value: string) { + public async setCustom(comboBoxSelector: string, value: string) { log.debug(`comboBox.setCustom, comboBoxSelector: ${comboBoxSelector}, value: ${value}`); const comboBoxElement = await testSubjects.find(comboBoxSelector); - await this._filterOptionsList(comboBoxElement, value); + await this.setFilterValue(comboBoxElement, value); await PageObjects.common.pressEnterKey(); await this.closeOptionsList(comboBoxElement); } - async filterOptionsList(comboBoxSelector: string, filterValue: string) { + /** + * Sets filter value in combobox + * + * @param comboBoxSelector data-test-subj selector + * @param filterValue text + */ + public async filterOptionsList(comboBoxSelector: string, filterValue: string) { log.debug( `comboBox.filterOptionsList, comboBoxSelector: ${comboBoxSelector}, filter: ${filterValue}` ); const comboBox = await testSubjects.find(comboBoxSelector); - await this._filterOptionsList(comboBox, filterValue); + await this.setFilterValue(comboBox, filterValue); await this.closeOptionsList(comboBox); } - private async _filterOptionsList( + /** + * Sets new value in combobox input field + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param filterValue text + */ + private async setFilterValue( comboBoxElement: WebElementWrapper, filterValue: string ): Promise { @@ -127,10 +146,20 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont await this.waitForOptionsListLoading(comboBoxElement); } + /** + * Waits options list is loaded + * + * @param comboBoxElement element that wraps up EuiComboBox + */ private async waitForOptionsListLoading(comboBoxElement: WebElementWrapper): Promise { await comboBoxElement.waitForDeletedByCssSelector('.euiLoadingSpinner'); } + /** + * Returns options list as a 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); @@ -148,37 +177,33 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont return optionsText; } + /** + * Checks if combobox have 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 selectedOptions = await comboBox.findAllByClassName( - 'euiComboBoxPill', - WAIT_FOR_EXISTS_TIME - ); - return selectedOptions.length > 0; + const $ = await comboBox.parseDomContent(); + return $('.euiComboBoxPill').toArray().length > 0; } + /** + * Returns selected options + * @param comboBoxSelector data-test-subj selector + */ public async getComboBoxSelectedOptions(comboBoxSelector: string): Promise { log.debug(`comboBox.getComboBoxSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); - return await retry.try(async () => { - const comboBox = await testSubjects.find(comboBoxSelector); - const selectedOptions = await comboBox.findAllByClassName( - 'euiComboBoxPill', - WAIT_FOR_EXISTS_TIME - ); - if (selectedOptions.length === 0) { - return []; - } - return Promise.all( - selectedOptions.map(async optionElement => { - return await optionElement.getVisibleText(); - }) - ); - }); + const comboBox = await testSubjects.find(comboBoxSelector); + const $ = await comboBox.parseDomContent(); + return $('.euiComboBoxPill') + .toArray() + .map(option => $(option).text()); } /** - * clearing value from combobox + * Clears value in combobox input field by clicking clear button * * @param comboBoxSelector data-test-subj selector */ @@ -212,9 +237,9 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont } /** - * closing option list for combobox + * Closes options list * - * @param comboBoxElement + * @param comboBoxElement element that wraps up EuiComboBox */ public async closeOptionsList(comboBoxElement: WebElementWrapper): Promise { const isOptionsListOpen = await testSubjects.exists('comboBoxOptionsList'); @@ -225,9 +250,9 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont } /** - * opened list of options for combobox + * Opens options list * - * @param comboBoxElement + * @param comboBoxElement element that wraps up EuiComboBox */ public async openOptionsList(comboBoxElement: WebElementWrapper): Promise { const isOptionsListOpen = await testSubjects.exists('comboBoxOptionsList'); @@ -240,10 +265,10 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont } /** - * check if option is already selected + * Checks if option is already selected * - * @param comboBoxElement - * @param value + * @param comboBoxElement element that wraps up EuiComboBox + * @param value option text */ public async isOptionSelected( comboBoxElement: WebElementWrapper, diff --git a/test/functional/services/embedding.js b/test/functional/services/embedding.ts similarity index 86% rename from test/functional/services/embedding.js rename to test/functional/services/embedding.ts index 2242be2923c156d..9a6bb3ba9b4e2c5 100644 --- a/test/functional/services/embedding.js +++ b/test/functional/services/embedding.ts @@ -17,20 +17,23 @@ * under the License. */ -export function EmbeddingProvider({ getService, getPageObjects }) { +import { FtrProviderContext } from '../ftr_provider_context'; + +export function EmbeddingProvider({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const log = getService('log'); const PageObjects = getPageObjects(['header']); class Embedding { - - async openInEmbeddedMode() { + /** + * Opens current page in embeded mode + */ + public async openInEmbeddedMode(): Promise { const currentUrl = await browser.getCurrentUrl(); log.debug(`Opening in embedded mode: ${currentUrl}`); await browser.get(`${currentUrl}&embed=true`); await PageObjects.header.waitUntilLoadingHasFinished(); } - } return new Embedding(); diff --git a/test/functional/services/filter_bar.js b/test/functional/services/filter_bar.ts similarity index 71% rename from test/functional/services/filter_bar.js rename to test/functional/services/filter_bar.ts index 51b3de354bc8250..987fa1b2df1d115 100644 --- a/test/functional/services/filter_bar.js +++ b/test/functional/services/filter_bar.ts @@ -17,48 +17,70 @@ * under the License. */ -export function FilterBarProvider({ getService, getPageObjects }) { - const testSubjects = getService('testSubjects'); +import { FtrProviderContext } from '../ftr_provider_context'; + +export function FilterBarProvider({ getService, getPageObjects }: FtrProviderContext) { const comboBox = getService('comboBox'); + const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects(['common', 'header']); class FilterBar { - hasFilter(key, value, enabled = true) { + /** + * Checks if specified filter exists + * + * @param key field name + * @param value filter value + * @param enabled filter status + */ + public async hasFilter(key: string, value: string, enabled: boolean = true): Promise { const filterActivationState = enabled ? 'enabled' : 'disabled'; - return testSubjects.exists( + return await testSubjects.exists( `filter & filter-key-${key} & filter-value-${value} & filter-${filterActivationState}`, { - allowHidden: true + allowHidden: true, } ); } - async removeFilter(key) { + /** + * Removes specified filter + * + * @param key field name + */ + public async removeFilter(key: string): Promise { await testSubjects.click(`filter & filter-key-${key}`); await testSubjects.click(`deleteFilter`); await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); } - async removeAllFilters() { + /** + * Removes all filters + */ + public async removeAllFilters(): Promise { await testSubjects.click('showFilterActions'); await testSubjects.click('removeAllFilters'); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.common.waitUntilUrlIncludes('filters:!()'); } - async toggleFilterEnabled(key) { + /** + * Changes filter active status + * + * @param key field name + */ + public async toggleFilterEnabled(key: string): Promise { await testSubjects.click(`filter & filter-key-${key}`); await testSubjects.click(`disableFilter`); await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); } - async toggleFilterPinned(key) { + public async toggleFilterPinned(key: string): Promise { await testSubjects.click(`filter & filter-key-${key}`); await testSubjects.click(`pinFilter`); await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); } - async getFilterCount() { + public async getFilterCount(): Promise { const filters = await testSubjects.findAll('filter'); return filters.length; } @@ -81,12 +103,14 @@ export function FilterBarProvider({ getService, getPageObjects }) { * // Add a filter containing multiple values * filterBar.addFilter('extension', 'is one of', ['jpg', 'png']); */ - async addFilter(field, operator, ...values) { + public async addFilter(field: string, operator: string, ...values: any): Promise { await testSubjects.click('addFilter'); await comboBox.set('filterFieldSuggestionList', field); await comboBox.set('filterOperatorList', operator); const params = await testSubjects.find('filterParams'); - const paramsComboBoxes = await params.findAllByCssSelector('[data-test-subj~="filterParamsComboBox"]'); + const paramsComboBoxes = await params.findAllByCssSelector( + '[data-test-subj~="filterParamsComboBox"]' + ); const paramFields = await params.findAllByTagName('input'); for (let i = 0; i < values.length; i++) { let fieldValues = values[i]; @@ -98,8 +122,7 @@ export function FilterBarProvider({ getService, getPageObjects }) { for (let j = 0; j < fieldValues.length; j++) { await comboBox.setElement(paramsComboBoxes[i], fieldValues[j]); } - } - else if (paramFields && paramFields.length > 0) { + } else if (paramFields && paramFields.length > 0) { for (let j = 0; j < fieldValues.length; j++) { await paramFields[i].type(fieldValues[j]); } @@ -109,36 +132,60 @@ export function FilterBarProvider({ getService, getPageObjects }) { await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); } - async clickEditFilter(key, value) { + /** + * Activates filter editing + * @param key field name + * @param value field value + */ + public async clickEditFilter(key: string, value: string): Promise { await testSubjects.click(`filter & filter-key-${key} & filter-value-${value}`); await testSubjects.click(`editFilter`); await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); } - async getFilterEditorSelectedPhrases() { + /** + * Returns available phrases in the filter + */ + public async getFilterEditorSelectedPhrases(): Promise { return await comboBox.getComboBoxSelectedOptions('filterParamsComboBox'); } - async getFilterEditorFields() { + /** + * Returns available fields in the filter + */ + public async getFilterEditorFields(): Promise { const optionsString = await comboBox.getOptionsList('filterFieldSuggestionList'); return optionsString.split('\n'); } - async ensureFieldEditorModalIsClosed() { + /** + * Closes field editor modal window + */ + public async ensureFieldEditorModalIsClosed(): Promise { const cancelSaveFilterModalButtonExists = await testSubjects.exists('cancelSaveFilter'); if (cancelSaveFilterModalButtonExists) { await testSubjects.click('cancelSaveFilter'); } } - async getIndexPatterns() { + /** + * Returns comma-separated list of index patterns + */ + public async getIndexPatterns(): Promise { await testSubjects.click('addFilter'); const indexPatterns = await comboBox.getOptionsList('filterIndexPatternsSelect'); await this.ensureFieldEditorModalIsClosed(); - return indexPatterns.trim().split('\n').join(','); + return indexPatterns + .trim() + .split('\n') + .join(','); } - async selectIndexPattern(indexPatternTitle) { + /** + * Adds new index pattern filter + * @param indexPatternTitle + */ + public async selectIndexPattern(indexPatternTitle: string): Promise { await testSubjects.click('addFilter'); await comboBox.set('filterIndexPatternsSelect', indexPatternTitle); } diff --git a/test/functional/services/find.ts b/test/functional/services/find.ts index 4fdc26619d8bea9..29713304cd5cbce 100644 --- a/test/functional/services/find.ts +++ b/test/functional/services/find.ts @@ -364,7 +364,7 @@ export async function FindProvider({ getService }: FtrProviderContext) { public async clickByButtonText( buttonText: string, - element = driver, + element: WebDriver | WebElement | WebElementWrapper = driver, timeout: number = defaultFindTimeout ): Promise { log.debug(`Find.clickByButtonText('${buttonText}') with timeout=${timeout}`); diff --git a/test/functional/services/flyout.js b/test/functional/services/flyout.ts similarity index 56% rename from test/functional/services/flyout.js rename to test/functional/services/flyout.ts index f0395e1cdd410ff..1ac07fd4e2e05a1 100644 --- a/test/functional/services/flyout.js +++ b/test/functional/services/flyout.ts @@ -17,42 +17,47 @@ * under the License. */ -export function FlyoutProvider({ getService }) { +import { FtrProviderContext } from '../ftr_provider_context'; + +export function FlyoutProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const find = getService('find'); const log = getService('log'); const retry = getService('retry'); class Flyout { - async close(testSubj) { - log.debug('Closing flyout', testSubj); - const flyoutElement = await testSubjects.find(testSubj); + public async close(dataTestSubj: string): Promise { + log.debug('Closing flyout', dataTestSubj); + const flyoutElement = await testSubjects.find(dataTestSubj); const closeBtn = await flyoutElement.findByCssSelector('[aria-label*="Close"]'); await closeBtn.click(); - await retry.waitFor('flyout closed', async () => !await testSubjects.exists(testSubj)); + await retry.waitFor('flyout closed', async () => !(await testSubjects.exists(dataTestSubj))); } - async ensureClosed(testSubj) { - if (await testSubjects.exists(testSubj)) { - await this.close(testSubj); + public async ensureClosed(dataTestSubj: string): Promise { + if (await testSubjects.exists(dataTestSubj)) { + await this.close(dataTestSubj); } } - async ensureAllClosed() { + public async ensureAllClosed(): Promise { const flyoutElements = await find.allByCssSelector('.euiFlyout'); if (!flyoutElements.length) { return; } - await Promise.all(flyoutElements.map(async (flyoutElement) => { - const closeBtn = await flyoutElement.findByCssSelector('[aria-label*="Close"]'); - await closeBtn.click(); - })); + await Promise.all( + flyoutElements.map(async flyoutElement => { + const closeBtn = await flyoutElement.findByCssSelector('[aria-label*="Close"]'); + await closeBtn.click(); + }) + ); - await retry.waitFor('all flyouts to be closed', async () => ( - (await find.allByCssSelector('.euiFlyout')).length === 0 - )); + await retry.waitFor( + 'all flyouts to be closed', + async () => (await find.allByCssSelector('.euiFlyout')).length === 0 + ); } } diff --git a/test/functional/services/global_nav.js b/test/functional/services/global_nav.ts similarity index 73% rename from test/functional/services/global_nav.js rename to test/functional/services/global_nav.ts index 332efdbd2bd7ba9..9622d2980093084 100644 --- a/test/functional/services/global_nav.js +++ b/test/functional/services/global_nav.ts @@ -18,39 +18,42 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; -export function GlobalNavProvider({ getService }) { +export function GlobalNavProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); - return new class GlobalNav { - async moveMouseToLogo() { + class GlobalNav { + public async moveMouseToLogo(): Promise { await testSubjects.moveMouseTo('headerGlobalNav logo'); } - async clickLogo() { + public async clickLogo(): Promise { return await testSubjects.click('headerGlobalNav logo'); } - async exists() { + public async exists(): Promise { return await testSubjects.exists('headerGlobalNav'); } - async getFirstBreadcrumb() { + public async getFirstBreadcrumb(): Promise { return await testSubjects.getVisibleText('headerGlobalNav breadcrumbs first&breadcrumb'); } - async getLastBreadcrumb() { + public async getLastBreadcrumb(): Promise { return await testSubjects.getVisibleText('headerGlobalNav breadcrumbs last&breadcrumb'); } - async badgeExistsOrFail(expectedLabel) { + public async badgeExistsOrFail(expectedLabel: string): Promise { await testSubjects.existOrFail('headerBadge'); const actualLabel = await testSubjects.getAttribute('headerBadge', 'data-test-badge-label'); expect(actualLabel.toUpperCase()).to.equal(expectedLabel.toUpperCase()); } - async badgeMissingOrFail() { + public async badgeMissingOrFail(): Promise { await testSubjects.missingOrFail('headerBadge'); } - }; + } + + return new GlobalNav(); } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 60ab726bafd64f4..e7b02a89b4b2ce2 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -29,36 +29,26 @@ import { DashboardVisualizationProvider, // @ts-ignore not TS yet } from './dashboard'; -// @ts-ignore not TS yet import { DocTableProvider } from './doc_table'; -// @ts-ignore not TS yet import { EmbeddingProvider } from './embedding'; // @ts-ignore not TS yet import { FailureDebuggingProvider } from './failure_debugging'; -// @ts-ignore not TS yet import { FilterBarProvider } from './filter_bar'; import { FindProvider } from './find'; -// @ts-ignore not TS yet import { FlyoutProvider } from './flyout'; -// @ts-ignore not TS yet import { GlobalNavProvider } from './global_nav'; -// @ts-ignore not TS yet import { InspectorProvider } from './inspector'; -// @ts-ignore not TS yet import { QueryBarProvider } from './query_bar'; import { RemoteProvider } from './remote'; -// @ts-ignore not TS yet import { RenderableProvider } from './renderable'; import { ScreenshotsProvider } from './screenshots'; // @ts-ignore not TS yet import { SnapshotsProvider } from './snapshots'; -// @ts-ignore not TS yet import { TableProvider } from './table'; import { TestSubjectsProvider } from './test_subjects'; import { ToastsProvider } from './toasts'; // @ts-ignore not TS yet import { PieChartProvider } from './visualizations'; -// @ts-ignore not TS yet import { VisualizeListingTableProvider } from './visualize_listing_table'; // @ts-ignore not TS yet import { SavedQueryManagementComponentProvider } from './saved_query_management_component'; diff --git a/test/functional/services/inspector.js b/test/functional/services/inspector.ts similarity index 60% rename from test/functional/services/inspector.js rename to test/functional/services/inspector.ts index d7c3109251aafbf..74fc250438635bb 100644 --- a/test/functional/services/inspector.js +++ b/test/functional/services/inspector.ts @@ -18,8 +18,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; -export function InspectorProvider({ getService }) { +export function InspectorProvider({ getService }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); const renderable = getService('renderable'); @@ -27,27 +28,36 @@ export function InspectorProvider({ getService }) { const testSubjects = getService('testSubjects'); const find = getService('find'); - return new class Inspector { - async getIsEnabled() { + class Inspector { + private async getIsEnabled(): Promise { const ariaDisabled = await testSubjects.getAttribute('openInspectorButton', 'disabled'); return ariaDisabled !== 'true'; } - async expectIsEnabled() { + /** + * Asserts that inspector is enabled + */ + public async expectIsEnabled(): Promise { await retry.try(async () => { const isEnabled = await this.getIsEnabled(); expect(isEnabled).to.be(true); }); } - async expectIsNotEnabled() { + /** + * Asserts that inspector is disabled + */ + public async expectIsNotEnabled(): Promise { await retry.try(async () => { const isEnabled = await this.getIsEnabled(); expect(isEnabled).to.be(false); }); } - async open() { + /** + * Opens inspector panel + */ + public async open(): Promise { log.debug('Inspector.open'); const isOpen = await testSubjects.exists('inspectorPanel'); if (!isOpen) { @@ -58,7 +68,10 @@ export function InspectorProvider({ getService }) { } } - async close() { + /** + * Closes inspector panel + */ + public async close(): Promise { log.debug('Close Inspector'); let isOpen = await testSubjects.exists('inspectorPanel'); if (isOpen) { @@ -72,13 +85,21 @@ export function InspectorProvider({ getService }) { } } - async expectTableData(expectedData) { + /** + * Asserts data on inspector panel + * @param expectedData + */ + public async expectTableData(expectedData: string[][]): Promise { await log.debug(`Inspector.expectTableData(${expectedData.join(',')})`); const data = await this.getTableData(); expect(data).to.eql(expectedData); } - async setTablePageSize(size) { + /** + * Sets table page size + * @param size rows count + */ + public async setTablePageSize(size: number): Promise { const panel = await testSubjects.find('inspectorPanel'); await find.clickByButtonText('Rows per page: 20', panel); // The buttons for setting table page size are in a popover element. This popover @@ -88,27 +109,43 @@ export function InspectorProvider({ getService }) { await find.clickByButtonText(`${size} rows`, tableSizesPopover); } - async getTableData() { + /** + * Returns table data in nested array format + */ + public async getTableData(): Promise { // TODO: we should use datat-test-subj=inspectorTable as soon as EUI supports it const inspectorPanel = await testSubjects.find('inspectorPanel'); const tableBody = await retry.try(async () => inspectorPanel.findByTagName('tbody')); const $ = await tableBody.parseDomContent(); - return $('tr').toArray().map(tr => { - return $(tr).find('td').toArray().map(cell => { - // if this is an EUI table, filter down to the specific cell content - // otherwise this will include mobile-specific header information - const euiTableCellContent = $(cell).find('.euiTableCellContent'); - - if (euiTableCellContent.length > 0) { - return $(cell).find('.euiTableCellContent').text().trim(); - } else { - return $(cell).text().trim(); - } + return $('tr') + .toArray() + .map(tr => { + return $(tr) + .find('td') + .toArray() + .map(cell => { + // if this is an EUI table, filter down to the specific cell content + // otherwise this will include mobile-specific header information + const euiTableCellContent = $(cell).find('.euiTableCellContent'); + + if (euiTableCellContent.length > 0) { + return $(cell) + .find('.euiTableCellContent') + .text() + .trim(); + } else { + return $(cell) + .text() + .trim(); + } + }); }); - }); } - async getTableHeaders() { + /** + * Returns table headers + */ + public async getTableHeaders(): Promise { log.debug('Inspector.getTableHeaders'); // TODO: we should use datat-test-subj=inspectorTable as soon as EUI supports it const dataTableHeader = await retry.try(async () => { @@ -116,21 +153,37 @@ export function InspectorProvider({ getService }) { return await inspectorPanel.findByTagName('thead'); }); const $ = await dataTableHeader.parseDomContent(); - return $('th span.euiTableCellContent__text').toArray() - .map(cell => $(cell).text().trim()); + return $('th span.euiTableCellContent__text') + .toArray() + .map(cell => + $(cell) + .text() + .trim() + ); } - async expectTableHeaders(expected) { + /** + * Asserts table headers + * @param expected expected headers + */ + public async expectTableHeaders(expected: string[]): Promise { await retry.try(async () => { const headers = await this.getTableHeaders(); expect(headers).to.eql(expected); }); } - async filterForTableCell(column, row) { + /** + * Filters table for value by clicking specified cell + * @param column column index + * @param row row index + */ + public async filterForTableCell(column: string, row: string): Promise { await retry.try(async () => { const table = await testSubjects.find('inspectorTable'); - const cell = await table.findByCssSelector(`tbody tr:nth-child(${row}) td:nth-child(${column})`); + const cell = await table.findByCssSelector( + `tbody tr:nth-child(${row}) td:nth-child(${column})` + ); await cell.moveMouseTo(); const filterBtn = await testSubjects.findDescendant('filterForInspectorCellValue', cell); await filterBtn.click(); @@ -138,10 +191,17 @@ export function InspectorProvider({ getService }) { await renderable.waitForRender(); } - async filterOutTableCell(column, row) { + /** + * Filters out table by clicking specified cell + * @param column column index + * @param row row index + */ + public async filterOutTableCell(column: string, row: string): Promise { await retry.try(async () => { const table = await testSubjects.find('inspectorTable'); - const cell = await table.findByCssSelector(`tbody tr:nth-child(${row}) td:nth-child(${column})`); + const cell = await table.findByCssSelector( + `tbody tr:nth-child(${row}) td:nth-child(${column})` + ); await cell.moveMouseTo(); const filterBtn = await testSubjects.findDescendant('filterOutInspectorCellValue', cell); await filterBtn.click(); @@ -149,28 +209,43 @@ export function InspectorProvider({ getService }) { await renderable.waitForRender(); } - async openInspectorView(viewId) { + /** + * Opens inspector view + * @param viewId + */ + public async openInspectorView(viewId: string): Promise { log.debug(`Open Inspector view ${viewId}`); await testSubjects.click('inspectorViewChooser'); await testSubjects.click(viewId); } - async openInspectorRequestsView() { + /** + * Opens inspector requests view + */ + public async openInspectorRequestsView(): Promise { await this.openInspectorView('inspectorViewChooserRequests'); } - async getRequestNames() { + /** + * Returns request name as the comma-separated string + */ + public async getRequestNames(): Promise { await this.openInspectorRequestsView(); const requestChooserExists = await testSubjects.exists('inspectorRequestChooser'); if (requestChooserExists) { await testSubjects.click('inspectorRequestChooser'); const menu = await testSubjects.find('inspectorRequestChooserMenuPanel'); const requestNames = await menu.getVisibleText(); - return requestNames.trim().split('\n').join(','); + return requestNames + .trim() + .split('\n') + .join(','); } const singleRequest = await testSubjects.find('inspectorRequestName'); return await singleRequest.getVisibleText(); } - }; + } + + return new Inspector(); } diff --git a/test/functional/services/query_bar.js b/test/functional/services/query_bar.ts similarity index 81% rename from test/functional/services/query_bar.js rename to test/functional/services/query_bar.ts index eb11ff10c8ed8c9..ace8b97155c09e8 100644 --- a/test/functional/services/query_bar.js +++ b/test/functional/services/query_bar.ts @@ -17,7 +17,9 @@ * under the License. */ -export function QueryBarProvider({ getService, getPageObjects }) { +import { FtrProviderContext } from '../ftr_provider_context'; + +export function QueryBarProvider({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const retry = getService('retry'); const log = getService('log'); @@ -25,12 +27,11 @@ export function QueryBarProvider({ getService, getPageObjects }) { const find = getService('find'); class QueryBar { - - async getQueryString() { + async getQueryString(): Promise { return await testSubjects.getAttribute('queryInput', 'value'); } - async setQuery(query) { + public async setQuery(query: string): Promise { log.debug(`QueryBar.setQuery(${query})`); // Extra caution used because of flaky test here: https://github.com/elastic/kibana/issues/16978 doesn't seem // to be actually setting the query in the query input based off @@ -44,22 +45,23 @@ export function QueryBarProvider({ getService, getPageObjects }) { await input.type(query); const currentQuery = await this.getQueryString(); if (currentQuery !== query) { - throw new Error(`Failed to set query input to ${query}, instead query is ${currentQuery}`); + throw new Error( + `Failed to set query input to ${query}, instead query is ${currentQuery}` + ); } }); } - async submitQuery() { + public async submitQuery(): Promise { log.debug('QueryBar.submitQuery'); await testSubjects.click('queryInput'); await PageObjects.common.pressEnterKey(); await PageObjects.header.waitUntilLoadingHasFinished(); } - async clickQuerySubmitButton() { + public async clickQuerySubmitButton(): Promise { await testSubjects.click('querySubmitButton'); } - } return new QueryBar(); diff --git a/test/functional/services/renderable.js b/test/functional/services/renderable.ts similarity index 83% rename from test/functional/services/renderable.js rename to test/functional/services/renderable.ts index d602ae059637c6a..e5a0b22fef7fbdd 100644 --- a/test/functional/services/renderable.js +++ b/test/functional/services/renderable.ts @@ -17,17 +17,18 @@ * under the License. */ +import { FtrProviderContext } from '../ftr_provider_context'; + const RENDER_COMPLETE_SELECTOR = '[data-render-complete="true"]'; const RENDER_COMPLETE_PENDING_SELECTOR = '[data-render-complete="false"]'; const DATA_LOADING_SELECTOR = '[data-loading]'; -export function RenderableProvider({ getService }) { +export function RenderableProvider({ getService }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); const find = getService('find'); - return new class Renderable { - + class Renderable { /** * This method waits for a certain number of objects to finish rendering and loading, which is indicated * by a couple tags. The RENDER_COMPLETE_SELECTOR indicates that it's done initially loading up. Some @@ -35,7 +36,7 @@ export function RenderableProvider({ getService }) { * return if any of those tags are found. * @param count {Number} Number of RENDER_COMPLETE_SELECTORs to wait for. */ - async waitForRender(count = 1) { + public async waitForRender(count: number = 1): Promise { log.debug(`Renderable.waitForRender for ${count} elements`); await retry.try(async () => { const completedElements = await find.allByCssSelector(RENDER_COMPLETE_SELECTOR); @@ -46,8 +47,10 @@ export function RenderableProvider({ getService }) { const title = await pendingElement.getAttribute('data-title'); pendingElementNames.push(title); } - throw new Error(`${completedElements.length} elements completed rendering, still waiting on a total of ${count} - specifically:\n${pendingElementNames.join('\n')}`); + throw new Error(`${ + completedElements.length + } elements completed rendering, still waiting on a total of ${count} + specifically:\n${pendingElementNames.join('\n')}`); } const stillLoadingElements = await find.allByCssSelector(DATA_LOADING_SELECTOR, 1000); @@ -56,5 +59,7 @@ export function RenderableProvider({ getService }) { } }); } - }; + } + + return new Renderable(); } diff --git a/test/functional/services/table.js b/test/functional/services/table.ts similarity index 51% rename from test/functional/services/table.js rename to test/functional/services/table.ts index a881699eeda0d11..6298221ab8db3d2 100644 --- a/test/functional/services/table.js +++ b/test/functional/services/table.ts @@ -17,25 +17,36 @@ * under the License. */ -export function TableProvider({ getService }) { +import { FtrProviderContext } from '../ftr_provider_context'; +import { WebElementWrapper } from './lib/web_element_wrapper'; + +export function TableProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); - // const retry = getService('retry'); class Table { + /** + * Finds table and returns data in the nested array format + * @param dataTestSubj data-test-subj selector + */ - async getDataFromTestSubj(testSubj) { - const table = await testSubjects.find(testSubj); + public async getDataFromTestSubj(dataTestSubj: string): Promise { + const table = await testSubjects.find(dataTestSubj); return await this.getDataFromElement(table); } - async getDataFromElement(table) { - // Convert the data into a nested array format: - // [ [cell1_in_row1, cell2_in_row1], [cell1_in_row2, cell2_in_row2] ] + /** + * Converts the table data into nested array + * [ [cell1_in_row1, cell2_in_row1], [cell1_in_row2, cell2_in_row2] ] + * @param table + */ + public async getDataFromElement(table: WebElementWrapper): Promise { const rows = await table.findAllByTagName('tr'); - return await Promise.all(rows.map(async row => { - const cells = await row.findAllByTagName('td'); - return await Promise.all(cells.map(async cell => await cell.getVisibleText())); - })); + return await Promise.all( + rows.map(async row => { + const cells = await row.findAllByTagName('td'); + return await Promise.all(cells.map(async cell => await cell.getVisibleText())); + }) + ); } } diff --git a/test/functional/services/visualize_listing_table.js b/test/functional/services/visualize_listing_table.ts similarity index 72% rename from test/functional/services/visualize_listing_table.js rename to test/functional/services/visualize_listing_table.ts index de9a095430afdb7..8c4640ada1c059a 100644 --- a/test/functional/services/visualize_listing_table.js +++ b/test/functional/services/visualize_listing_table.ts @@ -17,14 +17,16 @@ * under the License. */ -export function VisualizeListingTableProvider({ getService, getPageObjects }) { +import { FtrProviderContext } from '../ftr_provider_context'; + +export function VisualizeListingTableProvider({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const find = getService('find'); const log = getService('log'); - const PageObjects = getPageObjects(['dashboard', 'visualize', 'header', 'discover']); + const { header } = getPageObjects(['header']); class VisualizeListingTable { - async getAllVisualizationNamesOnCurrentPage() { + public async getAllVisualizationNamesOnCurrentPage(): Promise { const visualizationNames = []; const links = await find.allByCssSelector('.kuiLink'); for (let i = 0; i < links.length; i++) { @@ -34,16 +36,18 @@ export function VisualizeListingTableProvider({ getService, getPageObjects }) { return visualizationNames; } - async getAllVisualizationNames() { + public async getAllVisualizationNames(): Promise { log.debug('VisualizeListingTable.getAllVisualizationNames'); let morePages = true; - let visualizationNames = []; + let visualizationNames: string[] = []; while (morePages) { - visualizationNames = visualizationNames.concat(await this.getAllVisualizationNamesOnCurrentPage()); - morePages = !(await testSubjects.getAttribute('pagerNextButton', 'disabled') === 'true'); + visualizationNames = visualizationNames.concat( + await this.getAllVisualizationNamesOnCurrentPage() + ); + morePages = !((await testSubjects.getAttribute('pagerNextButton', 'disabled')) === 'true'); if (morePages) { await testSubjects.click('pagerNextButton'); - await PageObjects.header.waitUntilLoadingHasFinished(); + await header.waitUntilLoadingHasFinished(); } } return visualizationNames; diff --git a/x-pack/test/functional/apps/visualize/hybrid_visualization.ts b/x-pack/test/functional/apps/visualize/hybrid_visualization.ts index adb3ae5308be97c..dacd0b75b126c32 100644 --- a/x-pack/test/functional/apps/visualize/hybrid_visualization.ts +++ b/x-pack/test/functional/apps/visualize/hybrid_visualization.ts @@ -83,7 +83,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); await PageObjects.visualize.waitForVisualizationRenderingStabilized(); await inspector.open(); - await inspector.setTablePageSize('50'); + await inspector.setTablePageSize(50); await inspector.expectTableData(expectedData); }); });