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.

Moiz Raja
  • 5,612
  • 6
  • 40
  • 52

2 Answers2

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.

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
coudy
  • 13,218
  • 5
  • 23
  • 26
  • Hello guys, this solution gave me `Error: This Deferred has already been resolved.` Did this work for you? – haejeong87 Aug 29 '13 at 01:39
  • 8
    instead, `driver.isElementPresent(locator);` worked for me, for those of you who could not use this solution :) – haejeong87 Aug 29 '13 at 01:58
  • 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. – mpen Sep 06 '13 at 16:07
  • 1
    @coudy (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... – rinogo Jan 24 '14 at 16:25
  • 1
    @rinogo 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. – coudy Jul 10 '14 at 14:22
  • 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. – Max Aug 25 '18 at 20:39
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)

Katie
  • 45,622
  • 19
  • 93
  • 125
jsdevel
  • 1,539
  • 1
  • 12
  • 8
  • 2
    You should try Webdriver Js (https://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" (https://code.google.com/p/selenium/wiki/WebDriverJs#Control_Flows). By using this, your code will be even more readable! – cSn May 12 '14 at 18:21
  • @cSn, I really love that the Webdriver JS team has made the effort to look as synchronous as possible; however, as was mentioned [here](http://stackoverflow.com/questions/16882860/selenium-webdriver-js-explicit-wait/18797176?noredirect=1#comment32167323_16882922), 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). – jsdevel May 13 '14 at 05:41
  • [Here](https://gist.github.com/jsdevel/99a5d736fbdd6c86d455) is a gist that shows a version of the solution written in a purely synchronous way using `webdriver-sync`. – jsdevel May 13 '14 at 05:55