Protractor: How To Page Object

Feb 14, 2016

bookPage objects, for lack of a better word, are good. Page objects are right. Page objects work.

And if you're writing e2e tests, you should know what they are, and how to use them. Let's page object!

What is it?

You'll find a veritable plethora of definitions and examples on the webs... or TLDR: page objects create a user-centric model of your application.

Why should I care?

This page object model is then used to manipulate your application, abstracting away the html/css from your tests. The benefits are many:

  1. saves maintenance time: updating the page object updates all tests that use it
  2. organizes your code and keeps it DRY
  3. declutters your spec files by moving logic to the page object
  4. use a cool buzzword that is actually useful!

How to page object?

A simple page object:

var GithubPage = function() {
    this.username = $('div.vcard-username');

    // Webdriver equivilant to hitting Enter/Return key.
    this.hitEnter = function() {
        return browser.actions().sendKeys(protractor.Key.ENTER).perform();
    };
};
module.exports = new GithubPage();

Let's go line by line...

var GithubPage = function() {

We use a constructor to create our page object. We could (and I sometimes do) use an object literal, but not when I'm extending a basePage (a topic for another post).

this.username = $('div.vcard-username');

Here we start creating our model by setting this.username to our app's css (using Protractor's JQuery-like $ locator).

The idea here is that in our tests, we'll call this property, githubPage.username, to refer to the app's css code. This save us from having raw selectors (eg. $('div.vcard-username') ) strewn about in our tests. Thus, if (when) the css changes in your application, you simply update the page object, and you're green again. No hunting for uses through tests. It also makes your tests read better, and just look cleaner. You should never have raw selectors in you tests... keep 'em in the page object.

We'll also put methods in our page object:

    // Webdriver equivilant to hitting Enter/Return key.
    this.hitEnter = function() {
        return browser.actions().sendKeys(protractor.Key.ENTER).perform();
    };

We'll also add methods to our page objects. Here we create a method for hitting the enter key; something we'll use throughout our tests. This not only keeps wonky looking webdriver code out of our tests, it also keeps our code DRY.

Examples of when you might want to add a method to your page object:

module.exports = new GithubPage();

And finally, we use Node's module.exports to create a reference to our page, that will allow us to require it in our tests. Note, we also instantiate it here, by using the new keyword and parenthesis. I'm not a fan of instantiating a page object within a test... it's cruft that should be done elsewhere whenever possible.

That's the basic gist. For more examples, take a peek at my working Protractor example project up on GitHub...