Selenium WebDriver JS - Explicit Wait
Asked Answered
E

2

21

I am using the selenium-webdriverjs. I want to wait for a certain element to be displayed for which I have created an explicit wait as follows and it works just fine,

var displayed = false;
driver.wait(function(){
    driver.findElement(locator).isDisplayed().then(function(value){
        displayed = value;
    });
    return displayed;
}, timeout);

Is this the best I can do or is there a better way to do this? The reason I ask is that the first time ever the wait callback is called (in my case) it will always return false. Only subsequently when the isDisplayed promise is executed will the value of displayed change.

Elysium answered 2/6, 2013 at 12:41 Comment(0)
U
28

Your code is mixing a synchronous return with asynchronous callbacks, the following code should do the right thing:

return driver.wait(function() {
    return driver.findElement(locator).isDisplayed();
}, timeout);

The inner function will return a promise that driver.wait will wait for and will take its value (true/false) as the waiting condition.

Unseasonable answered 2/6, 2013 at 12:50 Comment(6)
Hello guys, this solution gave me Error: This Deferred has already been resolved. Did this work for you?Origami
instead, driver.isElementPresent(locator); worked for me, for those of you who could not use this solution :)Origami
The "timeout" appears to be in milliseconds, by the way. I know it usually is, in JavaScript, but this is a binding so I wasn't too sure. Docs didn't bother to specify. Thanks for the answer. Haeljeong87s tip worked for me.Smalls
@Unseasonable (and all): You mentioned that Moiz Raza was "mixing a synchronous return with asynchronous callbacks". I'm having the same problem - I don't know which are which! Is there a way to know which callbacks/functions are synchronous and which are asynchronous? I'm finding this all terribly confusing...Pyonephritis
@Pyonephritis Generally, an operation that takes time or involves external actors (browser, filesystem) will be async, and the function will take a callback. Some "by default" async functions have sync counterparts with "Sync" appended to the function name.Unseasonable
There is no chance this to work because driver.findElement will return error already the first time it does not find the element. You need findElements and then return true for non-zero element count.Secundine
B
5

To avoid much of the confusion involved in the asynchronous flavors of webdriver and js, you could give webdriver-sync a try: https://npmjs.org/package/webdriver-sync

It's been my experience that the async versions of the webdriver API become difficult to read after too many nested callbacks.

This of course assumes that you don't have requirements to remain asynchronous.

Disclaimer: I am the creator of this piece of software (webdriver-sync)

Bebebebeerine answered 14/9, 2013 at 0:42 Comment(3)
You should try Webdriver Js (code.google.com/p/selenium/wiki/WebDriverJs) which is the "official" javascript version of webdriver provided by Selenium folks. Additionally, it's not difficult to read as webdriver js provides a "promises manager" that let you write/execute your code in a sync way by using "Control Flows" (code.google.com/p/selenium/wiki/WebDriverJs#Control_Flows). By using this, your code will be even more readable!Clyde
@cSn, I really love that the Webdriver JS team has made the effort to look as synchronous as possible; however, as was mentioned here, it is often confusing to know what is synchronous and what is not. Even with a promise based approach, you still end up with scenarios where you fall into nested callbacks (like doing something after you've retrieved an element's text).Bebebebeerine
Here is a gist that shows a version of the solution written in a purely synchronous way using webdriver-sync.Bebebebeerine

© 2022 - 2024 — McMap. All rights reserved.