Selenium Wait Tutorial with All Strategies!

Selenium Wait strategies are a very critical topic in selenium test automation. In order to have non-flaky tests, we have to know explicit wait, implicit wait, fluent wait strategies. If we do not pay attention to Selenium Webdriver Wait in our projects, this will generally lead to non-reliable, intermittent, slow, and non-stable tests. Thus, we have to do proper synchronization to make our tests fast, robust, and reliable.

When we automate a web page, we should not wait too much, should not use static waits, and should not wait at the wrong point. I will try to explain Selenium Webdriver Wait Methods and how to work with expected conditions to synchronize your tests properly.

Selenium Expected Conditions for Wait in Selenium Properly

If we need some synchronization points, we should use the Selenium WebDriverWait methods. These methods help us to control our tests. We can wait at any specific point until an expected condition occurs. When that expected condition occurred, our test script goes on running from that point.

Before doing an example, it is better to talk about AJAX pages. AJAX expansion is Asynchronous JavaScript and AJAX allows the web page to retrieve small amounts of data from the server without refreshing the entire page and retrieving that data takes time. Thus, at that point, our test code should also wait. As I told you above, with Selenium WebdriverWait and ExpectedCondition methods, we can wait at any point and then continue the test execution when the element is found/visible. There are many wait.until(ExpectedConditions.anyCondition) methods, but I want to explain the most common ones below for selenium webdriver synchronization.

WebDriverWait Syntax

WebDriverWait wait = new WebDriverWait(driver, waitTime);

presenceOfElementLocated:

wait.until(ExpectedConditions.presenceOfElementLocated(locator));

It checks the element presence on the DOM of a page. This does not necessarily mean that the element is visible.

visibilityOfElementLocated:

 wait.until(ExpectedConditions.visibilityOfElementLocated(locator));

 It is for the element present in the DOM of a page is visible.

invisibilityOfElementLocated:

wait.until(ExpectedConditions.invisibilityOfElementLocated(locator));

It is for the element present in the DOM of a page is invisible.

elementToBeClickable:

wait.until(ExpectedConditions.elementToBeClickable(locator));

It is for the element to be clickable.

 Note: All Expected Conditions are listed here: ExpectedConditions

Now, it is time to do an example.

Test site: http://demos.telerik.com/aspnet-ajax/ajaxloadingpanel/functionality/explicit-show-hide/defaultcs.aspx

I want to explain the webpage and date form functionality. When you select a date, then a loader will occur immediately and after a period of time selected date will be seen in the Selected Dates pane. When you deselect the selected date, again a loader will occur and after a period of time selected date will be wiped away from the Selected Dates pane.

selenium wait

selenium wait for page to load

Test Scenario without Synchronization

  1. Go to the above URL.
  2. Maximize the window.
  3. Get the selected date text before selecting the date. (Before AJAX call)
  4. Print selected date text to the console. (Before AJAX call)
  5. Click 3rd day of the month.
  6. Get the selected date. (After AJAX call – This will be the failing point)
  7. Print selected date text to the console. (After AJAX call)
  8. Check the expected text and actual text.

Selected Text Area CSS Path: #ctl00_ContentPlaceholder1_Label1

3rd Day Xpath: .//*[contains(@class, ‘rcWeekend’)]/a[.=’3′]

Test Code(it will fail).

@Test
public void T01_FirstFailedSeleniumWaitTest() {
    //Get the selected date text before AJAX call
    String selectedDateTextBeforeAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextBeforeAjaxCall to the console
    System.out.println("selectedDateTextBeforeAjaxCall: " + selectedDateTextBeforeAjaxCall + "\n");

    //Find 3rd Day on the calendar
    WebElement thirdDayOfMonth = driver.findElement(By.xpath(".//*[contains(@class, 'rcRow')]/td/a[.='3']"));

    //Click 3rd Day
    thirdDayOfMonth.click();

    //Get the selected date text after AJAX call
    String selectedDateTextAfterAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextAfterAjaxCall to the console
    System.out.println("selectedDateTextAfterAjaxCall: " + selectedDateTextAfterAjaxCall + "\n");

    //Check the Actual and Expected Text
    Assertions.assertEquals(getExpectedDate(), selectedDateTextAfterAjaxCall);
}

Helper Date Method to Get Expected Date:

private String getExpectedDate() {
   LocalDate currentDate = LocalDate.now();
   Month     month       = currentDate.getMonth();
   int       year        = currentDate.getYear();
   DayOfWeek dayOfWeek   = LocalDate.of(year, month, 3).getDayOfWeek();
   return StringUtils.capitalize(dayOfWeek.toString().toLowerCase()) + ", " + StringUtils.capitalize(month.toString().toLowerCase())
           + " 3, " + year;
}

Console Output:

explicit wait in selenium

Test Scenario with Synchronization

  1. Go to the above URL.
  2. Maximize the window
  3. Declare WebDriverWait for 10 seconds.
  4. Wait until the presence of the date form container in DOM. (Synchronization Point)
  5. Get the selected date text before selecting the date. (Before AJAX call)
  6. Print selected date text to the console. (Before AJAX call)
  7. Click 3rd day of the month.
  8. Wait until invisibility of loader. (Synchronization Point)
  9. Wait until visibility of selected date text. (Synchronization Point – This is not necessary but I added this to show visibilityOfElementLocated)
  10. Get the selected date. (After AJAX call – This time it will not fail.)
  11. Print selected date text to the console. (After AJAX call)
  12. Check the expected text and actual text.

Date Container CSS Path: .demo-container.size-narrow

Loader CSS Path: .raDiv

Selected Text Area CSS Path: #ctl00_ContentPlaceholder1_Label1

3rd Day Xpath: .//*[contains(@class, ‘rcWeekend’)]/a[.=’3′]

Test Code (it will pass).

@Test
public void T02_FirstSeleniumWaitTest() {
    //Declare a Webdriver Wait
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

    //Wait until presence of container
    wait.until(
        driver -> ExpectedConditions.presenceOfElementLocated(By.cssSelector(".demo-container.size-narrow")).apply(driver));

    //Get the selected date text before AJAX call
    String selectedDateTextBeforeAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextBeforeAjaxCall to the console
    System.out.println("selectedDateTextBeforeAjaxCall: " + selectedDateTextBeforeAjaxCall + "\n");

    //Find 3rd Day on the calendar
    WebElement thirdDayOfMonth = driver.findElement(By.xpath(".//*[contains(@class, 'rcRow')]/td/a[.='3']"));

    //Click 3rd Day
    thirdDayOfMonth.click();

    //Wait until invisibility of loader
    new WebDriverWait(driver, Duration.ofSeconds(10)).until(
        driver -> ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(".raDiv")).apply(driver));

    //Wait until visibility of selected date text
    //Actually it is not necessary, I added this control to see an example of visibilityOfElementLocated usage.
    new WebDriverWait(driver, Duration.ofSeconds(10)).until(driver ->
        ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).apply(driver));

    //Find Selected Dates Text
    String selectedDateTextAfterAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextAfterAjaxCall to the console
    System.out.println("selectedDateTextAfterAjaxCall: " + selectedDateTextAfterAjaxCall + "\n");

    //Check the Actual and Expected Text
    Assertions.assertEquals(getExpectedDate(), selectedDateTextAfterAjaxCall);
}

Note: For Selenium 4.x you can use the below code for all waits if you face any problems. You need to send the webdriver instance to the functional interface’s apply method. 

new WebDriverWait(driver, Duration.ofSeconds(10)).until(
    driver -> ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(".raDiv")).apply(driver));

Console Output: 

implicit

Selenium Custom Expected Conditions

Sometimes we need, or we want to use expected conditions rather than built-in expected conditions. These custom expected conditions can make our tests more readable, tidy, and short. I want to show a sample custom ExpectedCondition class below. It checks “Does an element contain given text until defined WebdriverWait time?”

Custom ExpectedCondition by Using Named Class

//Custom Expected Condition Class
private class ElementContainsText implements ExpectedCondition<Boolean> {
    private String textToFind;
    private By     findBy;

    //Constructor (Set the given values)
    public ElementContainsText(final By elementFindBy, final String textToFind) {
        this.findBy = elementFindBy;
        this.textToFind = textToFind;
    }

    //Override the apply method with your own functionality
    @Override
    public Boolean apply(WebDriver webDriver) {
        //Find the element with given By method (By CSS, XPath, Name, etc.)
        WebElement element = webDriver.findElement(this.findBy);

        //Check that the element contains given text?
        return element.getText().contains(this.textToFind);
    }

    //This is for log message. I override it because when test fails, it will give us a meaningful message.
    @Override
    public String toString() {
        return ": \"Does " + this.findBy + " contain " + this.textToFind + "?\"";
    }
}

In the above class (named class) you can see that I did the below stuff:
–    Implemented ExpectedContion<Boolean> interface.
–    Set FindBy and testToFind values in the constructor.
–    Override the apply method to implement “Does the given element contains the given text?” functionality. (We should put our logic in here.)
–    Override the String method because when the test fails, I want to see a more meaningful message. It is shown below.

explicit

Example: Let’s do the same example that I showed and coded the “Working with WebDriverWait and ExpectedConditions” section but now we will use our custom “ElementContainsText” class.

Test website is: http://demos.telerik.com/aspnet-ajax/ajaxloadingpanel/functionality/explicit-show-hide/defaultcs.aspx

Selected Text Area CSS Path: #ctl00_ContentPlaceholder1_Label1

3rd day of the month Xpath: .//*[contains(@class, ‘rcWeekend’)]/a[.=’3′]

Test Scenario with Custom ExpectedCondition by Using Named Class:

  1. Go to above URL.
  2. Maximize the window
  3. Declare WebDriverWait for 10 seconds.
  4. Wait until the presence of the date form container in DOM. (Synchronization)
  5. Get the selected date text before selecting the date. (Before AJAX call)
  6. Print selected date text to the console. (Before AJAX call)
  7. Click 3rd day of the month.
  8. (-) Removed: Wait until invisibility of loader. (We will not use built-in ExpectedCondition)
  9. (+) Added: Use custom-named ExpectedCondition (Synchronization)
  10. Get the selected date. (After AJAX call)
  11. Print selected date text to the console. (After AJAX call)
  12. Check the expected text and actual text.
@Test
public void T03_CustomExpectedConditionWithNamedClassTest() {
    //Declare a Webdriver Wait
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

    //Wait until presence of container
    wait.until(driver -> ExpectedConditions.presenceOfElementLocated(By.cssSelector(".demo-container.size-narrow")).apply(driver));

    //Get the selected date text before AJAX call
    String selectedDateTextBeforeAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextBeforeAjaxCall to the console
    System.out.println("selectedDateTextBeforeAjaxCall: " + selectedDateTextBeforeAjaxCall + "\n");

    //Find 3rd January on the calendar
    WebElement thirdDayOfMonth = driver.findElement(By.xpath(".//*[contains(@class, 'rcRow')]/td/a[.='3']"));

    //Click 3rd Day
    thirdDayOfMonth.click();

    //This time we are using custom ExpectedCondition
    wait.until(
        driver -> new ElementContainsText(By.cssSelector("#ctl00_ContentPlaceholder1_Label1"), String.valueOf(year)).apply(driver));

    //Find Selected Dates Text
    String selectedDateTextAfterAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextAfterAjaxCall to the console
    System.out.println("selectedDateTextAfterAjaxCall: " + selectedDateTextAfterAjaxCall + "\n");

    //Check the Actual and Expected Text
    Assertions.assertEquals(getExpectedDate(), selectedDateTextAfterAjaxCall);
}

Custom ExpectedCondition by Using Anonymous Class

Sometimes you may want to synchronize your test with Adhoc(Inline) ExpectedCondition for selenium webdriver synchronization. This can be done with an anonymous class. If you do synchronization in this way, you can still override the apply method, but you cannot use a constructor. The anonymous class is located in until () block, and we can write our synchronization logic in the apply method.

//AdHoc Wait with Anonymous Class (Synchronization)
wait.until((ExpectedCondition<Boolean>) webDriver -> {
    return webDriver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().contains(String.valueOf(year));
});

Example: Now, let’s do the same example that is shown below sections by using an anonymous class. Test scenario, URL, and CSS, XPath paths of the elements are the same.

Test Scenario with Custom ExpectedCondition by Using Anonymous Class:

  1. Go to test URL.
  2. Maximize the window
  3. Declare WebDriverWait for 10 seconds.
  4. Wait until the presence of the date form container in DOM. (Synchronization)
  5. Get the selected date text before selecting the date. (Before AJAX call)
  6. Print selected date text to the console. (Before AJAX call)
  7. Click 3rd day of the month.
  8. (-) Removed: Wait until invisibility of loader. (We will not use built-in ExpectedCondition!)
  9. (-) Removed: Use custom-named ExpectedCondition class. (We will not use it!)
  10. (+) Added: Use custom anonymous ExpectedCondition
  11. Get the selected date. (After AJAX call)
  12. Print selected date text to the console. (After AJAX call)
  13. Check the expected text and actual text.
@Test
public void T04_CustomExpectedConditionWithAnonymousClassTest() {
    //Declare a Webdriver Wait
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

    //Wait until presence of container
    wait.until(driver -> ExpectedConditions.presenceOfElementLocated(By.cssSelector(".demo-container.size-narrow")).apply(driver));

    //Get the selected date text before AJAX call
    String selectedDateTextBeforeAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextBeforeAjaxCall to the console
    System.out.println("selectedDateTextBeforeAjaxCall: " + selectedDateTextBeforeAjaxCall + "\n");

    //Find 3rd Day of the month on the calendar
    WebElement thirdOfJanuary = driver.findElement(By.xpath(".//*[contains(@class, 'rcRow')]/td/a[.='3']"));

    //Click 3rd of Month
    thirdOfJanuary.click();

    //AdHoc Wait with Anonymous Class (Synchronization)
    wait.until(webDriver -> webDriver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().contains(String.valueOf(year)));

    //Find Selected Dates Text
    String selectedDateTextAfterAjaxCall = driver.findElement(
        By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextAfterAjaxCall to the console
    System.out.println("selectedDateTextAfterAjaxCall: " + selectedDateTextAfterAjaxCall + "\n");

    //Check the Actual and Expected Text
    Assertions.assertEquals(getExpectedDate(), selectedDateTextAfterAjaxCall);
}

Custom ExpectedCondition by Wrapping Anonymous Class in a Method

Actually, using an anonymous class for synchronization is a kind of hard-coded coding style and it is not so flexible. However, when you encapsulate an anonymous class in a method, your selenium webdriver synchronization code will be more flexible and reusable. The sample code is shown below.

Implementation:

private ExpectedCondition<Boolean> textDisplayed (final By elementFindBy, final String text){
    return webDriver -> webDriver.findElement(elementFindBy).getText().contains(text);
}

How to call wrapped anonymous class:

//Wrapped Anonymous Class Call
wait.until(textDisplayed(By.cssSelector("#ctl00_ContentPlaceholder1_Label1"), String.valueOf(year)));

Example: The Same example is done with the wrapped anonymous class below. (I do not want to write the SAME scenario again. It is as same as the previous ones.)

@Test
public void T05_CustomExpectedConditionWithWrappedAnonymousClassTest() {
    //Declare a Webdriver Wait
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

    //Wait until presence of container
    wait.until(driver -> ExpectedConditions.presenceOfElementLocated(By.cssSelector(".demo-container.size-narrow")).apply(driver));

    //Get the selected date text before AJAX call
    String selectedDateTextBeforeAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextBeforeAjaxCall to the console
    System.out.println("selectedDateTextBeforeAjaxCall: " + selectedDateTextBeforeAjaxCall + "\n");

    //Find Day of the Month on the calendar
    WebElement thirdDayOfMonth = driver.findElement(By.xpath(".//*[contains(@class, 'rcRow')]/td/a[.='3']"));

    //Click 3rd Day of the month
    thirdDayOfMonth.click();

    //Wrapped Anonymous Class (Synchronization)
    wait.until(driver -> textDisplayed(By.cssSelector("#ctl00_ContentPlaceholder1_Label1"), String.valueOf(year)).apply(driver));

    //Find Selected Dates Text
    String selectedDateTextAfterAjaxCall = driver.findElement(By.cssSelector("#ctl00_ContentPlaceholder1_Label1")).getText().trim();

    //Print selectedDateTextAfterAjaxCall to the console
    System.out.println("selectedDateTextAfterAjaxCall: " + selectedDateTextAfterAjaxCall + "\n");

    //Check the Expected and Actual Text
    Assertions.assertEquals(getExpectedDate(), selectedDateTextAfterAjaxCall);
}

What is Fluent Wait in Selenium?

One of the wait types for selenium webdriver synchronization is FluentWait. It defines the maximum amount of time to wait for a condition and specifies an interval period to check that status. Also, you can configure the FluentWait to ignore specific types of exceptions such as NoSuchElementExceptions when trying to locate an element on the page. WebdriverWait is developed on top of FluentWait. Thus, with FluentWait we can declare a wait with additional functionalities. FluentWait methods and their meanings are listed below:

//FluentWait Declaration
FluentWait<WebDriver> wait = new FluentWait<>(driver)
    .withTimeout(Duration.ofSeconds(timeoutSeconds)) //Set timeout
    .pollingEvery(Duration.ofMillis(100)) //Set query/check/control interval
    .withMessage("Timeout occured!") //Set timeout message
    .ignoring(NoSuchElementException.class); //Ignore NoSuchElementException

Note: Also you can use WebDriverWait fluently. I want to show a sample syntax below.

new WebDriverWait(driver, Duration.ofSeconds(10))
    .pollingEvery(Duration.ofMillis(100))
    .withMessage("It is a timeout message!");

The difference between WebDriverWait and FluentWait is,

  • FluentWait can apply ANYTHING (WebElement, String, etc.) and returns anything.
  • WebdriverWait can apply ONLY Webdriver and returns anything

Example: The Same example is written with FluentWait. I found an element with FluentWait, and I also check an ExpectedCondition with FluentWait. You can find the details in the comments. (I do not want to write the same scenario again. It is as same as the previous ones.)

@Test
public void T06_FluentWaitTest() {
    //Using findElement method to find selectedText element until timeout period.
    WebElement selectedTextElement = findElement(driver, By.cssSelector("#ctl00_ContentPlaceholder1_Label1"), 5);
    //SelectedDateElement
    String selectedDateBeforeAjaxCall = selectedTextElement.getText();
    //Print selectedDateTextBeforeAjaxCall to the console
    System.out.println("selectedDateTextBeforeAjaxCall: " + selectedDateBeforeAjaxCall + "\n");
    //Find 3rd Day on the calendar with findElement method which
    //comprises FluentWait implementation and returns Web element.
    WebElement thirdDayOfMonth = findElement(driver, By.xpath(".//*[contains(@class, 'rcWeekend')]/a[.='3']"), 5);
    //Click 3rd Day
    thirdDayOfMonth.click();
    //Call method which comprises of FluentWait implementation
    //It will wait until period time and checks the given locator's text contains year
    //If it contains then it will return whole text
    By locator = By.cssSelector("#ctl00_ContentPlaceholder1_Label1");
    String selectedDateAfterAjaxCall = textContainsKeyword(driver, locator, 10, String.valueOf(year));
    //Print selectedDateTextAfterAjaxCall to the console
    System.out.println("selectedDateTextAfterAjaxCall: " + selectedDateAfterAjaxCall + "\n");
    //Check the Expected and Actual Text
    Assertions.assertEquals(getExpectedDate(), selectedDateAfterAjaxCall);
}

//**Helper Methods*/
//Using FluentWait in a method with ExpectedCondition
private String textContainsKeyword(WebDriver driver, By locator, int timeoutSeconds, String keyword) {
    //FluentWait Declaration
    FluentWait<WebDriver> wait = new FluentWait<>(driver)
        .withTimeout(Duration.ofSeconds(timeoutSeconds)) //Set timeout
        .pollingEvery(Duration.ofMillis(100)) //Set query/check/control interval
        .withMessage("Timeout occured!") //Set timeout message
        .ignoring(NoSuchElementException.class); //Ignore NoSuchElementException
    //ExpectedCondition: Wait until text contains keyword until timeout period and return the whole text
    //If text does not contains keyword until timeout period, return null.
    return wait.until((ExpectedCondition<String>) webDriver -> {
        if (webDriver.findElement(locator).getText().contains(keyword)) {
            return webDriver.findElement(locator).getText();
        } else {
            return null;
        }
    });
}

//Find element with FluentWait
private static WebElement findElement(WebDriver driver, By locator, int timeoutSeconds) {
    //FluentWait Declaration
    FluentWait<WebDriver> wait = new FluentWait<>(driver)
        .withTimeout(Duration.ofSeconds(timeoutSeconds)) //Set timeout
        .pollingEvery(Duration.ofMillis(100)) //Set query/check/control interval
        .withMessage("Timeout occured!") //Set timeout message
        .ignoring(NoSuchElementException.class); //Ignore NoSuchElementException
    //Wait until timeout period and when an element is found, then return it.
    return wait.until(webDriver -> driver.findElement(locator));
}

Implicit Wait vs Explicit Wait in Selenium 

Explicit waits are simply WebdriverWait and FluentWait with expected conditions for Selenium Webdriver Synchronization. We can define a wait with extra functionalities for a specific condition. Generally, we use built-in ExpectedConditions or our custom ExpectedCondition for elements to become visible, clickable, invisible, etc.

The implicit wait is the wait that waits for a given time period before findElement or findElements methods cannot find the web element on the page and throw an element not found exception. During the implicit wait period, if the element is not available and WebDriver cannot find it, then WebDriver will wait for the defined implicit wait time to find that element once again the last time before throwing ElementNotFound exception. Its syntax is shown below.

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

We defined await with 30 seconds timeout period. When we do not designate the timeout period with the implicit wait, the default timeout will always be  0. In other words, “Default implicit wait is zero”. This makes us think about our synchronization and makes it very explicit, robust, and maintainable.

Implicit Wait

Explicit Wait

It is easier to write tests faster with less code but it is RISKY! It needs extra codes (logic) for synchronization and it is more ROBUST!
The default timeout period is 0. You can set the timeout with FluentWait or WebDriver Wait and it will wait until ExpectedCondition will meet.
You don’t need to think about ExpectedConditions, you just set the timeout period for synchronization. You need to think about certain ExpectedConditions to ensure synchronization.
It is hard to fix synchronization problems later. Your only option is to alter the implicit timeout period. You can fix your synchronization problems by changing your ExpectedCondition and timeouts.
If the implicit wait time is too long, sometimes it takes too much time to get feedback when your test has not worked. If you use a long implicit wait time, it will wait for the same time for every element. It checks the presence of elements. Explicit Wait waits until the ExpectedCondition is going to occur. It checks certain conditions.


Note:
Some web pages are displayed with javascript, the elements of that page are already present in the browser DOM, but are not visible. Implicit wait only waits for an element to appear in the DOM, so it returns immediately and at that time if that element is not visible and if you try to interact with it, you will get NoSuchElementException. You can test any element that is visible or clickable with the below methods.

public WebElement getWhenVisible(By locator, int timeout) {
    WebElement element = null;
    WebDriverWait wait = new WebDriverWait(driver, timeout);
    element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
    return element;
}
public void clickWhenReady(By locator, int timeout) {
    WebDriverWait wait = new WebDriverWait(driver, timeout);
    WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator));
    element.click();
}

Implicit Wait in Selenium Example

Test site: http://the-internet.herokuapp.com/dynamic_loading/2

Start Button CSS Path: #start>button

Result Text CSS Path: #finish>h4

Test Scenario with Custom ExpectedCondition by Using Named Class:

  1. Go to the above URL.
  2. Maximize the window
  3. Define an implicit wait (If you declare a timeout such as 2 seconds, the test will fail.)
  4. Find the start button.
  5. Click the start button.
  6. Wait result text will appear and find it.
  7. Check result text is “Hello World!”

Test Code:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.MethodName.class)
public class ImplicitWaitExample {
    private        WebDriver driver;
    private static String    url = "http://the-internet.herokuapp.com/dynamic_loading/2";

    //Setup Driver
    @BeforeAll
    public void setupTest() {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.navigate().to(url);
        driver.manage().window().maximize();
    }

    @Test
    public void ImplicitWaitTest() {
        // wait for 10 seconds implicitly
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

        //Get the selected date text before AJAX call
        WebElement startButton = driver.findElement(By.cssSelector("#start>button"));

        //Click the button
        startButton.click();

        //Find the result text
        WebElement resultText = driver.findElement(By.cssSelector("#finish>h4"));

        //Check the Expected and Actual Text
        Assertions.assertEquals("Hello World!", resultText.getText().trim());
    }

    //Close Driver
    @AfterAll
    public void quitDriver() {
        driver.quit();
    }
}

Selenium Wait for Page to Load

By using the below command the Selenium WebDriver will wait for a page to load before throwing an error. You can also set time out as an argument. In the below code, we set the timeout duration as 20 seconds.

Syntax:

driver.manage().timeouts().pageLoadTimeout(20, SECONDS); 

Selenium Webdriver Wait Suggestions

  • Wrap custom wait in a method.
  • If you want to see meaningful messages when your custom wait fails, override the toString method to implement more meaningful synchronization error messages.
  • If you use the same WebDriver and WebDriverWait then create a waiting variable and use all the test scripts. Do not repeat using “new WebDriverWait”. Make your test code more readable.
  • Before interacting with any element, please wait for it. ;-)
  • Try to use explicit wait more rather than implicit wait. It is more robust and less risky.
  • “Right synchronization” makes your test robust and durable! Please pay attention to synchronization while you are coding your automation scripts.

I wrote an article for “How to wait for Asynchronous Behaviour” such as JQuery, JS loadings, AJAX Calls, Angular waits. 

You can check it here: How to Wait Angular JavaScript AJAX in Selenium

Github Project

https://github.com/swtestacademy/selenium-examples/tree/main/src/test/java/wait 

Thanks,
Onur

9 thoughts on “Selenium Wait Tutorial with All Strategies!”

    • Hi Raj, please write your problems in here. We will try to help you. For AJAX pages, you can also use JavascriptExecutor. Please check Selenium-11: Execute JavaScript with JavascriptExecutor post.

      Reply
  1. Hi

    Its an excellent article. I have little doubt
    I want to click on the Calendar Change icon next to Calendar so that i can get it clicked through WebDriver
    and go to previous Month i.e. January Month from Current March month. But, its not locating correctly to
    this particular element and thus, not able to click.
    Can you please guide me. Thanks

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.