Let’s first quickly understand the concept of page object before jumping in and writing it.
Page object to be concise, creating a relationship between each and every test method we execute, which can be done by returning page object in every method we call. This will ensure that our test execution is happening on the right page rather waiting for some object (UI) in a wrong page.
Well the above description sounds weird, since we are expecting a method to return object of page to perform another operation, but how to do that and how does it looks ?
Let’s consider we have a scenario like this, we have to
login in our AUT (Application Under Test) and hit
settings page and perform
email configuration of
Admin and check the logged in user got admin privilege.
Well, this can be done simply by writing methods for each and every operation mentioned and call them in sequence (Which is done more often) and perform operation, but the downside of this way of operation is
- What if the page in sequence not loaded
- What if the AUT landing in wrong page (rather landing in settings page, if it lands in logout page)
- How to manage objects (UI object) of all pages
- Duplication of code (functionalities)
In order to cope the above problems, page objects can be used.
Let’s see them as an example
public class Login
{
public Login Login(string user)
{
//Perform some operation of login
//Return Login Reference
return new Login();
}
}
public class Settings
{
public Settings settings(string SettingType)
{
//Perform some operation
//Return settings
return new Settings();
}
}
public class EmailConfig
{
public EmailConfig EmailConfiguration(string configType)
{
//Return Email config
return new EmailConfig();
}
}
public class TestClass
{
public void testCreateEmailConfig()
{
Login log = new Login();
Settings userSetting = log.Settings("Admin");
EmailConfig config = userSetting.EmailConfiguration("Admin");
}
}
As you all could see from the above
C# code snippet, we are creating separate class for each and every page and writing functionalities which those page provide in the same class itself and also each page will return the reference of the
Type of the page, this makes us even more comfortable to make sure we are performing operations on the correct page.
Well, whatever we have seen so far is how we can create classes based on the functionalities within a page, now let’s see how we can write objects within a page. Objects for a page can be identified by either
ID, CSS, XPath, LinkText etc, hence the object in the Page Object pattern can be written by referencing the namespace
using OpenQA.Selenium.Support.PageObjects
and the objects can decorated using annotations in square brackets as shown below
//User Name
[FindsBy(How = How.ID, Using = "UserName")]
public IWebElement txtUserName { get; set; }
//Password
[FindsBy(How = How.ID, Using = "Password")]
public IWebElement txtPassword { get; set; }
//LoginWidget
[FindsBy(How = How.XPath, Using = ".//div[@widget-name='Login']//table]")]
public IWebElement wdLogin { get; set; }
As shown in the above code, the UserName and Password textbox are identified using ID and Widget has been identified using Xpath. The
FindsBy is an attribute found under
using OpenQA.Selenium.Support.PageObjects namespace. The attribute has named parameter type such as
CustomFinderType, How, Priority and
Using. The
How is an enumeration type and has following
Once all the objects are written in the Page object class (Here
Login class), we need to first initialize the Page object using
InitElements method of
PageFactory class. The code to initialize the object can be written like the one shown below
PageFactory.InitElements(driver, new Login); // Driver is the instance variable of FF driver
Here is how the Login class will looks like
public class Login
{
public static void LoginAdmin()
{
LoginPageObject ObjectLogin = new LoginPageObject();
//User Name
ObjectLogin.txtUserName.SendKeys("admin");
//Password
ObjectLogin.txtPassword.SendKeys("admin");
}
}
The intelli-sense will give us the entire object as shown
This will give us the understanding and overview of how to work with Page Object.
Thanks,
Karthik KK
Hi Karthik.
This is very helpful, and makes the project much leaner.
I wonder though if its possible to use the FindsBy attribute with Element wait?
something like this?
[FindsBy(How = How.ID, Using = “UserName”)]
public IWebElement txtUserName { get; set; }
WaitforElement(By.??(txtUserName ),2000);
Instead of
WaitforElement(By.Id(“txtUserName “),2000);
Thanks in advance.
Yes you can by customizing the code, but there is even more neat way of doing it something like this
txtUserName.WaitForElement(2000);
You need to use extension methods, which you can learn from here http://executeautomation.com/blog/using-c-extension-methods-for-selenium/
Hope it helps !
Thanks,
Karthik KK