Selenium - Wait for Javascript function to execute before continuing

20,076

Solution 1

** EDIT 3**

So we have:

DefaultSelenium selenium = new DefaultSelenium("localhost",4444,"*iexplore", "websiteURL");

Still you can use the command isVisible like this:

boolean doTheLoop = true;
    int i = 0;
    while (doTheLoop){      
        i = i+200;
        Thread.sleep(200);
        if (i>30000){
            doTheLoop = false;
        }
        if (!selenium.isVisible("id=the ID Of element")){
            doTheLoop = false;
      }      
}

Hope you will not end up in infinite loop.

I never worked with DefaultSelenium, so use please the isVisible() function the same way as you are using the click() for example.

Solution 2

You can use waitForCondition
And if you're using WebDriver, you can try WebDriverBackedSelenium or FluentWait.
I think this link will help.

Solution 3

You should try this. It waits until the specified timeout. And what it waits for is specified in the FluentWait-object. It waits until the Boolean gets true. So if your element is not visible any more, the Boolean gets true and the method stops waiting. The nice thing about this is that it only asks every 1 second if your element is visible instead of asking as fast as it can which makes no sense.

public static void wait(WebDriver driver, int timeout, final By locator){
    FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
       .withTimeout(timeout, TimeUnit.SECONDS)
       .pollingEvery(1, TimeUnit.SECONDS)
       .ignoring(NoSuchElementException.class)

    wait.until(new Function<WebDriver, Boolean>() {
        public Boolean apply(WebDriver driver) {
            WebElement element = driver.findElement(locator);
            return !element.isDisplayed();
        }
    });
}

EDIT: As you wrote in your comments and in your edit, it seems that you use Selenium 1. WebDriver is part of Selenium 2. So just get the wrapped driver like this:

Selenium selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "website-url");
CommandExecutor executor = new SeleneseCommandExecutor(selenium); 
WebDriver driver = new RemoteWebDriver(executor, new DesiredCapabilities());
Share:
20,076
Kevin Maschke
Author by

Kevin Maschke

Updated on July 09, 2022

Comments

  • Kevin Maschke
    Kevin Maschke almost 2 years

    I'm currently creating some test cases with Selenium and I've come across a problem.

    In my test case, the website I'm trying to walk through has a small form and a button to search. No problem filling the form and clicking the button. The problem comes once clicking the problem.

    Once clicked the button, this function is called:

    function muestraEspera(){
    document.getElementById("divCargando").style.display = "";
    }
    

    Basically, this makes visible a DIV which contains an "loading" image so the visitor do just see the image and wont be able to actually see the website loading the content until finished (the content is loaded with ajax).

    Once the content is loaded, this function is executed:

    function escondeEspera(){
    document.getElementById("divCargando").style.display = "none";
    }
    

    Which basically hides the "loading" DIV so the visitor can see the results.

    Now, I can't use SLEEPS because loading can take more or less, and because I need the real execution time of the website. Is there any way (using java - junit4) to make selenium wait until the second function is executed before continuing with the next steps?

    EDIT: I do use Selenium RC. To start the driver I use:

    public void setUp() throws Exception {
            selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "website-url");
            selenium.start();
        }
    

    At the end, the solution that worked perfectly for me, given by Pavel Janicek is:

    boolean doTheLoop = true;
          int i = 0;
          while (doTheLoop){      
          i= i+200;
          Thread.sleep(1000);
          if (i>30000){
            doTheLoop = false;
          }
          if (!selenium.isVisible("id=divCargando")){
             doTheLoop = false;
          }      
          if (selenium.isVisible("id=divCargando")){
                 doTheLoop = true;
              }      
         }
    
  • Kevin Maschke
    Kevin Maschke about 12 years
    Using ----- FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver) .withTimeout(200, TimeUnit.SECONDS) .pollingEvery(1, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class); wait.until(new Function<WebDriver, Boolean>() { public Boolean apply(WebDriver driver) { WebElement element = driver.findElement(divCargando); return !element.isDisplayed(); } }); ----- I do get this error: "Driver cannot be resolved to a variable"
  • Kevin Maschke
    Kevin Maschke about 12 years
    Both methods give me these errors: "driver cannot be resolved" and "The method isVisible() is undefined for the type WebElement"..
  • Kevin Maschke
    Kevin Maschke about 12 years
    How would you use it? I tried it with waitForCondition and I could not get it to work... :(
  • Pavel Janicek
    Pavel Janicek about 12 years
    I forgot to mention - the driver is instance of WebDriver. I will update the answer a little.
  • Pavel Janicek
    Pavel Janicek about 12 years
    The waitForCondition seems to be Selenium-IDE related. Will not work if you use WebDriver approach.
  • tester
    tester about 12 years
    Can you provide a stack trace? driver is an WebDriver instance, like FirefoxDiver or RemoteWebDriver.
  • Kevin Maschke
    Kevin Maschke about 12 years
    The thing is that I use selenium RC: selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "website-url");
  • Pavel Janicek
    Pavel Janicek about 12 years
    Or more generally - can you provide how do you initialize the WebDriver?
  • Kevin Maschke
    Kevin Maschke about 12 years
    I do use: selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "website-url"); To start the driver. Selenium RC.
  • Pavel Janicek
    Pavel Janicek about 12 years
    Editing once more. I will provide the quickest solution found: WebDriver driver = selenium.getWrappedDriver();
  • tester
    tester about 12 years
    You use Selenium 1. Just add the following after your DefaultSelenium: CommandExecutor executor = new SeleneseCommandExecutor(selenium); WebDriver driver = new RemoteWebDriver(executor, new DesiredCapabilities());
  • Kevin Maschke
    Kevin Maschke about 12 years
    Just one problem using this solution: "The method getWrappedDriver() is undefined for the type Selenium"
  • Kevin Maschke
    Kevin Maschke about 12 years
    Here I do get: "RemoteWebDriver cannot be resolved to a type"
  • tester
    tester about 12 years
    are you sure you imported org.openqa.selenium.remote.RemoteWebDriver ?
  • Pavel Janicek
    Pavel Janicek about 12 years
    Darn! I provided you the answer for WebDriverBackedSelenium class, which I am using sometimes. Never worked with DefaultSelenium class. Will have to look...
  • Kevin Maschke
    Kevin Maschke about 12 years
    SORRY!! I missed that one. I imported it and that error disappeared. Now the only error left is: "The type Function is not generic; it cannot be parameterized with arguments <WebDriver, Boolean>".
  • tester
    tester about 12 years
    Sure it can. the code which I posted works. Are you sure we are talking about the same Function-class? It is com.google.common.base.Function. And furthermore this thread is gonna turn into a Java-coding problem than the original problem with selenium. I tested the code I posted and it works and solves your problem.
  • Kevin Maschke
    Kevin Maschke about 12 years
    Thanks a lot for your help! But at the end the solution provided by Pavel Janicek worked like a charm. Thanks a lot :D I would give you a PLUS vote, but I haven't got enough rep.. :(
  • Kevin Maschke
    Kevin Maschke about 12 years
    Thanks a lot! This worked great! I just added: if (selenium.isVisible("id=divCargando")){ doTheLoop = true;} This way once the div is hidden, next step is done like a charm! Thank you very much!
  • Kevin Maschke
    Kevin Maschke about 12 years
    Can't mark two answers as solution. And the other one worked perfectly for me.
  • Pavel Janicek
    Pavel Janicek about 12 years
    Uff! At least something :) Happy testing to you ;)
  • tester
    tester about 12 years
    Thats what I meant. Mark HIS answer as solution. not mine.