diff --git a/test/functional/apps/visualize/_tile_map.js b/test/functional/apps/visualize/_tile_map.js index ee07e66757b6..9e39e93926c9 100644 --- a/test/functional/apps/visualize/_tile_map.js +++ b/test/functional/apps/visualize/_tile_map.js @@ -23,7 +23,6 @@ export default function({ getService, getPageObjects }) { const log = getService('log'); const retry = getService('retry'); const inspector = getService('inspector'); - const find = getService('find'); const filterBar = getService('filterBar'); const testSubjects = getService('testSubjects'); const browser = getService('browser'); @@ -279,7 +278,7 @@ export default function({ getService, getPageObjects }) { it('should suppress zoom warning if suppress warnings button clicked', async () => { last = true; await PageObjects.visChart.waitForVisualization(); - await find.clickByCssSelector('[data-test-subj="suppressZoomWarnings"]'); + await testSubjects.click('suppressZoomWarnings'); await PageObjects.tileMap.clickMapZoomOut(waitForLoading); await testSubjects.waitForDeleted('suppressZoomWarnings'); await PageObjects.tileMap.clickMapZoomIn(waitForLoading); diff --git a/test/functional/page_objects/common_page.ts b/test/functional/page_objects/common_page.ts index 6895034f22ed..de4917ef2b1b 100644 --- a/test/functional/page_objects/common_page.ts +++ b/test/functional/page_objects/common_page.ts @@ -100,7 +100,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo private async loginIfPrompted(appUrl: string) { let currentUrl = await browser.getCurrentUrl(); log.debug(`currentUrl = ${currentUrl}\n appUrl = ${appUrl}`); - await find.byCssSelector('[data-test-subj="kibanaChrome"]', 6 * defaultFindTimeout); // 60 sec waiting + await testSubjects.find('kibanaChrome', 6 * defaultFindTimeout); // 60 sec waiting const loginPage = currentUrl.includes('/login'); const wantedLoginPage = appUrl.includes('/login') || appUrl.includes('/logout'); diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index f018a1ceda50..a126cfb1bce4 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -255,14 +255,14 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider public async clickFieldListPlusFilter(field: string, value: string) { // this method requires the field details to be open from clickFieldListItem() // testSubjects.find doesn't handle spaces in the data-test-subj value - await find.clickByCssSelector(`[data-test-subj="plus-${field}-${value}"]`); + await testSubjects.click(`plus-${field}-${value}`); await header.waitUntilLoadingHasFinished(); } public async clickFieldListMinusFilter(field: string, value: string) { // this method requires the field details to be open from clickFieldListItem() // testSubjects.find doesn't handle spaces in the data-test-subj value - await find.clickByCssSelector('[data-test-subj="minus-' + field + '-' + value + '"]'); + await testSubjects.click(`minus-${field}-${value}`); await header.waitUntilLoadingHasFinished(); } diff --git a/test/functional/page_objects/newsfeed_page.ts b/test/functional/page_objects/newsfeed_page.ts index 24ff21f0b47d..ade3bdadf25d 100644 --- a/test/functional/page_objects/newsfeed_page.ts +++ b/test/functional/page_objects/newsfeed_page.ts @@ -54,7 +54,7 @@ export function NewsfeedPageProvider({ getService, getPageObjects }: FtrProvider async getNewsfeedList() { const list = await testSubjects.find('NewsfeedFlyout'); - const cells = await list.findAllByCssSelector('[data-test-subj="newsHeadAlert"]'); + const cells = await list.findAllByTestSubject('newsHeadAlert'); const objects = []; for (const cell of cells) { diff --git a/test/functional/page_objects/settings_page.ts b/test/functional/page_objects/settings_page.ts index 0ad1a1dc5132..e0f64340ca7d 100644 --- a/test/functional/page_objects/settings_page.ts +++ b/test/functional/page_objects/settings_page.ts @@ -211,9 +211,8 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider } async getScriptedFieldsTabCount() { - const selector = '[data-test-subj="tab-count-scriptedFields"]'; return await retry.try(async () => { - const theText = await (await find.byCssSelector(selector)).getVisibleText(); + const theText = await testSubjects.getVisibleText('tab-count-scriptedFields'); return theText.replace(/\((.*)\)/, '$1'); }); } diff --git a/test/functional/page_objects/timelion_page.js b/test/functional/page_objects/timelion_page.js index 4aaa654e4286..88eda5da5ce1 100644 --- a/test/functional/page_objects/timelion_page.js +++ b/test/functional/page_objects/timelion_page.js @@ -19,7 +19,6 @@ export function TimelionPageProvider({ getService, getPageObjects }) { const testSubjects = getService('testSubjects'); - const find = getService('find'); const log = getService('log'); const PageObjects = getPageObjects(['common', 'header']); const esArchiver = getService('esArchiver'); @@ -55,12 +54,12 @@ export function TimelionPageProvider({ getService, getPageObjects }) { } async getSuggestionItemsText() { - const elements = await find.allByCssSelector('[data-test-subj="timelionSuggestionListItem"]'); + const elements = await testSubjects.findAll('timelionSuggestionListItem'); return await Promise.all(elements.map(async element => await element.getVisibleText())); } async clickSuggestion(suggestionIndex = 0, waitTime = 500) { - const elements = await find.allByCssSelector('[data-test-subj="timelionSuggestionListItem"]'); + const elements = await testSubjects.findAll('timelionSuggestionListItem'); if (suggestionIndex > elements.length) { throw new Error( `Unable to select suggestion ${suggestionIndex}, only ${elements.length} suggestions available.` diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index ee0cafb51d45..0bfd2141be03 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -485,7 +485,7 @@ export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrPro const labels = await testSubjects.findAll('aggRow'); const label = labels[aggNth]; - return (await label.findAllByCssSelector('[data-test-subj = "comboBoxInput"]'))[1]; + return (await label.findAllByTestSubject('comboBoxInput'))[1]; } public async clickColorPicker(): Promise { @@ -533,7 +533,7 @@ export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrPro */ public async getAggregationCount(nth: number = 0): Promise { const series = await this.getSeries(); - const aggregation = await series[nth].findAllByCssSelector('[data-test-subj="draggable"]'); + const aggregation = await series[nth].findAllByTestSubject('draggable'); return aggregation.length; } diff --git a/test/functional/page_objects/visualize_editor_page.ts b/test/functional/page_objects/visualize_editor_page.ts index cdc16babc418..b1c3e924b3c1 100644 --- a/test/functional/page_objects/visualize_editor_page.ts +++ b/test/functional/page_objects/visualize_editor_page.ts @@ -110,7 +110,7 @@ export function VisualizeEditorPageProvider({ getService, getPageObjects }: FtrP */ public async clickBucket(bucketName: string, type = 'buckets') { await testSubjects.click(`visEditorAdd_${type}`); - await find.clickByCssSelector(`[data-test-subj="visEditorAdd_${type}_${bucketName}"`); + await testSubjects.click(`visEditorAdd_${type}_${bucketName}`); } public async clickEnableCustomRanges() { diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 33610e64f1c7..2c12490ccd43 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -218,7 +218,7 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont return; } - const clearBtn = await comboBox.findByCssSelector('[data-test-subj="comboBoxClearButton"]'); + const clearBtn = await comboBox.findByTestSubject('comboBoxClearButton'); await clearBtn.click(); const clearButtonStillExists = await this.doesClearButtonExist(comboBox); @@ -230,8 +230,8 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont } public async doesClearButtonExist(comboBoxElement: WebElementWrapper): Promise { - const found = await comboBoxElement.findAllByCssSelector( - '[data-test-subj="comboBoxClearButton"]', + const found = await comboBoxElement.findAllByTestSubject( + 'comboBoxClearButton', WAIT_FOR_EXISTS_TIME ); return found.length > 0; @@ -264,9 +264,7 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont public async openOptionsList(comboBoxElement: WebElementWrapper): Promise { const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); if (!isOptionsListOpen) { - const toggleBtn = await comboBoxElement.findByCssSelector( - '[data-test-subj="comboBoxToggleListButton"]' - ); + const toggleBtn = await comboBoxElement.findByTestSubject('comboBoxToggleListButton'); await toggleBtn.click(); } } diff --git a/test/functional/services/doc_table.ts b/test/functional/services/doc_table.ts index cb3daf20c641..69650f123d99 100644 --- a/test/functional/services/doc_table.ts +++ b/test/functional/services/doc_table.ts @@ -48,12 +48,12 @@ export function DocTableProvider({ getService, getPageObjects }: FtrProviderCont public async getBodyRows(): Promise { const table = await this.getTable(); - return await table.findAllByCssSelector('[data-test-subj~="docTableRow"]'); + return await table.findAllByTestSubject('~docTableRow'); } public async getAnchorRow(): Promise { const table = await this.getTable(); - return await table.findByCssSelector('[data-test-subj~="docTableAnchorRow"]'); + return await table.findByTestSubject('~docTableAnchorRow'); } public async getRow(options: SelectOptions): Promise { @@ -73,7 +73,7 @@ export function DocTableProvider({ getService, getPageObjects }: FtrProviderCont options: SelectOptions = { isAnchorRow: false, rowIndex: 0 } ): Promise { const row = await this.getRow(options); - const toggle = await row.findByCssSelector('[data-test-subj~="docTableExpandToggleColumn"]'); + const toggle = await row.findByTestSubject('~docTableExpandToggleColumn'); await toggle.click(); } @@ -90,7 +90,7 @@ export function DocTableProvider({ getService, getPageObjects }: FtrProviderCont const detailsRow = options.isAnchorRow ? await this.getAnchorDetailsRow() : (await this.getDetailsRows())[options.rowIndex]; - return await detailsRow.findAllByCssSelector('[data-test-subj~="docTableRowAction"]'); + return await detailsRow.findAllByTestSubject('~docTableRowAction'); } public async getFields(options: { isAnchorRow: boolean } = { isAnchorRow: false }) { @@ -122,15 +122,13 @@ export function DocTableProvider({ getService, getPageObjects }: FtrProviderCont detailsRow: WebElementWrapper, fieldName: WebElementWrapper ): Promise { - return await detailsRow.findByCssSelector(`[data-test-subj~="tableDocViewRow-${fieldName}"]`); + return await detailsRow.findByTestSubject(`~tableDocViewRow-${fieldName}`); } public async getAddInclusiveFilterButton( tableDocViewRow: WebElementWrapper ): Promise { - return await tableDocViewRow.findByCssSelector( - `[data-test-subj~="addInclusiveFilterButton"]` - ); + return await tableDocViewRow.findByTestSubject(`~addInclusiveFilterButton`); } public async addInclusiveFilter( @@ -146,7 +144,7 @@ export function DocTableProvider({ getService, getPageObjects }: FtrProviderCont public async getAddExistsFilterButton( tableDocViewRow: WebElementWrapper ): Promise { - return await tableDocViewRow.findByCssSelector(`[data-test-subj~="addExistsFilterButton"]`); + return await tableDocViewRow.findByTestSubject(`~addExistsFilterButton`); } public async addExistsFilter( @@ -171,7 +169,7 @@ export function DocTableProvider({ getService, getPageObjects }: FtrProviderCont const detailsRow = await row.findByXpath( './following-sibling::*[@data-test-subj="docTableDetailsRow"]' ); - return detailsRow.findByCssSelector('[data-test-subj~="docViewer"]'); + return detailsRow.findByTestSubject('~docViewer'); }); } } diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts index fe781c2ac02b..157918df874c 100644 --- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts +++ b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts @@ -537,6 +537,40 @@ export class WebElementWrapper { }); } + /** + * Gets the first element inside this element matching the given data-test-subj selector. + * + * @param {string} selector + * @return {Promise} + */ + public async findByTestSubject(selector: string) { + return await this.retryCall(async function find(wrapper) { + return wrapper._wrap( + await wrapper._webElement.findElement(wrapper.By.css(testSubjSelector(selector))), + wrapper.By.css(selector) + ); + }); + } + + /** + * Gets all elements inside this element matching the given data-test-subj selector. + * + * @param {string} selector + * @param {number} timeout + * @return {Promise} + */ + public async findAllByTestSubject(selector: string, timeout?: number) { + return await this.retryCall(async function findAll(wrapper) { + return wrapper._wrapAll( + await wrapper._findWithCustomTimeout( + async () => + await wrapper._webElement.findElements(wrapper.By.css(testSubjSelector(selector))), + timeout + ) + ); + }); + } + /** * Gets the first element inside this element matching the given CSS class name. * https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElement.html#findElement diff --git a/x-pack/test/functional/page_objects/gis_page.js b/x-pack/test/functional/page_objects/gis_page.js index 8d0c649d75dd..1d0e231d7dc5 100644 --- a/x-pack/test/functional/page_objects/gis_page.js +++ b/x-pack/test/functional/page_objects/gis_page.js @@ -451,7 +451,7 @@ export function GisPageProvider({ getService, getPageObjects }) { async getCodeBlockParsedJson(dataTestSubjName) { log.debug(`Get parsed code block for ${dataTestSubjName}`); - const indexRespCodeBlock = await find.byCssSelector(`[data-test-subj="${dataTestSubjName}"]`); + const indexRespCodeBlock = await testSubjects.find(`${dataTestSubjName}`); const indexRespJson = await indexRespCodeBlock.getAttribute('innerText'); return JSON.parse(indexRespJson); } diff --git a/x-pack/test/functional/page_objects/rollup_page.js b/x-pack/test/functional/page_objects/rollup_page.js index 1514693defec..b6bc60df6f7c 100644 --- a/x-pack/test/functional/page_objects/rollup_page.js +++ b/x-pack/test/functional/page_objects/rollup_page.js @@ -111,28 +111,18 @@ export function RollupPageProvider({ getService, getPageObjects }) { async getJobList() { const jobs = await testSubjects.findAll('jobTableRow'); return mapAsync(jobs, async job => { - const jobNameElement = await job.findByCssSelector('[data-test-subj="jobTableCell-id"]'); - const jobStatusElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-status"]' + const jobNameElement = await job.findByTestSubject('jobTableCell-id'); + const jobStatusElement = await job.findByTestSubject('jobTableCell-status'); + const jobIndexPatternElement = await job.findByTestSubject('jobTableCell-indexPattern'); + const jobRollUpIndexPatternElement = await job.findByTestSubject( + 'jobTableCell-rollupIndex' ); - const jobIndexPatternElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-indexPattern"]' - ); - const jobRollUpIndexPatternElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-rollupIndex"]' - ); - const jobDelayElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-rollupDelay"]' - ); - const jobIntervalElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-dateHistogramInterval"]' - ); - const jobGroupElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-groups"]' - ); - const jobMetricsElement = await job.findByCssSelector( - '[data-test-subj="jobTableCell-metrics"]' + const jobDelayElement = await job.findByTestSubject('jobTableCell-rollupDelay'); + const jobIntervalElement = await job.findByTestSubject( + 'jobTableCell-dateHistogramInterval' ); + const jobGroupElement = await job.findByTestSubject('jobTableCell-groups'); + const jobMetricsElement = await job.findByTestSubject('jobTableCell-metrics'); return { jobName: await jobNameElement.getVisibleText(), diff --git a/x-pack/test/functional/page_objects/security_page.js b/x-pack/test/functional/page_objects/security_page.js index 4b097b916573..b399327012a7 100644 --- a/x-pack/test/functional/page_objects/security_page.js +++ b/x-pack/test/functional/page_objects/security_page.js @@ -229,13 +229,12 @@ export function SecurityPageProvider({ getService, getPageObjects }) { async getElasticsearchUsers() { const users = await testSubjects.findAll('userRow'); return mapAsync(users, async user => { - const fullnameElement = await user.findByCssSelector('[data-test-subj="userRowFullName"]'); - const usernameElement = await user.findByCssSelector('[data-test-subj="userRowUserName"]'); - const emailElement = await user.findByCssSelector('[data-test-subj="userRowEmail"]'); - const rolesElement = await user.findByCssSelector('[data-test-subj="userRowRoles"]'); - // findAllByCssSelector is substantially faster than `find.descendantExistsByCssSelector for negative cases - const isUserReserved = - (await user.findAllByCssSelector('span[data-test-subj="userReserved"]', 1)).length > 0; + const fullnameElement = await user.findByTestSubject('userRowFullName'); + const usernameElement = await user.findByTestSubject('userRowUserName'); + const emailElement = await user.findByTestSubject('userRowEmail'); + const rolesElement = await user.findByTestSubject('userRowRoles'); + // findAll is substantially faster than `find.descendantExistsByCssSelector for negative cases + const isUserReserved = (await user.findAllByTestSubject('userReserved', 1)).length > 0; return { username: await usernameElement.getVisibleText(), @@ -251,15 +250,11 @@ export function SecurityPageProvider({ getService, getPageObjects }) { const users = await testSubjects.findAll('roleRow'); return mapAsync(users, async role => { const [rolename, reserved, deprecated] = await Promise.all([ - role.findByCssSelector('[data-test-subj="roleRowName"]').then(el => el.getVisibleText()), - // findAllByCssSelector is substantially faster than `find.descendantExistsByCssSelector for negative cases - role - .findAllByCssSelector('span[data-test-subj="roleReserved"]', 1) - .then(el => el.length > 0), - // findAllByCssSelector is substantially faster than `find.descendantExistsByCssSelector for negative cases - role - .findAllByCssSelector('span[data-test-subj="roleDeprecated"]', 1) - .then(el => el.length > 0), + role.findByTestSubject('roleRowName').then(el => el.getVisibleText()), + // findAll is substantially faster than `find.descendantExistsByCssSelector for negative cases + role.findAllByTestSubject('roleReserved', 1).then(el => el.length > 0), + // findAll is substantially faster than `find.descendantExistsByCssSelector for negative cases + role.findAllByTestSubject('roleDeprecated', 1).then(el => el.length > 0), ]); return { diff --git a/x-pack/test/functional/page_objects/snapshot_restore_page.ts b/x-pack/test/functional/page_objects/snapshot_restore_page.ts index 1c8ba9f63311..841345e3727f 100644 --- a/x-pack/test/functional/page_objects/snapshot_restore_page.ts +++ b/x-pack/test/functional/page_objects/snapshot_restore_page.ts @@ -28,21 +28,15 @@ export function SnapshotRestorePageProvider({ getService }: FtrProviderContext) }, async getRepoList() { const table = await testSubjects.find('repositoryTable'); - const rows = await table.findAllByCssSelector('[data-test-subj="row"]'); + const rows = await table.findAllByTestSubject('row'); return await Promise.all( rows.map(async row => { return { - repoName: await ( - await row.findByCssSelector('[data-test-subj="Name_cell"]') - ).getVisibleText(), - repoLink: await ( - await row.findByCssSelector('[data-test-subj="Name_cell"]') - ).findByCssSelector('a'), - repoType: await ( - await row.findByCssSelector('[data-test-subj="Type_cell"]') - ).getVisibleText(), - repoEdit: await row.findByCssSelector('[data-test-subj="editRepositoryButton"]'), - repoDelete: await row.findByCssSelector('[data-test-subj="deleteRepositoryButton"]'), + repoName: await (await row.findByTestSubject('Name_cell')).getVisibleText(), + repoLink: await (await row.findByTestSubject('Name_cell')).findByCssSelector('a'), + repoType: await (await row.findByTestSubject('Type_cell')).getVisibleText(), + repoEdit: await row.findByTestSubject('editRepositoryButton'), + repoDelete: await row.findByTestSubject('deleteRepositoryButton'), }; }) ); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 79448fa53537..266e128fd6be 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -84,7 +84,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('slackAddVariableButton'); const variableMenuButton = await testSubjects.find('variableMenuButton-0'); await variableMenuButton.click(); - await find.clickByCssSelector('[data-test-subj="saveAlertButton"]'); + await testSubjects.click('saveAlertButton'); const toastTitle = await pageObjects.common.closeToast(); expect(toastTitle).to.eql(`Saved '${alertName}'`); await pageObjects.triggersActionsUI.searchAlerts(alertName); @@ -333,9 +333,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('collapsedItemActions'); await testSubjects.click('deleteAlert'); - const emptyPrompt = await find.byCssSelector( - '[data-test-subj="createFirstAlertEmptyPrompt"]' - ); + const emptyPrompt = await testSubjects.find('createFirstAlertEmptyPrompt'); expect(await emptyPrompt.elementHasClass('euiEmptyPrompt')).to.be(true); }); @@ -446,9 +444,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('deleteAll'); - const emptyPrompt = await find.byCssSelector( - '[data-test-subj="createFirstAlertEmptyPrompt"]' - ); + const emptyPrompt = await testSubjects.find('createFirstAlertEmptyPrompt'); expect(await emptyPrompt.elementHasClass('euiEmptyPrompt')).to.be(true); }); }); diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 91c7fe1f97d1..8d90d3c84b18 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -19,14 +19,14 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) return await testSubjects.getVisibleText('appTitle'); }, async clickCreateFirstConnectorButton() { - const createBtn = await find.byCssSelector('[data-test-subj="createFirstActionButton"]'); + const createBtn = await testSubjects.find('createFirstActionButton'); const createBtnIsVisible = await createBtn.isDisplayed(); if (createBtnIsVisible) { await createBtn.click(); } }, async clickCreateConnectorButton() { - const createBtn = await find.byCssSelector('[data-test-subj="createActionButton"]'); + const createBtn = await testSubjects.find('createActionButton'); const createBtnIsVisible = await createBtn.isDisplayed(); if (createBtnIsVisible) { await createBtn.click();