Keep Your Page Objects DRY

The page object pattern is an extremely important pattern that’s well described over at Selenium. If you don’t know about the pattern and haven’t read their article, go read it now.

Everything said in the article also applies to dialogs, so don’t be misled by the word page. They could just as well have written about dialog objects.

The article also suggested a wonderful practice that’s new to me:  Having a method in a page object return another page object. I’m now doing this whenever a method lands the application on a different page. Example:  Completing the sign-in on the sign-in page lands the app on the home page, so method SignInPage.SignIn returns a HomePage object.

So what can I add?  Well, DRYness! (Don’t Repeat Yourself!)

[This post originally emphasized inheritance. David Green commented that composition is more flexible. I agree, so I’ve revised the post.]

I’m going to talk about composition and inheritance here because the language I’m using is C#. The corresponding strategy in a different language might be different: Ruby mixins, Python modules, etc.

Let’s get to it. The web application I’m testing, like many others, has some elements that appear on many but not all of its pages. For the sake of DRYness, it’s useful to handle these elements with composition and inheritance (or other code-sharing strategy, as above).

_BasePage

The first class for page encapsulation is the base class _BasePage. I’ve given the class name an underscore to emphasize that it’s not an ordinary page class — it is not itself the encapsulator of a single web page.

Every page class derives from _BasePage.

What’s in _BasePage? Only those things needed for every page in the application:

  • A Context object.
  • Support for the Locator objects that will tell CUIT how to find controls.

I’ll write about classes Context and Locator in other posts.

Compositors

In the application:

  • The menu bar appears on every page except a popover and the sign-in page.
  • The footer appears on every page except a popover. In this particular app, a popover is sufficiently page-like to be treated as a separate page.

The other elements that are shared among pages are handled via composition, because different pages may have different mixtures of those elements.

Each of the compositors is a class whose constructor accepts a page object. The compositor defines locators and adds those locators to the given page.

_Menubar

Almost all pages have the menu bar, which has the basic navigation for the application. The page objects for such a page declares an instance variable _Menubar menubar and assigns it a new instance of _Menubar, whose constructor adds the appropriate locators to the page object.

_Footer

Like the menu bar, most pages have footer boilerplate. The page object for such a page declares an instance variable _Footer and assigns it a new instance of _Footer, whose constructor adds the appropriate locators to the page object.

“Tabbed” Pages

A few pages in the application have tab-like behaviors. On such a page, there’s an upper area with a title and two or more links (tabs). Below there’s content that can be changed by clicking one of the links.

Let’s say that there are four tabs, for the four seasons.

Then a class _Seasons encapsulates the elements in the upper part of the page.

Each of the tabs is encapsulated by a page object (derived from _BasePage). Each page object declares an instance variable _Seasons seasons and assigns it a new instance of _Seasons, whose constructor adds the appropriate locators to the page object.

So each season tab has its own locators, plus those in _Seasons, plus any it chooses to get from _Menubar and _Footer.

Now that’s DRY!

Burdette Lamar

Advertisements

4 thoughts on “Keep Your Page Objects DRY

  1. From what I understand, you have a basePage class where all page classes extends from; you also a have a Season class, that contains all common elements for the 4 tabs. You will then have 4 page objects – Spring, Summer, Fall and Winter, each of which includes a Season class as their class properties, so that from Spring, you can go to Winter tab by: Spring.Season.Winter.click() (very stupid pseudo code);

    If this is NOT what you explain, my bad; If this is what you mean though, I would argue instead of having Spring contains Season, they should more of Spring extends Season, which means Spring is a Seaon, while composition means Spring has a Seaon, which doesn’t make much sense to me…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s