Page Objects- Partial Classes String Properties- WebDriver C#

Design Patterns
Share
Partial Classes String Properties

Editorial Note: I originally wrote this post for the Test Huddle Blog. You can check out the original here, at their site.

This is the fifth article from the WebDriver Page Objects Series. It is dedicated to page objects using partial classes and exposing elements as string properties.

In the previous articles from the series, I showed you how to create more maintainable page objects through separating the code of the pages in three different files. Moreover, you are no more obligated to use the Selenium.Support NuGet package. The primary difference compared to the other versions of the pattern will be that here we will not expose the whole interface of the elements. Instead, we will use them as string properties, simplifying the API.

Test Case

We will once again automate the main Bing page. All of the code is placed inside the BingMainPage class.

Bing Main Page

Page Objects using String Properties Code

BingMainPage Initial Version

public partial class BingMainPage
{
private readonly IWebDriver _driver;
private readonly string _url = @"http://www.bing.com/";
public BingMainPage(IWebDriver browser) => _driver = browser;
public void Navigate() => _driver.Navigate().GoToUrl(_url);
public void Search(string textToType)
{
SearchBox.Clear();
SearchBox.SendKeys(textToType);
GoButton.Click();
}
}

BingMainPage String Properties’ Version

public partial class BingMainPage
{
private readonly IWebDriver _driver;
private readonly string _url = @"http://www.bing.com/";
public BingMainPage(IWebDriver browser) => _driver = browser;
public void Navigate() => _driver.Navigate().GoToUrl(_url);
public void Search(string textToType)
{
SearchBox = textToType;
GoButton.Click();
}
}

The difference here is that we do not call the SendKeys method anymore. Instead, we assign the value directly to the element’s property.

BingMainPage.Map Initial Version

public partial class BingMainPage
{
public IWebElement SearchBox
{
get
{
return this._driver.FindElement(By.Id("sb_form_q"));
}
}
public IWebElement GoButton
{
get
{
return this._driver.FindElement(By.Id("sb_form_go"));
}
}
public IWebElement ResultsCountDiv
{
get
{
return this._driver.FindElement(By.Id("b_tween"));
}
}
}

BingMainPage.Map String Properties Version

public partial class BingMainPage
{
public string SearchBox
{
get => _driver.FindElement(By.Id("sb_form_q")).Text;
set
{
var element = _driver.FindElement(By.Id("sb_form_q"));
element.Clear();
element.SendKeys(value);
}
}
public IWebElement GoButton => _driver.FindElement(By.Id("sb_form_go"));
public string ResultsCountDiv => _driver.FindElement(By.Id("b_tween")).Text;
}

As you can see we wrap the nitty gritty details of the WebDriver’s API here directly in the properties. Then return only the required information instead of the whole IWebElement object. This way the users of your pages/API will not be able to shoot themselves in the foot.

BingMainPage.Asserter Initial Version

public partial class BingMainPage
{
public void AssertResultsCount(string expectedCount) => Assert.AreEqual(ResultsCountDiv.Text, expectedCount);
}

As demonstrated, here we get the text in the element through the Text property of the element.

BingMainPage.Asserter String Properties Version

public partial class BingMainPage
{
public void AssertResultsCount(string expectedCount) => Assert.AreEqual(ResultsCountDiv, expectedCount);
}

The primary difference is that we access the inner text of the element without the call to the Text property.

Elements’ String Properties in Tests

[TestClass]
public class BingTests
{
private IWebDriver _driver;
[TestInitialize]
public void SetupTest()
{
_driver = new FirefoxDriver();
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);
}
[TestCleanup]
public void TeardownTest()
{
_driver.Quit();
}
[TestMethod]
public void SearchTextInBing_First()
{
var bingMainPage = new BingMainPage(_driver);
bingMainPage.Navigate();
bingMainPage.Search("Automate The Planet");
bingMainPage.AssertResultsCount("236,000 RESULTS");
}
[TestMethod]
public void SearchTextInBing_UseElementsDirectly()
{
var bingMainPage = new BingMainPage(_driver);
bingMainPage.Navigate();
bingMainPage.SearchBox = "Automate The Planet";
bingMainPage.GoButton.Click();
Assert.AreEqual(bingMainPage.ResultsCountDiv, "236,000 RESULTS");
}
}

You can create service methods for most common operations as we did with the Search method. However, you can use the elements’ string properties directly as shown in the example tests.

In future articles, I will share with you other modifications of the design pattern that can make your tests even more maintainable. You can find even more articles in the Design Patterns in Automated Testing Series.