Introduction
When you use Selenium WebDriver, Page Object pattern and waiting element loading complete are important when executing test case. Beside one, extension selector with jQuery, query selector helps you to easily interact with web page. This tip introduces how to use this one effectively.
Background
This tip helps you to write your automation test case smoothly with Page object design pattern and customize waiting for loading element to complete.
Using the Code
This code is based-on Selenium WebDiver extension of RaYell: https://github.com/RaYell/selenium-webdriver-extensions. Before using this source, you should download the extension by RaYell from github. To understand this code, you should read this link and research about Page object design pattern in Selenium at sample link: https://code.google.com/p/selenium/wiki/PageObjects or http://martinfowler.com/bliki/PageObject.html. In this source code, beside RaYell lib, I created 2 project, 1 for test, 1 for page object like the image below.
This sample test is used to reference, it follows from our project. You can imagine, we have one webpage, before we run every page, we must pass login page. Then, we do some command like create new item, check item create successfully.
In this source, I create InitializeTest
class for initializing driver configuration. After that, I write TeamTest
class inherited from InitializeTest
like image below:
I will explain some points in the source code...
Init WebDriver
, the first thing for selenium web driver. (Source: InitializeTest.cs)
[TestInitialize]
public void Init()
{
Driver.Initialize();
LoginPage.GoTo();
LoginPage.LoginAs("abc123").WithPassword("abc123").Login();
}
Sample case writing test case goes to Team page. We design one file for test and one file for page object. Here page object is Team.cs.
The first, TeamTest.cs will be inherited from InitializeTest.cs to pass login case. We write 4 methods to test this case including: GoTo
, GoToAddNewTeamPage
, CreateTeam
, IsExistTeam
.
[TestMethod]
public void Can_Add_New_Team()
{
Team.GoTo();
Team.GoToAddNewTeamPage();
AddNewTeam.CreateTeam(Constants.NewTeamName, Constants.NewTeamNote).Save();
Assert.IsTrue(Team.IsExistTeam(Constants.NewTeamName), "Fail To Add New Team!");
}
4 methods will be implemented in Team.cs page object.
public static void GoTo()
{
Driver.Instance.Navigate().GoToUrl("https://abcxyz/#/admin/teams");
}
public static void GoToAddNewTeamPage()
{
var rows = Driver.Instance.FindElements(By.JQuerySelector("td"));
Driver.Instance.FindElement(By.ClassName("glyphicon-plus")).Click();
}
public static bool IsExistTeam(string newTeamName)
{
GoTo();
Driver.Instance.FindElement(By.JQuerySelector
("input[placeholder='Search for Team Name...']")).SendKeys(newTeamName);
Driver.Instance.FindElement(By.JQuerySelector(".fa.fa-search")).Click();
var rows = Driver.Instance.FindElements(By.JQuerySelector("td"));
return rows.Any(row => row.FindElement(By.TagName("a")).Text == newTeamName);
}
As this source I mention, when you use AngularJS, Durandal...element will exist after compile and link function time. Therefore, if you find element immediately, element is not found and through exception. I had covered this case by adding customize in extension source code of library in file WebDriverExtensions.cs namespace Selenium.WebDriver.Extensions.JQuery
.
public static void WaitForPageToLoad(this IWebDriver driver, string script)
{
var timeout = new TimeSpan(0, 0, 30);
var wait = new WebDriverWait(driver, timeout);
var javascript = driver as IJavaScriptExecutor;
if (javascript == null)
throw new ArgumentException("driver", "Driver must support javascript execution");
wait.Until((d) =>
{
try
{
var result = javascript.ExecuteScript(script);
var isColection = result is IEnumerable<object> || result is IEnumerable;
if (isColection)
{
var count = (result as IEnumerable).Cast<object>().Count();
if (count > 0)
return true;
}
else
{
if (result != null)
return true;
}
return false;
}
catch (InvalidOperationException e)
{
return e.Message.ToLower().Contains("unable to get browser");
}
catch (WebDriverException e)
{
return e.Message.ToLower().Contains("unable to connect");
}
catch (Exception)
{
return false;
}
});
}
This code covers 2 cases:
- result is list element
- result is only 1 element
We are waiting until element exits after timeout. After timeout occurs, this return element exception is not found.
I will not explain more details about the API, you can reference in document to understand selector using jQuery extension.
I am so sorry I do not have the REAL source code for Page object design pattern.
Points of Interest
The Web Driver Extension library I reference from https://github.com/RaYell/selenium-webdriver-extensions is very interest. With the new version, you can use jQuery for your selector very easy and smoothly.
I want to say thank you to RaYell + those contributors of page object design pattern, coding sample for waiting loading element for more completion.
Enjoy your coding.
History
This is the first version of project. I will update changes soon.