Skip to content

Page objects [Deprecated]

Dor Blayzer edited this page Apr 13, 2024 · 1 revision

Information about Page Object design pattern.. Information about PageFactory. Here is java version. Sorry. The .Net version works the similar way.

The common use case looks as usual.

A single element:

using OpenQA.Selenium.Support.PageObjects;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
IWebElement targetElement;

or

using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Appium.Interfaces;
using OpenQA.Selenium.Appium;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
IMobileElement<AppiumWebElement> targetElement;

A list of elements:

using OpenQA.Selenium.Support.PageObjects;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
IList<IWebElement> targetElements;

or

using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Appium.Interfaces;
using OpenQA.Selenium.Appium;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
IList<AppiumWebElement> targetElement;

The following is also available:

A single element property:

using OpenQA.Selenium.Support.PageObjects;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
private IWebElement TargetElement
{
       set; get;
}

or

using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Appium.Interfaces;
using OpenQA.Selenium.Appium;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
private IMobileElement<AppiumWebElement> TargetElement
{
       set; get;
}

A list of elements property:

using OpenQA.Selenium.Support.PageObjects;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
private IList<IWebElement> TargetElements
{
       set; get;
}

or

using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Appium.Interfaces;
using OpenQA.Selenium.Appium;
...

[FindsBy(How = How.ClassName, Using = "theClassOfAnElement")]
private IList<AppiumWebElement> TargetElement
{
       set; get;
}

How to populate fields and properties

using OpenQA.Selenium.Appium.PageObjects;
using OpenQA.Selenium.Support.PageObjects;
...

PageObject screenOrPage = new PageObject();
ISearchContext context;
...
PageFactory.InitElements(context, screenOrPage , new AppiumPageObjectMemberDecorator());

or

using OpenQA.Selenium.Appium.PageObjects;
using OpenQA.Selenium.Support.PageObjects;
...

PageObject screenOrPage = new PageObject();
ISearchContext context;
TimeOutDuration timeSpan = new TimeOutDuration(new TimeSpan(0, 0, 0, 5, 0)); //time 
//of the waiting for elements in general
...
PageFactory.InitElements(context, screenOrPage , new 
AppiumPageObjectMemberDecorator(timeSpan));

What fields and properties are populated:

If there is a single element then IWebElement and IMobileElement<> are available. The list of IMobileElement<> parameters is below:

                - IWebElement

                - RemoteWebElement

                - AppiumWebElement

                - AndroidElement

                - IOSElement

If there is a list of elements then IList<> with same parameters is can be populated.

The described use case is good when Page/Screen object is for web testing or testing on Android/IOS only. Locators such as css, linkText and partialLinkText are invalid for Android/IOS native app testing.

Advanced use cases

If Page/Screen object is supposed to be reused in crossplatform testing (web testing + Android/iOS native app testing) and a target service/app has the similar UI for all plaforms then

using OpenQA.Selenium.Appium.PageObjects.Attributes;
using OpenQA.Selenium.Support.PageObjects;
...

[FindsBy(How = How.Id, Using = "TargetID")] //this locator will be used for Html content at desktop
//or mobile browser/webview
[FindsByIOSUIAutomation(Name = "The name of the iOS native element")] //this locator will be used
//for an iOS native content
[FindsByAndroidUIAutomator(Accessibility = "The accessibility id of the Android native element")] 
//this locator will be used for an Android native content
[FindsBySelendroid(ID = "The selendroid mode element Id")]
IWebElement target;

//the same is available for lists and element/list properties.

If there are few possible locators

using OpenQA.Selenium.Appium.PageObjects.Attributes;
using OpenQA.Selenium.Support.PageObjects;
...

[FindsBy(How = How.Id, Using = "TargetID1", Priority = 1)] [FindsBy(How = How.Id, Using = "TargetID2", Priority = 2)] 
[FindsByIOSUIAutomation(Name = "The name of the iOS native element", Priority = 1)] 
[FindsByIOSUIAutomation(Id = "The id of the iOS native element", Priority = 2)] 
//and so on
//The "Priority" property defines a queue of the using of the locator to find elements 
IWebElement target;

If there is chained searching

using OpenQA.Selenium.Appium.PageObjects.Attributes;
using OpenQA.Selenium.Support.PageObjects;
...

[FindsBySequence] //is used with Selenium FindsBy
[FindsBy(How = How.Id, Using = "TargetID1", Priority = 1)] [FindsBy(How = How.Id, Using = "TargetID2", Priority = 2)] 
[MobileFindsBySequence(Android = true, IOS = true)] //"Android" and "IOS" properties = true
//mean that the chained searching uses defined locators on these platforms/with these automation
//types
[FindsByIOSUIAutomation(Name = "The name of the iOS native element", Priority = 1)] 
[FindsByIOSUIAutomation(Id = "The id of the iOS native element", Priority = 2)] 
//and so on
IWebElement target;

If desired elements should match few locators

then

using OpenQA.Selenium.Appium.PageObjects.Attributes;
using OpenQA.Selenium.Support.PageObjects;
...

[FindsByAll] //is used with Selenium FindsBy
[FindsBy(How = How.Id, Using = "TargetID1", Priority = 1)] [FindsBy(How = How.ClassName, Using = "TargetID2", Priority = 2)] 
[MobileFindsByAll(Android = true, IOS = true)] //"Android" and "IOS" properties = true
//mean that found elements should match all defined locators on these platforms/with these
// automation types
[FindsByIOSUIAutomation(Name = "The name of the iOS native element", Priority = 1)] 
[FindsByIOSUIAutomation(ID = "The id of the iOS native element", Priority = 2)] 
//and so on
IWebElement target;

If time of the waiting for elements differs from general

using OpenQA.Selenium.Appium.PageObjects.Attributes;
using OpenQA.Selenium.Support.PageObjects;
...

[WithTimeSpan(Seconds = 15)]
[FindsBy(How = How.Id, Using = "TargetID")] 
//and so on
IWebElement target;

If it needs to change general timeout of the waiting for elements

using OpenQA.Selenium.Appium.PageObjects;
using OpenQA.Selenium.Support.PageObjects;
...

PageObject screenOrPage = new PageObject();
ISearchContext context;
TimeOutDuration duration = new TimeOutDuration(new TimeSpan(0, 0, 0, 5, 0)); //time 
//of the waiting for elements in general
...
PageFactory.InitElements(context, screenOrPage , new 
AppiumPageObjectMemberDecorator(duration));

//tons of user's code
TimeSpan newTime = new TimeSpan(0, 0, 0, 20, 500);
duration.WaitingDuration = newTime; //and here we go!

If there is need to use original element

There is no problem to get and use the target instance of IWebElement subclass from IList field/property. What about a single element field or property? At this case you are free to do the following for your purposes:

using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Internal;
...

[FindsBy(How = How.Id, Using = "TargetID")] 
//and so on
IWebElement target;

...
IWebElement original = ((IWrapsElement) target).WrappedElement;