Web element extensions in C# that I find useful

I really miss the Watir API when working with WebDriver in C#. Whilst the C# WebDriver bindings are fantastic (thanks Se team!), simple things I like to do with the Watir API aren’t present, so I find myself writing web element extension methods to make my life easier (and code cleaner). Here’s some of my favourites: (wouldn’t it be neat to see them in WebDriver one day. I can dream…)

IWebElement.Set(text)

I have always found .SendKeys to be an unusual method, as I haven’t come across an instance where I want to fire keys at a field instead of just setting it to a value. So .Set(text) is usually one of the first web element extensions that I write:

namespace WebDriverExtensions
{
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using OpenQA.Selenium;
  using OpenQA.Selenium.Firefox;

  public static class WebElementExtensions
  {
    public static void Set(this IWebElement e, string text)
    {
      e.Clear();
      e.SendKeys(text);
    }
  }

  [TestClass]
  public class ExtensionUnitTests
  {
    [TestMethod]
    public void SetTextField()
    {
      var driver = new FirefoxDriver();
      driver.Navigate().GoToUrl("data:text/html,<input type=\"text\" id=\"t\" />");
      var textField = driver.FindElement(By.Id("t"));
      textField.SendKeys("a");
      Assert.AreEqual("a", textField.GetAttribute("value"));
      textField.SendKeys("b");
      Assert.AreEqual("ab", textField.GetAttribute("value"));
      textField.Set("b");
      Assert.AreEqual("b", textField.GetAttribute("value"));
      driver.Quit();
    }
  }
}

SelectElement.SelectBySubText(subText)

The Selenium Support library provides some useful select element specific methods, but unfortunately the .SelectByText(partial) method doesn’t select by subtext (as advertised), so I wrote a .SelectBySubText(subText) method to actually do this.

namespace WebDriverExtensions
{
  using System.Linq;
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using OpenQA.Selenium;
  using OpenQA.Selenium.Firefox;
  using OpenQA.Selenium.Support.UI;

  public static class WebElementExtensions
  {
    public static string SelectBySubText(this SelectElement me, string subText)
    {
      foreach (var option in me.Options.Where(option =&gt; option.Text.Contains(subText)))
      {
        var optionText = option.Text;
        option.Click();
        return optionText;
      }
      me.SelectByText(subText);
      return subText;
    }
  }

  public class ExtensionUnitTests
  {
    [TestMethod]
    public void SelectBySubTextTest()
    {
      var driver = new FirefoxDriver();
      driver.Navigate().GoToUrl("data:text/html,VolvoSaab");
      var selectList = new SelectElement(driver.FindElement(By.Id("cars")));
      selectList.SelectByText("Volvo");
      Assert.AreEqual(selectList.SelectedOption.Text, "Volvo");
      selectList.SelectBySubText("Saa");
      Assert.AreEqual(selectList.SelectedOption.Text, "Saab");
      driver.Quit();
    }
  }
}

IWebElement.FindVisibleElement(by) and IWebElement.VisibleElementExists(by)

Web Apps I test often hide elements that are available to use, but unfortunately WebDriver still locates these (even though it won’t allow you to interact with them). So, I wrote two extensions: one to only find an element matching a selector that is visible, and another to check if a visible element exists matching a selector.

namespace WebDriverExtensions
{
  using System;
  using System.Linq;
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using OpenQA.Selenium;
  using OpenQA.Selenium.Firefox;

  public static class WebElementExtensions
  {
    public static IWebElement FindVisibleElement(this IWebDriver driver, By by)
    {
      var elements = driver.FindElements(by);
      foreach (var element in elements.Where(e => e.Displayed))
      {
        return element;
      }
      throw new NoSuchElementException("Unable to find visible element with " + @by);
    }

    public static bool VisibleElementExists(this IWebDriver driver, By by, Int32 implicitWait=10)
    {
      driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 0));
      var elements = driver.FindElements(by);
      var visibleElements = elements.Count(e => e.Displayed);
      driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, implicitWait));
      return visibleElements != 0;
    }
  }

  public class ExtensionUnitTests
  {
    [TestMethod]
    public void FindVisibleElements()
    {
      var driver = new FirefoxDriver();
      driver.Navigate().GoToUrl("data:text/html,<input  type=\"hidden\" class=\"myfield\" name=\"date-submitted\" value=\"Hidden\"><input class=\"myfield\" name=\"date-submitted\" value=\"Visible\">");
      var textField = driver.FindElement(By.ClassName("myfield"));
      Assert.IsFalse(textField.Displayed);
      var visibleTextField = driver.FindVisibleElement(By.ClassName("myfield"));
      Assert.IsTrue(visibleTextField.Displayed);
      Assert.AreEqual("Visible", visibleTextField.GetAttribute("value"));
      driver.Quit();
    }

    [TestMethod]
    public void VisibleElementExists()
    {
      var driver = new FirefoxDriver();
      driver.Navigate().GoToUrl("data:text/html,<input  type=\"hidden\" class=\"myfield\" name=\"date-submitted\" value=\"Hidden\"><input class=\"myfield\" name=\"date-submitted\" value=\"Visible\">");
      Assert.IsTrue(driver.VisibleElementExists(By.ClassName("myfield")));
      driver.Quit();
    }

    [TestMethod]
    public void VisibleElementDoesNotExist()
    {
      var driver = new FirefoxDriver();
      driver.Navigate().GoToUrl("data:text/html,<input  type=\"hidden\" class=\"myfield\" name=\"date-submitted\" value=\"Hidden\">");
      Assert.IsFalse(driver.VisibleElementExists(By.ClassName("myfield")));
      driver.Quit();
    }
  }
}

Summary

These are some web element extensions that I find useful. Do you have any? What would you like to see built into WebDriver?

Author: Alister Scott

Alister is an Excellence Wrangler for Automattic.

1 thought on “Web element extensions in C# that I find useful”

Comments are closed.