How can I ask the Selenium-WebDriver to wait for f

2019-01-01 08:48发布

问题:

I\'m working on a Java Selenium-WebDriver. I added

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

and

WebElement textbox = driver.findElement(By.id(\"textbox\"));

because my Applications takes few seconds to load the User Interface. So I set 2 seconds implicitwait. but I got unable to locate element textbox

Then I add Thread.sleep(2000);

Now it works fine. Which one is a better way?

回答1:

Well, there are two types of wait: explicit and implicit wait. The idea of explicit wait is

WebDriverWait.until(condition-that-finds-the-element);

The concept of implicit wait is

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

You can get difference in details here.

In such situations I\'d prefer using explicit wait (fluentWait in particular):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

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

    return  foo;
};

fluentWait function returns your found web element. From the documentation on fluentWait: An implementation of the Wait interface that may have its timeout and polling interval configured on the fly. Each FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition. Furthermore, the user may configure the wait to ignore specific types of exceptions whilst waiting, such as NoSuchElementExceptions when searching for an element on the page. Details you can get here

Usage of fluentWait in your case be the following:

WebElement textbox = fluentWait(By.id(\"textbox\"));

This approach IMHO better as you do not know exactly how much time to wait and in polling interval you can set arbitrary timevalue which element presence will be verified through . Regards.



回答2:

If using webdriverJs (node.js),

driver.findElement(webdriver.By.name(\'btnCalculate\')).click().then(function() {
    driver.sleep(5000);
});

The code above makes browser wait for 5 seconds after clicking the button.



回答3:

This thread is a bit older, but thought I\'d post what I currently do (work in progress).

Though I\'m still hitting situations where the system is under heavy load and when I click a submit button (e.g., login.jsp), all three conditions (see below) return true but the next page (e.g., home.jsp) hasn\'t started loading yet.

This is a generic wait method that takes a list of ExpectedConditions.

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

I have defined various reusable ExpectedConditions (three are below). In this example, the three expected conditions include document.readyState = \'complete\', no \"wait_dialog\" present, and no \'spinners\' (elements indicating async data is being requested).

Only the first one can be generically applied to all web pages.

/**
 * Returns \'true\' if the value of the \'window.document.readyState\' via
 * JavaScript is \'complete\'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = \"if (typeof window != \'undefined\' && window.document) { return window.document.readyState; } else { return \'notready\'; }\";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals(\"complete\");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns \'true\' if there is no \'wait_dialog\' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id(\"F\"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println(\"EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: \" + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the \'spinner\' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className(\"spinner\"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

Depending on the page, I may use one or all of them:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

There are also predefined ExpectedConditions in the following class: org.openqa.selenium.support.ui.ExpectedConditions



回答4:

Using Thread.sleep(2000); is an unconditional wait. If your test loads faster you will still have to wait. So in principle using implicitlyWait is the better solution.

However, I don\'t see why implicitlyWait does not work in your case. Did you measure if the findElement actually takes two seconds before throwing an exception. If so, can you try to use WebDriver\'s conditional wait as described in this answer?



回答5:

I like to use custom conditions. Here\'s some code in Python:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id(\"textbox\")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

Whenever you need to wait, you can do it explicitly by checking existance of a certain element (such element may vary from page to page). find_elements_by_id returns list - empty or not, you have just to check.



回答6:

click appears to be blocking? - here\'s another way to wait if you\'re using WebDriverJS:

driver.findElement(webdriver.By.name(\'mybutton\')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

The code above waits after the button is clicked for the next page to load and then grabs the source of the next page.



回答7:

Thread.sleep(5000);

This did help me but InterruptedException exception needs to be taken care of. So better surround it with try and catch:

try {
    Thread.sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

OR

Add throws declaration:

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

I would prefer the second one since one can then use sleep() as many times as it wants and avoid the repetition of try and catch block every time wherever sleep() has been used.



回答8:

Sometimes implicit wait seems to get overridden and wait time is cut short. [@eugene.polschikov] had good documentation on the whys. I have found in my testing and coding with Selenium 2 that implicit waits are good but occasionally you have to wait explicitly.

It is better to avoid directly calling for a thread to sleep, but sometimes there isn\'t a good way around it. However, there are other Selenium provided wait options that help. waitForPageToLoad and waitForFrameToLoad have proved especially useful.



回答9:

Implicitly wait and Thread.sleep Both are used for synchronization only..but the difference is we can use Implicitly wait for entire program but Thread.sleep will works for that single code only..Here my suggestion is use Implicitly wait once in the program when every time your Webpage will get refreshed means use Thread.sleep at that time..it will much Better :)

Here is My Code :

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get(\"https://www.flipkart.com\");
    WebElement ele=driver.findElement(By.cssSelector(\".menu-text.fk-inline-block\"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}


回答10:

Implicit Wait: During Implicit wait if the Web Driver cannot find it immediately because of its availability, the WebDriver will wait for mentioned time and it will not try to find the element again during the specified time period. Once the specified time is over, it will try to search the element once again the last time before throwing exception. The default setting is zero. Once we set a time, the Web Driver waits for the period of the WebDriver object instance.

Explicit Wait: There can be instance when a particular element takes more than a minute to load. In that case you definitely not like to set a huge time to Implicit wait, as if you do this your browser will going to wait for the same time for every element. To avoid that situation you can simply put a separate time on the required element only. By following this your browser implicit wait time would be short for every element and it would be large for specific element.



回答11:

Sometimes implicit wait fails, saying that an element exists but it really doesn\'t.

The solution is to avoid using driver.findElement and to replace it with a custom method that uses an Explicit Wait implicitly. For example:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

There are additional reasons to avoid implicit wait other than sporadic, occasional failures (see this link).

You can use this \"element\" method in the same way as driver.findElement. For Example:

    driver.get(\"http://yoursite.html\");
    element(By.cssSelector(\"h1.logo\")).click();

If you really want to just wait a few seconds for troubleshooting or some other rare occasion, you can create a pause method similar to what selenium IDE offers:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}


回答12:

Answer : wait for few seconds before element visibility using Selenium WebDriver go through below methods.

implicitlyWait() : WebDriver instance wait until full page load. You muse use 30 to 60 seconds to wait full page load.

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

ExplicitlyWait WebDriverWait() : WebDriver instance wait until full page load.

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id(\"Year\")).sendKeys(allKeys);

Note : Please use ExplicitlyWait WebDriverWait() to handle any particular WebElement.



回答13:

I prefer the following code to wait for 2 seconds.

for(int i=0; i<2 && driver.findElements(By.id(\"textbox\")).size()==0 ; i++){
   Thread.sleep(1000);
}


回答14:

Thread.sleep(1000);

is the worse: being a static wait, it will make test script slower.

driver.manage().timeouts.implicitlyWait(10,TimeUnit.SECONDS);

this is a dynamic wait

  • it is valid till webdriver existence or has a scope till driver lifetime
  • we can implicit wait also.

Finally, what I suggest is

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

with some predefined conditions:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • It is also dynamic wait
  • in this the wait will only be in seconds
  • we have to use explicit wait for a particular web element on which we want to use.