Classes of pages. IsLoaded property

Any web application consists of a number of web pages and each web page consists of a set of web elements such as blocks, text, buttons, links, pictures, etc., which are represented with HTML tags and scripts (on the client side, of course).

Basing on the principles of OOP programming and using PageObject design pattern assumes having a separate class for every kind of page. It makes test’s structure easier for understanding and for reading, and therefore it makes maintenance of the framework much easier.

I’ve created simple web site as the application for testing. It was made for being independent from third parties decisions and sudden changes of tested application. It’s pretty simple and old-style fashioned (I’m not a programmer or front-end designer), but it allows to demonstrate general approaches to testing of web applications. Like any other site this one has so called “start” or “home” page – the main page of the application.

clip_image002

Below I show how to describe the page in the framework and add it to the project.

In the Mapping project I created new folder named TestingWithSelenium. All the classes which represent web pages of the application will be located inside it.

clip_image003

The main page of the site consists of several parts as shown below:

clip_image005

1 – header

2 – left side menu

3 – inner content area

4 – advertisement block

5 – footer

Blocks 1, 2, 4 and 5 are common for most pages of the application. Inner content area (3) is unique for every page. Considering this I decided to pick out common elements into higher level abstract page where the blocks are described once and all the pages will inherit it.

Initially I added new class for this abstract page to the Mapping project. I named it MasterPage similar to ASP.NET approach.

clip_image007

This is class derived from WebPage class, parent class for all page classes. It is public and abstract.

namespace Mapping.TestingWithSelenium

{

public abstract class MasterPage : WebPage

{

}

}

Because of WebPage’s constructor takes IWebDriver instance as input parameter I added similar constructor to the child class:

public MasterPage(IWebDriver driver) : base(driver) { }

It is not possible to create an instance of MasterPage since it is abstract, so for testing I created class that represents home page of the application. This page inherits MasterPage.

clip_image009

using OpenQA.Selenium;

namespace Mapping.TestingWithSelenium

{

public class HomePage : MasterPage

{

public HomePage(IWebDriver driver) : base(driver) { }

}

}

To make the solution to be compiled I had to implement IsLoaded property of a page declared in WebPage class.

clip_image011

At least like this:

public override bool IsLoaded { get { return true; } }

At the moment the property does nothing but always returns true. It just allows the project to be compiled. For the entire implementation of the property I have to design a logic which indicates that the page is loaded.

Common practice for determination that a page is completely loaded is verification that some key elements of the page may be found, probably visible and available for interaction. There is no sense to verify all elements on the page because likely if key elements are loaded then all other are loaded too.

You should define by yourself which elements are most important for every page and which of them may be used as key elements. Some elements are loaded stable and fast, others may be loaded only in specific conditions or it requires some time for loading. You can define necessary elements doing experiments with your page and watching which of its elements are slowest, for example, or which will be used in tests and so on.

For the given page I decided that I can consider the page being loaded if the following elements are displayed:

· Page title – “Testing with Selenium” label

· One of menu items (for example, Home)

· content area block (iframe)

· “Hi all” text in the inner content

clip_image013

For the verification I have to find the elements on the page first, that is I have to know their locators in the DOM structure of the page. Then I have to pass the locators to the driver for finding the elements. And finally I have to check elements’ Displayed property.

Finding element locator with Firebug and Firepath

I useMozilla Firefoxbrowser and its plug-ins Firebug and Firepath for finding locators of web elements on a web page.

clip_image014

clip_image015

clip_image016

After the plug-ins are installed you can open the page you are testing in Firefox browser and turn on Firebug.

This way:

clip_image017

Or this one:

clip_image019

Or just hit F12 key.

You will see this window appeared:

clip_image021

Open Firepath tab, select type of locator you want to get (XPath, CSS or Sizzle), activate ‘Click an element in the page to inspect’ button and then click on the target element.

clip_image023

Below in the Firebug panel you can see html code of selected element, it is highlighted with blue.

In my application the title label is represented with

<div style=”float: left; width: 20%; color: white; font-size: x-large; fontweight: bold; padding: 0 2%;”>

As you can see in the HTML code the title is a block element with text inside. There is no id or any other unique attributes of the element, so the most unique property of the block is its text.

Firebug has returned absolute path to the element: html/body/div[1]/div[1]/div[1]. The title may be easily found with this locator but I tend not to use absolute paths because after almost any update of the page the locator will be broken.

I redefined the path in the following manner: .//div[contains(.,’Testing with Selenium’) and not(div)]. You can immediately check the path with Firebug. Enter the locator into XPath field and click Eval. Firebug will show you all elements on the page found with this locator. In my case the element is the only one.

clip_image025

Hence, the title is located by path XPath = //div[contains(.,’Testing with Selenium’) and not(div)] which mean that it is <div> element containing text ‘Testing with Selenium’ and not containing any other <div> elements inside.

Playing with the tool you can find locator of other elements. For example, link Home: XPath = //a

, content area: ID = innerContent, text ‘Hi all’: XPath = //p[1]. Notice that the element is located inside innerContent iframe. Therefore, the driver must be switched to the innerContent iframe first and only then the element may be found.

clip_image027

IsLoaded property

Let’s go back to Home page IsLoaded property. At the moment there is HomePage class created in the framework with its IsLoaded property always returning true. Now I want to implement the property that it returns actual state of the page. I decided that if four key elements located on the page are loaded I may consider that the entire page is loaded as well.

Here are the elements:

● Page title (white text Testing with Selenium in left upper corner):

XPath = //div[contains(.,’Testing with Selenium’) and not(div)]

● Menu item Home: XPath = //a

● Inner content area – iframe with id ‘innerContent’: ID = innerContent

● Text ‘Hi all’ inside inner content area: XPath = //p[1]

IsLoaded property must return true if all the elements are found and visible, otherwise it returns false.

public override bool IsLoaded

{

get

{

try

{

Driver.SwitchTo().DefaultContent();

var title = Driver.FindElement(By.XPath(“//div[contains(.,’Testing with Selenium’) and not(div)]”));

var menu = Driver.FindElement(By.XPath(“//a

“));

var frame = Driver.FindElement(By.Id(“innerContent”));

bool displayed = title.Displayed && menu.Displayed && frame.Displayed;

Driver.SwitchTo().Frame(“innerContent”);

var text = Driver.FindElement(By.XPath(“//p[1]”));

return (displayed && text.Displayed);

}

catch { return false; }

}

}

Since element title, menu and frame belongs to MasterPage it is sensible to move it out from HomePage class and put into MasterPage. So, IsLoaded property should be implemented in MasterPage class as well.

MasterPage.IsLoaded:

public override bool IsLoaded

{

get

{

try

{

Driver.SwitchTo().DefaultContent();

var title = Driver.FindElement(By.XPath(“//div[contains(.,’Testing with Selenium’) and not(div)]”));

var menu = Driver.FindElement(By.XPath(“//a

“));

var frame = Driver.FindElement(By.Id(“innerContent”));

return (title.Displayed && menu.Displayed && frame.Displayed);

}

Catch { return false; }

}

}

Updated HomePage.IsLoaded:

public override bool IsLoaded

{

get

{

try

{

var masterPageIsLoaded = base.IsLoaded;

Driver.SwitchTo().Frame(“innerContent”);

var text = Driver.FindElement(By.XPath(“//p[1]”));

return (masterPageIsLoaded && text.Displayed);

}

catch { return false; }

}

}

The property may be used successfully as is but such approach conflicts with main principles of the framework and OOP principles in general.

First, the properties’ work is not logged and likely I will hardly know what is going on during testing and what the result is. Second, all the elements may be used for testing and therefore I must to describe them again on the page class. Thus the elements will be defined at least twice. It is not a good approach, I tend to describe every element only once. It helps to maintain them much easier in future.

That’s why the properties will be updated soon.

[row]
[column lg=”4″ md=”12″ sm=”12″ xs=”12″ ]
ClickableWebElement class [/column]
[column lg=”4″ md=”12″ sm=”12″ xs=”12″ ]
Table Of Content
[/column]
[column lg=”4″ md=”12″ sm=”12″ xs=”12″ ]
Custom classes for description of web elements instead of IWebElement interface
[/column]
[/row]

Leave a Reply

Archives