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 => 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?



