Simplify Web Automation with the WebDriver Extension for C#
Tags: csharp, selenium
Published: 2023-05-25 05:08:19

Web automation has become an essential part of modern software development and testing. One popular framework for web automation is Selenium WebDriver, which provides a powerful set of tools for interacting with web browsers. In this blog post, we will explore a C# extension method that enhances the capabilities of Selenium WebDriver by simplifying the process of locating elements using XPath.

## Why use the WebDriver extension?

The WebDriver extension we will discuss offers several advantages over the standard WebDriver methods:

**1. Simplified element location**: The extension method allows you to locate elements using XPath in a more concise and readable manner. Instead of writing lengthy code to find elements, you can use the `WithXPath` method to locate them with a single line of code.

**2. Automatic retries**: The extension method incorporates a built-in retry mechanism, which can be useful when dealing with dynamic web pages or slow-loading elements. By specifying the maximum retry time and interval, you can ensure that the method waits for the element to become available before timing out.

**3. Handling common exceptions**: The extension method handles common exceptions that may occur during element location, such as TimeoutException, StaleElementReferenceException, and NoSuchElementException. This simplifies error handling and improves the reliability of your automation code.

## How to use the WebDriver extension

To use the WebDriver extension in your C# project, follow these steps:

### Step 1: Add the extension method to your project

Copy the provided C# code into a suitable location in your project, such as a helper class or a separate file.

```csharp
public static IWebElement WithXPath<TDriver>(this TDriver driver, string xpath, int maxRetryInSeconds = 40,
      int retryIntervalInMilliseconds = 500) where TDriver : IWebDriver =>
      driver.WithActiveElement(By.XPath(xpath), maxRetryInSeconds, retryIntervalInMilliseconds);

private static IWebElement WithActiveElement(this IWebDriver driver, By locateBy, int maxRetryInSeconds = 40,
      int retryIntervalInMilliseconds = 500)
{
  var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(maxRetryInSeconds))
  {
    PollingInterval = TimeSpan.FromMilliseconds(retryIntervalInMilliseconds),
    Message = $"Max element retry has reached at {maxRetryInSeconds} seconds",
  };

  wait.IgnoreExceptionTypes(new[]
    {typeof(TimeoutException), typeof(StaleElementReferenceException), typeof(NoSuchElementException)});

  return wait.Until(d =>
  {
    var element = d.FindElement(locateBy);

    if (!element.Displayed and !element.Enabled)
    {
      return null;
    }

    ((IJavaScriptExecutor) d).ExecuteScript("arguments[0].scrollIntoViewIfNeeded(true);", element);
    return element;
  }) ?? throw new WebDriverTimeoutException(wait.Message);
}
```

### Step 2: Set up the WebDriver

Create an instance of the WebDriver in your test or automation code, such as ChromeDriver or FirefoxDriver.

```csharp
// Set up the WebDriver
var driver = new ChromeDriver();
```

### Step 3: Locate elements using XPath

Instead of using the standard WebDriver methods like `FindElement(By.XPath(xpath))`, you can now use the `WithXPath` extension method on your WebDriver instance. Simply pass the XPath expression as a parameter to the method.

Here's an example of how to use the WebDriver extension:

```csharp
// Locate elements using XPath
var element = driver.WithXPath("//input[@id='username']");
```

In the above example, we use the `WithXPath` method to locate an input element with the id attribute equal to "username." The method will automatically retry until the element is found within the specified timeout.

**Note: Null-coalescing operator (??) for C# 8+**

As of C# 8, the null-coalescing operator (??) can be used to simplify the code and throw a `WebDriverTimeoutException` when the element is not found within the specified timeout. The null-coalescing operator works by returning the left-hand side expression if it is not null, or the right-hand side expression otherwise. In the case of the WebDriver extension, it can be used as follows:

```csharp
return wait.Until(d =>
{
  var element = d.FindElement(locateBy);

  if (!element.Displayed && !element.Enabled)
  {
    return null;
  }

  ((IJavaScriptExecutor) d).ExecuteScript("arguments[0].scrollIntoViewIfNeeded(true);", element);
  return element;
}) ?? throw new WebDriverTimeoutException(wait.Message);
```

By using the null-coalescing operator, the `Until` method will return the found element if it is not null, or the `throw new WebDriverTimeoutException(wait.Message)` expression will be executed, throwing the exception with the specified message.

## Conclusion

The WebDriver extension for C# simplifies the process of locating elements using XPath in Selenium WebDriver. With its concise syntax, built-in retry mechanism, and exception handling, the extension enhances the productivity and reliability of your web automation code. By incorporating this extension into your project, you can streamline your test automation efforts and improve the efficiency of your web application testing.