Talking testing, automation... and anything else.

Feb 16

Protractor: How To Page Object

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:

Let’s go line by line…

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).

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:

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:

  • actions you’ll using in multiple tests
  • actions that take multiple steps: eg. enter search text and hit return
  • wrap selectors or wonky looking webdriver code
  • wrap another method and add logging or whatnot to it

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

Aug 15

Protractor: Navigating Pages Without Angular

compassI’m currently using Protractor to build e2e test automation for my team. And while Protractor is especially helpful for Angular applications, my app is non-angular. This has presented some challenges… and because of it’s asynchronous nature, some truly maddening challenges at that :)

Case in point: page loads.

Because I don’t have Angular telling Protractor when a page has finished loading, I need to handle it myself. Thus I stole some ideas from my work with Geb, namely, the to() and at() methods. These two methods navigate to, wait for, and verify all page changes. Here’s how it works…

First, in my basePage (that is extended from all other pages), we have two friendly methods:

These methods rely on each page having the properties url and pageLoaded. For example, the page object could include:

The url property is just a string. It can be fully qualified, or relative (which then gets appended to the baseUrl). The pageLoaded property uses Protractor’s Expected Conditions and() method, that allows you to use any number of functions to both wait for the page, and test that we’re on the correct page.

In this example, I only need one EC function, hasText, but you can add as many as necessary, separated by commas (eg. you could wait for a spinner to NOT be displayed, for a header to be displayed, AND check the page title). Each function need only return true.

Finally, we can call these in our specs thusly:

In the beforeEach block, we call, which calls both the to() method to navigate to the page, and the at() method to wait/verify the page.

Then in the spec, we click on the home page link, and use at() inside an expect() to verify we’re on the right page. We can do this because we return the result of the Expected Conditions. If all are true, the test passes; if even one returns false, the test fails.

The result is a clean way to navigate pages without Angular.

I use this in my protractor_example code up on the GitHub

Nov 14

Screencast: Protractor Test Automation Framework Example Code

I’ve been playing around with Protractor, a great, new(ish) testing framework from our friends at Google. I’ve shared my example code on GitHub for those that might be interested in such things.

Examples in the code include:

  • Using page objects
  • Running on TravisCI
  • Running tests on Sauce Labs and Browserstack
  • Running multiple browsers at once

I’ve also made a quick screencast that walks you through downloading and running the example code.

Cut to the chase, in the video we:

  • Install Node (okay, I don’t show this but you need do to it!)
  • Download the example code from GitHub
  • run npm install to install the project dependancies
  • Briefly discuss a config file
  • run protractor conf.js to run the tests

Apr 14

Running Test Suites In Geb

sweetsMaybe you’re looking to run a number of tests against a new build, or perhaps you just can’t wait for the overnight Jenkins tests to run. Whatever the reason, running multiple Geb tests/specs from your IDE is a snap, thanks to JUnit’s sweet suite functionality.

To the code!

We use two annotations: @RunWith, to specify the runner to run the suite, and @Suite.SuiteClasses, that specifies an array of tests/specs we’d like to run. Just add any specs you’d like run in the array, with .class appended and separated with a comma.

Lastly, we have our actual class, which is left empty. All you need do is run the suite and all your specified tests will run.

I’ve added this code to my Geb examples project on GitHub, so you can play along at home!

Oct 13

Using Page Objects In Sahi (Javascript)

pageI read a nice post by Martin Fowler about Page Objects, that reminded me that I’ve not yet expanded on my original post about using them with Sahi. Let me correct that…

To demonstrate using page objects in Sahi, I refactored three tests from Sahi’s own demo. You’ll find the original three tests in your Sahi scripts folder, in: demo\testcases\training.sah.

Note, that this is my implementation of the page object pattern… I’m sure it could be improved upon. Also note that this code currently only works in Sahi Pro version 5.x. If you’re running the open source version of Sahi, you’ll need to wait until they update the OS version to 5.x. Feel free to lobby the Sahi dev team to do just that ;)

If you’d like to cut to the chase, you can just download the example code .zip or get it from GitHub.

What Is a Page Object?

A page object is code written to model an actual page (or part of a page) in a web application. Eg. each page in your app, would have an associated page object file that provides the “services” that the actual page offers. Eg. if there’s a button on a page in your application, you would have a reference to that button in your page object. If you then write a test that clicks that button, you would access the button through the page object.

Why Use Page Objects?

Page object provide many benefits, including:

  1. Make tests more readable/easier to understand
  2. Make tests easier to maintain
  3. Help organize code into logical chunks

Sahi Page Object Example (Javascript)

The following is the login page object you’ll find in my example code.

In our example, we first include a CommonPage (more on that in a minute) and then create our page object (Javascript’s version of a class), LoginPage. Then we abstract out all the elements we need from the actual page and store them as properties (variables). This is one of the biggest benefits of a page object. If an element is changed in your application, you need only update it’s associated property to fix your code.

We then add any methods (functions) we want to make use of on the page. In this case, we simplify the login method by also offering a loginAs method that takes a user role array as an argument. Thus to login (which we’ll do a LOT) we need only call: loginPage.loginAs($admin) or in this case, loginPage.loginAs($user).

Next, we extend the functionality of our LoginPage. You may wish to have certain properties and methods available to all of your page objects. You might also have common elements across multiple pages (eg. search box or nav bar). To accomplish this, we use Javascript’s prototype object to extend common objects. In our example, we have methods we’d like to make available in all of our page objects. Thus, we have LoginPage’s prototype object to extend CommonPage. Now, any method in CommonPage is also available in LoginPage.

Lastly, we simply instantiate the LoginPage object. I do this because I don’t care to have a bunch of “new” statements mucking up my tests. Therefore, when I include a page object, it’s already instantiated and I can just start using it. This might not jive with some folks… You’re of course welcome to instantiate each new page directly in your tests if you like ;)

Testing Login Using LoginPage Object

And now, here’s how we use our page object…

Pretty simple. We include our config.sah and the two page objects we need for the test. You’ll do this in every test. Then we login using our LoginPage object that we instantiated in the variable loginPage (note the object is uppercase and reference is lowercase). Once logged in, we grab the current page url and assert that we’re on the page we expected.

That’s it for our login test. The test code is simple and concise… we don’t use any Sahi code to access anything on the page, which should make maintaining our code MUCH easier down the line.

There are additional pages and tests in my example code. Feel free to give it a whirl and let me know what you think!