Selenium-webdriver JS - how to wait until an element is visible
It most likely is a Promise issue. Try this instead:
exports.waitForElement = function (locator, timeout) {
var timeout = timeout || DEFAULT_TIMEOUT;
return this.wait(until.elementLocated(locator), timeout);
};
exports.waitForVisibleElement = function (locator, timeout) {
var timeout = timeout || DEFAULT_TIMEOUT;
var element = this.wait(until.elementLocated(locator), timeout);
return this.wait(new until.WebElementCondition('for element to be visible ' + locator, function() {
return element.isDisplayed().then(v => v ? element : null);
}), timeout);
};
Usage:
driver.get("...");
driver.waitForElement(By.id("..."), 2000).getText().then(function(text){
console.log(text);
});
driver.waitForVisibleElement(By.id("..."), 2000).getText().then(function(text){
console.log(text);
});
NeuronQ
Programmer with 7+ yrs experience (backend, full-stack, a bit of ML-infra.). š” ā š - Can take complex projects from idea to delivery. āļø ā š¤ - Looking to bring my solid software-engineering experience to the areas of machine-learning- engineering and data-science-engineering - this is what Iām passionate about and where I feel I can make the strongest positive impact!
Updated on June 08, 2022Comments
-
NeuronQ almost 2 years
Using selenium-webdriver (api docs here), how can you wait for an element to be visible?
I have the following functions, part of a home-made set of testing helpers, and the first one works but the second one fails (eg. it times out wating for and element to be visible even if it exists - as confirmed by the first function that works - and is visible - as confirmed by all imaginable tests and inspections of the page html/css/js).
Here they are:
/** * Wait for an element to exist * * @param {object} locator * @param {int} timeout (ms) * * @return {Promise<element>} */ // !! THIS WORKS OK exports.waitForElement = function (locator, timeout) { var waitTimeout = timeout || DEFAULT_TIMEOUT; return this.wait(until.elementLocated(locator), waitTimeout) .then(() => { return this.findElement(locator); }); }; /** * Wait for an element to exist and then wait for it to be visible * * IMPORTANT: this is probable what you want to use instead of * waitForVisibleElement most of the time. * * @param {hash} locator * @param {number} timeout * * @return {Promise<element>} */ // !! THIS FAILS TO WORK AS EXPECTED exports.waitForVisibleElement = function (locator, timeout) { var waitTimeout = timeout || DEFAULT_TIMEOUT; return this.waitForElement(locator, waitTimeout) .then(el => { console.log('--- element found:', el); return this.wait(until.elementIsVisible(el), waitTimeout) .then(() => { console.log('--- element visible!'); // this is to make sure we are returning the same kind of // promise as waitForElement return this.findElement(locator); }); }); };
...I tested in multiple contexts, so it's no other cause of the problem then the code inside
waitForVisibleElement
but I can't seem to find any reason for why it does not work!
As clarification,
this
for that code ends up being the webdriver instance (the result ofnew webdriver.Builder().withCapabilities(webdriver.Capabilities.chrome()).build()
) after anaugment
method monkeypatches a given webdriver object... probably a questionable design pattern, but no the cause for my problem here :)
UPDATE: Apparently this only happens for XPath locators, like
{ xpath: '//*[contains(text(), "first name")]' }
... not that it makes any more sense now. Also, it's the same for Firefox, so it's not a weird chrome-webdriver thingy...