Stabilize and bring back flaky tests (#13034)

* Stabalize tests and bring back flaky test

* Try to fix flaky map radius visualize test

* fix flaky tile map zoom test

* Try to fix flaky zoom test by avoiding zooming in and out with spy panel open

* Remove duplicate wrapped retry around find methods

The retry was moved internally, around a check for stale elements as
well, so this should no longer be neccessary.
This commit is contained in:
Stacey Gammon 2017-07-27 15:26:09 -04:00 committed by GitHub
parent 8d5eac959f
commit 589df61e03
20 changed files with 551 additions and 900 deletions

View file

@ -1,6 +1,7 @@
import expect from 'expect.js';
export default function ({ getPageObjects }) {
export default function ({ getService, getPageObjects }) {
const retry = getService('retry');
const PageObjects = getPageObjects(['dashboard', 'header', 'common']);
describe('dashboard save', function describeIndexTests() {
@ -88,8 +89,11 @@ export default function ({ getPageObjects }) {
await PageObjects.dashboard.clickEdit();
await PageObjects.dashboard.enterDashboardTitleAndClickSave(dashboardName.toUpperCase());
const isConfirmOpen = await PageObjects.common.isConfirmModalOpen();
expect(isConfirmOpen).to.equal(true);
// We expect isConfirmModalOpen to be open, hence the retry if not found.
await retry.try(async () => {
const isConfirmOpen = await PageObjects.common.isConfirmModalOpen();
expect(isConfirmOpen).to.equal(true);
});
await PageObjects.common.clickCancelOnModal();
});

View file

@ -29,7 +29,7 @@ export default function ({ getPageObjects }) {
await PageObjects.header.clickToastOK();
});
it.skip('Does not set the time picker on open', async function () {
it('Does not set the time picker on open', async function () {
await PageObjects.header.setAbsoluteRange(fromTime, toTime);
await PageObjects.dashboard.loadSavedDashboard(dashboardName);
@ -81,7 +81,7 @@ export default function ({ getPageObjects }) {
// when it's opened. However, if the user then changes the time, navigates to visualize, then navigates
// back to dashboard, the overridden time should be preserved. The time is *only* reset on open, not
// during navigation or page refreshes.
describe.skip('time changes', function () {
describe('time changes', function () {
it('preserved during navigation', async function () {
await PageObjects.header.setQuickTime('Today');
await PageObjects.header.clickVisualize();

View file

@ -164,7 +164,7 @@ export default function ({ getService, getPageObjects }) {
expect(query).to.equal(originalQuery);
});
it.skip('when a filter is deleted', async function () {
it('when a filter is deleted', async function () {
await PageObjects.dashboard.setTimepickerInDataRange();
await PageObjects.dashboard.filterOnPieSlice();
await PageObjects.dashboard.saveDashboard(dashboardName);

View file

@ -230,7 +230,7 @@ export default function ({ getService, getPageObjects }) {
});
describe('data-shared-item', function () {
it.skip('should have correct data-shared-item title and description', async () => {
it('should have correct data-shared-item title and description', async () => {
const expected = {
title: 'A Saved Search',
description: 'A Saved Search Description'

View file

@ -1,7 +1,6 @@
import expect from 'expect.js';
export default function ({ getService, getPageObjects }) {
const log = getService('log');
const retry = getService('retry');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
@ -9,31 +8,21 @@ export default function ({ getService, getPageObjects }) {
const PageObjects = getPageObjects(['common', 'header', 'discover']);
describe('discover app', function describeIndexTests() {
before(function () {
before(async function () {
const fromTime = '2015-09-19 06:31:44.000';
const toTime = '2015-09-23 18:31:44.000';
await esArchiver.loadIfNeeded('logstash_functional');
await esArchiver.load('discover');
await kibanaServer.waitForStabilization();
// delete .kibana index and update configDoc
return kibanaServer.uiSettings.replace({
await kibanaServer.uiSettings.replace({
'dateFormat:tz': 'UTC',
'defaultIndex': 'logstash-*'
})
.then(function loadkibanaIndexPattern() {
log.debug('load kibana index with default index pattern');
return esArchiver.load('discover');
})
// and load a set of makelogs data
.then(function loadIfEmptyMakelogs() {
return esArchiver.loadIfNeeded('logstash_functional');
})
.then(function () {
log.debug('discover');
return PageObjects.common.navigateToApp('discover');
})
.then(function () {
log.debug('setAbsoluteRange');
return PageObjects.header.setAbsoluteRange(fromTime, toTime);
});
await PageObjects.common.navigateToApp('discover');
await PageObjects.header.setAbsoluteRange(fromTime, toTime);
});

View file

@ -68,7 +68,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be(`Visualization Editor: Saved Visualization "${vizNamewithSpecialChars}"`);
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
});
});
@ -79,7 +79,7 @@ export default function ({ getService, getPageObjects }) {
log.debug(`Saved viz message with umlaut = ${message}`);
expect(message).to.be(`Visualization Editor: Saved Visualization "${vizNamewithSpecialChars}"`);
await PageObjects.visualize.waitForToastMessageGone();
await PageObjects.header.waitForToastMessageGone();
});
it('should save and load', function () {
@ -90,7 +90,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function loadSavedVisualization() {
return PageObjects.visualize.loadSavedVisualization(vizName1);

View file

@ -59,7 +59,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.loadSavedVisualization(vizName1);

View file

@ -3,6 +3,7 @@ import expect from 'expect.js';
export default function ({ getService, getPageObjects }) {
const log = getService('log');
const screenshots = getService('screenshots');
const retry = getService('retry');
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
describe('visualize app', function describeIndexTests() {
@ -57,7 +58,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.loadSavedVisualization(vizName1);
@ -70,20 +71,14 @@ export default function ({ getService, getPageObjects }) {
});
});
it('should show correct chart, take screenshot', function () {
it('should show correct chart, take screenshot', async function () {
const expectedChartValues = ['0 - 400', '0 - 400', '400 - 800', '1,200 - 1,600',
'1,200 - 1,600', '400 - 800', '0 - 400', '0 - 400', '0 - 400', '0 - 400', '400 - 800',
'1,200 - 1,600', '1,200 - 1,600', '400 - 800', '0 - 400', '0 - 400', '0 - 400', '0 - 400',
'400 - 800', '1,200 - 1,600', '1,200 - 1,600', '400 - 800', '0 - 400', '0 - 400' ];
// Most recent failure on Jenkins usually indicates the bar chart is still being drawn?
// return arguments[0].getAttribute(arguments[1]);","args":[{"ELEMENT":"592"},"fill"]}] arguments[0].getAttribute is not a function
// try sleeping a bit before getting that data
return PageObjects.common.sleep(5000)
.then(function () {
return PageObjects.visualize.getHeatmapData();
})
.then(function showData(data) {
await retry.try(async () => {
const data = await PageObjects.visualize.getHeatmapData();
log.debug('data=' + data);
log.debug('data.length=' + data.length);
screenshots.take('Visualize-heatmap-chart');

View file

@ -131,7 +131,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.loadSavedVisualization(vizName1);

View file

@ -65,7 +65,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.loadSavedVisualization(vizName1);

View file

@ -2,6 +2,7 @@ import expect from 'expect.js';
export default function ({ getService, getPageObjects }) {
const log = getService('log');
const retry = getService('retry');
const screenshots = getService('screenshots');
const PageObjects = getPageObjects(['common', 'visualize', 'header', 'pointSeries']);
const pointSeriesVis = PageObjects.pointSeries;
@ -82,7 +83,7 @@ export default function ({ getService, getPageObjects }) {
describe('secondary value axis', function () {
it('should show correct chart, take screenshot', function () {
it('should show correct chart, take screenshot', async function () {
const expectedChartValues = [
[ 37, 202, 740, 1437, 1371, 751, 188, 31, 42, 202, 683,
1361, 1415, 707, 177, 27, 32, 175, 707, 1408, 1355, 726, 201, 29 ],
@ -92,27 +93,18 @@ export default function ({ getService, getPageObjects }) {
12807319386, 13375732998, 13190755620, 12627508458, 12731510199, 13153337344 ],
];
// Most recent failure on Jenkins usually indicates the bar chart is still being drawn?
// return arguments[0].getAttribute(arguments[1]);","args":[{"ELEMENT":"592"},"fill"]}] arguments[0].getAttribute is not a function
// try sleeping a bit before getting that data
return PageObjects.common.sleep(2000)
.then(function () {
return PageObjects.visualize.getLineChartData('fill="#00a69b"');
})
.then(function showData(data) {
log.debug('count data=' + data);
log.debug('data.length=' + data.length);
screenshots.take('Visualize-secondary-value-axis');
expect(data).to.eql(expectedChartValues[0]);
})
.then(function () {
return PageObjects.visualize.getLineChartData('fill="#57c17b"', 'ValueAxis-2');
})
.then(function showData(data) {
log.debug('average memory data=' + data);
log.debug('data.length=' + data.length);
expect(data).to.eql(expectedChartValues[1]);
});
await retry.try(async () => {
const data = await PageObjects.visualize.getLineChartData('fill="#00a69b"');
log.debug('count data=' + data);
log.debug('data.length=' + data.length);
screenshots.take('Visualize-secondary-value-axis');
expect(data).to.eql(expectedChartValues[0]);
const avgMemoryData = await PageObjects.visualize.getLineChartData('fill="#57c17b"', 'ValueAxis-2');
log.debug('average memory data=' + avgMemoryData);
log.debug('data.length=' + avgMemoryData.length);
expect(avgMemoryData).to.eql(expectedChartValues[1]);
});
});
it('should put secondary axis on the right', function () {

View file

@ -53,14 +53,10 @@ export default function ({ getService, getPageObjects }) {
describe('tile cloud chart', function indexPatternCreation() {
const vizName1 = 'Visualization tagCloud';
it('should show correct tag cloud data', function () {
return PageObjects.common.sleep(2000)
.then(function () {
return PageObjects.visualize.getTextTag().then(function (results) {
log.debug(results);
expect(results).to.eql([ '32212254720', '21474836480','20401094656','19327352832','18253611008' ]);
});
});
it('should show correct tag cloud data', async function () {
const data = await PageObjects.visualize.getTextTag();
log.debug(data);
expect(data).to.eql([ '32212254720', '21474836480','20401094656','19327352832','18253611008' ]);
});
@ -71,7 +67,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.loadSavedVisualization(vizName1);

View file

@ -90,54 +90,34 @@ export default function ({ getService, getPageObjects }) {
describe('tile map chart', function indexPatternCreation() {
it('should show correct tile map data on default zoom level', function () {
it('should show correct tile map data on default zoom level', async function () {
const expectedTableData = ['9 5,787 { "lat": 37.22448418632405, "lon": -103.01935195013255 }',
'd 5,600 { "lat": 37.44271478370398, "lon": -81.72692197253595 }',
'c 1,319 { "lat": 47.72720855392425, "lon": -109.84745063951028 }',
'b 999 { "lat": 62.04130042948433, "lon": -155.28087269195967 }',
'f 187 { "lat": 45.656166475784175, "lon": -82.45831044201545 }',
'8 108 { "lat": 18.85260305600241, "lon": -156.5148810390383 }'];
//level 1
await PageObjects.visualize.clickMapZoomOut();
//level 0
await PageObjects.visualize.clickMapZoomOut();
return PageObjects.visualize.openSpyPanel()
.then(function () {
//level 1
return PageObjects.visualize.clickMapZoomOut();
})
.then(function () {
//level 0
return PageObjects.visualize.clickMapZoomOut();
})
.then(function () {
return PageObjects.settings.setPageSize('All');
})
.then(function getDataTableData() {
return PageObjects.visualize.getDataTableData()
.then(function showData(actualTableData) {
compareTableData(expectedTableData, actualTableData.trim().split('\n'));
return PageObjects.visualize.closeSpyPanel();
});
});
await PageObjects.visualize.openSpyPanel();
await PageObjects.settings.setPageSize('All');
const actualTableData = await PageObjects.visualize.getDataTableData();
compareTableData(expectedTableData, actualTableData.trim().split('\n'));
await PageObjects.visualize.closeSpyPanel();
});
it('should not be able to zoom out beyond 0', function () {
return PageObjects.visualize.getMapZoomOutEnabled()
// we can tell we're at level 1 because zoom out is disabled
.then(function () {
return retry.try(function tryingForTime() {
return PageObjects.visualize.getMapZoomOutEnabled()
.then(function (enabled) {
//should be able to zoom more as current config has 0 as min level.
expect(enabled).to.be(false);
});
});
})
.then(function takeScreenshot() {
log.debug('Take screenshot (success)');
screenshots.take('map-at-zoom-0');
});
it('should not be able to zoom out beyond 0', async function () {
await PageObjects.visualize.zoomAllTheWayOut();
const enabled = await PageObjects.visualize.getMapZoomOutEnabled();
expect(enabled).to.be(false);
screenshots.take('map-at-zoom-0');
});
it('Fit data bounds should zoom to level 3', function () {
// See https://github.com/elastic/kibana/issues/13137 if this test starts failing intermittently
it('Fit data bounds should zoom to level 3', async function () {
const expectedPrecision2ZoomCircles = [
{ color: '#750000', radius: 192 },
{ color: '#750000', radius: 191 },
@ -187,12 +167,11 @@ export default function ({ getService, getPageObjects }) {
{ color: '#b99939', radius: 9 }
];
return PageObjects.visualize.clickMapFitDataBounds()
.then(function () {
return PageObjects.visualize.getTileMapData();
})
.then(function (data) {
await retry.try(async() => {
await PageObjects.visualize.clickMapFitDataBounds();
const data = await PageObjects.visualize.getTileMapData();
expect(data).to.eql(expectedPrecision2ZoomCircles);
screenshots.take('map-at-zoom-3');
});
});
@ -238,7 +217,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.openSpyPanel();

View file

@ -2,6 +2,7 @@ import expect from 'expect.js';
export default function ({ getService, getPageObjects }) {
const log = getService('log');
const retry = getService('retry');
const screenshots = getService('screenshots');
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
@ -57,7 +58,7 @@ export default function ({ getService, getPageObjects }) {
expect(message).to.be('Visualization Editor: Saved Visualization \"' + vizName1 + '\"');
})
.then(function testVisualizeWaitForToastMessageGone() {
return PageObjects.visualize.waitForToastMessageGone();
return PageObjects.header.waitForToastMessageGone();
})
.then(function () {
return PageObjects.visualize.loadSavedVisualization(vizName1);
@ -70,7 +71,7 @@ export default function ({ getService, getPageObjects }) {
});
});
it('should show correct chart, take screenshot', function () {
it('should show correct chart, take screenshot', async function () {
const expectedChartValues = [37, 202, 740, 1437, 1371, 751, 188, 31, 42, 202, 683,
1361, 1415, 707, 177, 27, 32, 175, 707, 1408, 1355, 726, 201, 29
];
@ -78,11 +79,8 @@ export default function ({ getService, getPageObjects }) {
// Most recent failure on Jenkins usually indicates the bar chart is still being drawn?
// return arguments[0].getAttribute(arguments[1]);","args":[{"ELEMENT":"592"},"fill"]}] arguments[0].getAttribute is not a function
// try sleeping a bit before getting that data
return PageObjects.common.sleep(50000)
.then(function () {
return PageObjects.visualize.getBarChartData();
})
.then(function showData(data) {
await retry.try(async() => {
const data = await PageObjects.visualize.getBarChartData();
log.debug('data=' + data);
log.debug('data.length=' + data.length);
screenshots.take('Visualize-vertical-bar-chart');
@ -90,7 +88,6 @@ export default function ({ getService, getPageObjects }) {
});
});
it('should show correct data', function () {
// this is only the first page of the tabular data.
const expectedChartData = [ '2015-09-20 00:00', '37',

View file

@ -7,6 +7,7 @@ export function CommonPageProvider({ getService, getPageObjects }) {
const config = getService('config');
const remote = getService('remote');
const retry = getService('retry');
const find = getService('find');
const testSubjects = getService('testSubjects');
const kibanaServer = getService('kibanaServer');
const PageObjects = getPageObjects(['shield']);
@ -200,10 +201,7 @@ export function CommonPageProvider({ getService, getPageObjects }) {
}
async getSharedItemTitleAndDescription() {
const element = await remote
.setFindTimeout(defaultFindTimeout)
.findByCssSelector('[data-shared-item]');
const element = await find.byCssSelector('[data-shared-item]');
return {
title: await element.getAttribute('data-title'),
description: await element.getAttribute('data-description')
@ -239,12 +237,8 @@ export function CommonPageProvider({ getService, getPageObjects }) {
}
async isConfirmModalOpen() {
const isOpen = await testSubjects
.find('confirmModalCancelButton', 2000)
.then(() => true, () => false);
await remote.setFindTimeout(defaultFindTimeout);
return isOpen;
log.debug('isConfirmModalOpen');
return await testSubjects.exists('confirmModalCancelButton', 2000);
}
async doesCssSelectorExist(selector) {

View file

@ -59,9 +59,14 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
}
}
async getQueryInputElement() {
return retry.try(() => testSubjects.find('queryInput'));
}
async getQuery() {
const queryObject = await testSubjects.find('queryInput');
return await queryObject.getProperty('value');
log.debug(`getQuery`);
const queryInputElement = await this.getQueryInputElement();
return await queryInputElement.getProperty('value');
}
async setQuery(query) {
@ -104,7 +109,7 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
}
clickCancelOutOfEditMode() {
log.debug('Clicking cancel');
log.debug('clickCancelOutOfEditMode');
return testSubjects.click('dashboardViewOnlyMode');
}
@ -229,12 +234,7 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
// verify that green message at the top of the page.
// it's only there for about 5 seconds
await retry.try(() => {
log.debug('verify toast-message for saved dashboard');
return getRemote()
.findByCssSelector('kbn-truncated.toast-message.ng-isolate-scope')
.getVisibleText();
});
return await PageObjects.header.getToastMessage();
}
/**

View file

@ -45,26 +45,23 @@ export function DiscoverPageProvider({ getService, getPageObjects }) {
});
}
loadSavedSearch(searchName) {
return this.clickLoadSavedSearchButton()
.then(() => {
getRemote().findByPartialLinkText(searchName).click();
})
.then(() => {
return PageObjects.header.waitUntilLoadingHasFinished();
});
async loadSavedSearch(searchName) {
await this.clickLoadSavedSearchButton();
const searchLink = await find.byPartialLinkText(searchName);
await searchLink.click();
await PageObjects.header.waitUntilLoadingHasFinished();
}
clickNewSearchButton() {
return testSubjects.click('discoverNewButton');
async clickNewSearchButton() {
await testSubjects.click('discoverNewButton');
}
clickSaveSearchButton() {
return testSubjects.click('discoverSaveButton');
async clickSaveSearchButton() {
await testSubjects.click('discoverSaveButton');
}
clickLoadSavedSearchButton() {
return testSubjects.click('discoverOpenButton');
async clickLoadSavedSearchButton() {
await testSubjects.click('discoverOpenButton');
}
async getCurrentQueryName() {

View file

@ -201,12 +201,13 @@ export function HeaderPageProvider({ getService, getPageObjects }) {
}
async isGlobalLoadingIndicatorVisible() {
return await testSubjects.find('globalLoadingIndicator', defaultFindTimeout / 5);
log.debug('isGlobalLoadingIndicatorVisible');
return await testSubjects.exists('globalLoadingIndicator');
}
async isGlobalLoadingIndicatorHidden() {
remote.setFindTimeout(defaultFindTimeout * 10);
return await remote.findByCssSelector('[data-test-subj="globalLoadingIndicator"].ng-hide');
log.debug('isGlobalLoadingIndicatorHidden');
return await find.byCssSelector('[data-test-subj="globalLoadingIndicator"].ng-hide', defaultFindTimeout * 10);
}
async getPrettyDuration() {

File diff suppressed because it is too large Load diff

View file

@ -2,64 +2,118 @@ export function FindProvider({ getService }) {
const log = getService('log');
const config = getService('config');
const remote = getService('remote');
const retry = getService('retry');
const defaultFindTimeout = config.get('timeouts.find');
class Find {
async withTimeout(timeout, block) {
try {
const remoteWithTimeout = remote.setFindTimeout(timeout);
return await block(remoteWithTimeout);
} finally {
remote.setFindTimeout(defaultFindTimeout);
}
}
async ensureElementWithTimeout(timeout, getElementFunction) {
try {
const remoteWithTimeout = remote.setFindTimeout(timeout);
return await retry.try(async () => {
const element = await getElementFunction(remoteWithTimeout);
// Calling any method forces a staleness check
element.isEnabled();
return element;
});
} finally {
remote.setFindTimeout(defaultFindTimeout);
}
}
async byName(selector, timeout = defaultFindTimeout) {
log.debug(`find.byName(${selector})`);
return await this.ensureElementWithTimeout(timeout, async remote => {
return await remote.findByName(selector);
});
}
async byCssSelector(selector, timeout = defaultFindTimeout) {
log.debug(`findByCssSelector ${selector}`);
const remoteWithTimeout = remote.setFindTimeout(timeout);
const element = await remoteWithTimeout.findByCssSelector(selector);
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
return element;
return await this.ensureElementWithTimeout(timeout, async remote => {
return await remote.findByCssSelector(selector);
});
}
async allByCssSelector(selector, timeout = defaultFindTimeout) {
log.debug('in findAllByCssSelector: ' + selector);
const remoteWithTimeout = remote.setFindTimeout(timeout);
let elements = await remoteWithTimeout.findAllByCssSelector(selector);
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
if (!elements) elements = [];
log.debug(`Found ${elements.length} for selector ${selector}`);
return elements;
return await this.withTimeout(timeout, async remote => {
return await retry.try(async () => {
let elements = await remote.findAllByCssSelector(selector);
if (!elements) elements = [];
// Force isStale checks for all the retrieved elements.
await Promise.all(elements.map(async element => await element.isEnabled()));
log.debug(`Found ${elements.length} for selector ${selector}`);
return elements;
});
});
}
async displayedByCssSelector(selector, timeout = defaultFindTimeout) {
log.debug('in displayedByCssSelector: ' + selector);
const remoteWithTimeout = remote.setFindTimeout(timeout);
const element = await remoteWithTimeout.findDisplayedByCssSelector(selector);
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
return element;
return await this.ensureElementWithTimeout(timeout, async remote => {
return await remote.findDisplayedByCssSelector(selector);
});
}
async existsByLinkText(linkText) {
async byPartialLinkText(partialLinkText, timeout = defaultFindTimeout) {
log.debug(`find.byPartialLinkText(${partialLinkText})`);
return await this.ensureElementWithTimeout(timeout, async remote => {
return await remote.findByPartialLinkText(partialLinkText);
});
}
async exists(findFunction, timeout = 1000) {
return await this.withTimeout(timeout, async remote => {
try {
await findFunction(remote);
return true;
} catch (error) {
return false;
}
});
}
async existsByLinkText(linkText, timeout = 1000) {
log.debug(`existsByLinkText ${linkText}`);
const remoteWithTimeout = remote.setFindTimeout(1000);
const exists = await remoteWithTimeout.findDisplayedByLinkText(linkText)
.then(() => true)
.catch(() => false);
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
return exists;
return await this.exists(async remote => await remote.findDisplayedByLinkText(linkText), timeout);
}
async existsByDisplayedByCssSelector(selector) {
async existsByDisplayedByCssSelector(selector, timeout = 1000) {
log.debug(`existsByDisplayedByCssSelector ${selector}`);
const remoteWithTimeout = remote.setFindTimeout(1000);
const exists = await remoteWithTimeout.findDisplayedByCssSelector(selector)
.then(() => true)
.catch(() => false);
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
return exists;
return await this.exists(async remote => await remote.findDisplayedByCssSelector(selector), timeout);
}
async existsByCssSelector(selector) {
async existsByCssSelector(selector, timeout = 1000) {
log.debug(`existsByCssSelector ${selector}`);
const remoteWithTimeout = remote.setFindTimeout(1000);
const exists = await remoteWithTimeout.findByCssSelector(selector)
.then(() => true)
.catch(() => false);
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
return exists;
return await this.exists(async remote => await remote.findByCssSelector(selector), timeout);
}
async clickByPartialLinkText(linkText, timeout = defaultFindTimeout) {
log.debug(`clickByPartialLinkText(${linkText})`);
const element = await retry.try(async () => await this.byPartialLinkText(linkText, timeout));
await element.click();
}
async clickByLinkText(linkText, timeout = defaultFindTimeout) {
log.debug(`clickByLinkText(${linkText})`);
const element = await this.byLinkText(linkText, timeout);
await element.click();
}
async clickByCssSelector(selector, timeout = defaultFindTimeout) {
log.debug(`clickByCssSelector(${selector})`);
const element = await this.byCssSelector(selector, timeout);
await element.click();
}
}