Selenium C# Tutorial: Synchronization in Selenium WebDriver

While building a test automation project for a complex web application using Selenium WebDriver, we need to ensure that the test flow from beginning to end is maintained for reliable test automation.


When tests are executed, it is common that the application under test does not always respond with the same speed as you may expect when creating your tests leading to an "ElementNotVisibleException" error. For example, it might take a few seconds for a status message to appear, a window to open, or an element to be enabled.


You can handle these anticipated timing issues by synchronizing your tests to the actual delays in the web application under test to ensure that each test waits until your application is ready before performing a certain step that may fail, which will consume time again in debugging.

Before diving into the solution, let's cover the two main categories related to synchronization:


Unconditional - In this scenario, we specify timeout only. This means that we stop the test execution until a certain amount of time passes and then proceed further. For example, Thread.Sleep(7000);//Stop code execution for 7 seconds


The main disadvantage in this approach is the chance of unnecessary waiting time in the test execution even though the element is ready to be tested.


Conditional Synchronization - We specify a condition along with the timeout value. The test framework waits to check for the condition and then decides to continue the test flow or come out if nothing happens.


In Selenium, we have implicit Wait and Explicit Wait conditional statements.



Synchronizing a test with an implicit wait

The Selenium WebDriver provides an implicit wait method to poll the Document Object.

Model (DOM) for a certain amount of time (work only for "FindElement" and "FindElements" statements). If WebDriver cannot find an element, it will wait for a defined amount of time for the element to appear in the DOM.


When an implicit wait is implemented in tests, it is set with a default value of 0 and will be set for the whole life of the WebDriver object instance (applied immediately once we initiate the WebDriver).


If we set implicit wait, find element will stop throwing an “ElementNotVisibleException” if the element is not found in the first instance; instead, it will wait for the timeout to expire and then proceeds further.


Before rushing and using it in your code, please note that using an implicit wait may slow down your test execution when an application responds as expected (no delays), as it waits for each element appearing in the DOM and increase the overall time it will take to complete execution flow.


Example using an implicit wait:

static IWebDriver driver;    

[ClassInitialize]
public static void ClassInitialize()
{
driver = new ChromeDriver();
//Set the Implicit Wait time Out to 10 Seconds
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);         driver.Navigate().GoToUrl("https://www.agilequalitymadeeasy.com/");
}

Note: Try to Minimize or avoid using an implicit wait in your tests and try to

synchronization issues with an explicit wait, which provides more control when compared with an implicit wait.


Summary:

  • Once set, the implicit wait is applied for the entire life of the WebDriver instance.

  • The implicit wait is declared with a single line (Usually on the setup function).

  • It is not suggested to use the implicit wait a large time counter (And to be more productive, make sure you minimize your use in this method).

  • By design, the default delay value of implicit wait is 0 seconds.

  • When used, the implicit wait may slow down the test execution because it will wait for each element appearing in the DOM.

  • The implicit wait can be changed numerous times (No Limitation) through the session of the IWebDriver.

  • The default polling time is 250 milliseconds (means that WebDriver will search the element in DOM after every 250 milliseconds until he finds it or the time specified is ended).

  • An implicit wait can be set with different time frames (Hours, Minutes, Seconds Etc.).



Synchronizing a test with an explicit wait

The Selenium WebDriver provides WebDriverWait and ExpectedCondition classes for

Implementing an explicit wait. The ExpectedCondition class (present in the OpenQA.Selenium.Support.UI namespace in C#) provides a set of predefined conditions to wait before proceeding further in the code. These two classes allow us to implement an explicit wait that we can use for synchronizing tests, which provides better control when compared with an implicit wait. Unlike an implicit wait, explicit wait in selenium will wait for certain conditions to occur. The conditions could be waiting for the presence of the web element, waiting for the element to become visible, etc.


It is recommended that you implement an explicit wait in cases where synchronization is needed, and the rest of the tests are working fine. Another advantage of explicit wait compared to implicit wait is that it will not wait to the MAX time-out before executing the test. If the condition for the explicit wait is satisfied, the wait condition is exited, and the execution will continue.


Another point worth mentioning is that when using explicit wait, it will not apply the time the driver instance is alive (similar to Implicit wait); explicit wait works only on the specific web element on which it is set, rather than all the elements on the page.


As I mentioned at the beginning, to define an explicit wait, selenium WebDriver provides two classes that we will use during the implementation of an explicit wait:



The WebDriverWait Class

Provides the ability to wait for a condition during the code execution and validate if an element is present/visible/enabled/disabled etc.

The ExpectedCondition Class

Provides a set of common conditions (that we can use in the WebDriverWait command) that tell the driver to wait before proceeding to the next code based on a predefined condition.


Here are the major class members (Feel free to explore the remaining once):

Note: Starting from Selenium WebDriver version 3.11, the ExpectedCondition class is no longer available and has now moved to a new separate NuGet package (DotNetSeleniumExtras.WaitHelpers, respectively).


Step 1: Using NuGet, search for DotNetSeleniumExtras.WaitHelpers,

Step 2: Import that namespace into your class.

Let us look into different examples for using the above scenarios:

public class UnitTest1
    {
        static IWebDriver driver;
        //Create an instance of the WebDriverWait Class
        static WebDriverWait Driver_Wait;
        IWebElement tmpElement;

[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
driver = new ChromeDriver();        driver.Navigate().GoToUrl("https://www.agilequalitymadeeasy.com/")
/*            
waits up to 20 seconds before throwing Exception (TimeoutException Timed out after 20 seconds waiting for visibility of element) or if it finds the element,it will return in 0 - 20 seconds.
*/
            
Driver_Wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20))  
}

[TestMethod]        
public void TitleValidation()
{
//Validate that the Page URL contains a specific string         Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.TitleContains("Quality Assurance | AgileQualityMadeEasy"));
         
//add Additional code here
}

[TestMethod]        
public void UrlValidation()
{
//An expectation for the URL of the current page to be a specific URL.            
            Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.UrlContains("agilequalitymadeeasy"));

/*Other alternatives:
Option 1: 
            Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.UrlMatches("agilequalitymadeeasy"));

Option 2: 
            Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.UrlToBe("agilequalitymadeeasy"));
            */
}

[TestMethod]        
[ExpectedException(typeof(WebDriverTimeoutException))]  
public void UrlValidationNegativetest()
{           Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.UrlContains("x"));         
}
                   
[TestMethod]
public void ElementExists()
{
//An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible.
try
{
//Unmark this code if you want the test to pass
              //Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(By.Id("comp-khbyvzuo1label")));

                Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(By.Id("cyvzuo1label")));

}
catch (Exception e)
{
//In this example, the test will fail so we will print the error and mark the test as failed
Console.WriteLine(e.Message);
Assert.IsFalse(true);
}
}

[TestMethod]
public void ValidateTextToBePresentInElement()
{
//validate if an element contains a specific text 
tmpElement = driver.FindElement(By.Id("comp-khbyvzuo1label"));
            Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.TextToBePresentInElement(tmpElement,"Blog"));
}
       
[TestMethod]
public void isElementVisible()
{
//Validate that a specific element is both present and visible in DOM
            Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.Id("comp-khbyvzuo1label")));

//Note: We can do the same with multiple elements: 
//IList<IWebElement> ListOfElements = driverwaitinstance.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.id("cyvzuo1label")));
}

[TestMethod]
public void isElementClickable()
{
//Validate that a specific element is Clickable 
            Driver_Wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(By.Id("comp-khbyvzuo1label")));
}

[ClassCleanup]
public static void ClassCleanup()
{
 driver.Quit();}
    }
}


Difference between Implicit and Explicit wait

Synchronizing a test with an explicit wait

The fluent wait is another variant in Selenium that lets you control the MAX amount of time the driver needs to wait for the defined condition to appear. This is done by defining the frequency at which the driver checks for the element before throwing ElementNotVisibleException.


When using the FluentWait instance, we can specify:

1. The MAX amount of time to wait for a condition.

2. The frequency with which FluentWait has to check the condition defined.

3. Ignore defined types of exceptions.


To put it simply, Fluent waits looks for an element repeatedly at regular intervals until it reaches the MAX amount of time defined for its condition or until the object is found. Fluent wait commands are most useful when delays in the app can take longer durations to load (often occurs in Ajax applications).


Fluent waits are also known in the industry as “smart waits” because they don’t wait out the entire duration defined in the test. Instead, the test will execute as soon as the element is detected and the condition specified in .until (condition) method becomes ‘true.’


Code:

{
static IWebDriver driver;
//Create an instance of the WebDriverWait Class
static WebDriverWait Driver_Wait;
IWebElement tmpElement;
DefaultWait<IWebDriver> fluentWait = new DefaultWait<IWebDriver>(driver);

[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://www.agilequalitymadeeasy.com/");
/*            
waits up to 20 seconds before throwing Exception
(TimeoutException Timed out after 20 seconds waiting for visibility of element) or if it finds the element,it will return in 0 - 20 seconds.
*/
Driver_Wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));            
}

[TestMethod]
public void fluentWaitExample()
{
// Waiting 15 seconds for an element to be present on the page, checking
// for its presence once every 250 Milliseconds.
fluentWait.Timeout = TimeSpan.FromSeconds(15);
fluentWait.PollingInterval = TimeSpan.FromMilliseconds(250);
            fluentWait.IgnoreExceptionTypes(typeof(NoSuchElementException));
fluentWait.Message = "Element not found, Test failed";
            fluentWait.Until(ExpectedConditions.PresenceOfAllElementsLocatedBy(By.Id("comp-khbyvzuo1label")));
}


24 views0 comments