OdeToCode IC Logo

PageObjects and Protractor

Tuesday, January 6, 2015

I’m a fan of the PageObject pattern when writing Protractor tests, because PageObjects make the test code more expressive and readable. When I sit down to write some Protractor tests, I usually write the test code I want to see first, and then try to make it happen.

For example, when writing some tests for a “login and redirect” scenario, I started off with some test specs like the following.

describe("The security application", function () { 

    var secret = new SecretPage();
    var login = new LoginPage(); 

    it("should redirect to login page if trying to view a secret as anonymous user", function () {
        secret.go();
        expect(browser.getCurrentUrl()).toBe(LoginPage.url);
    }); 

    it("should go back to the secret after a login", function () {
        login.login("sallen", "sallen");
        expect(browser.getCurrentUrl()).toBe(SecretPage.url);
    }); 

});

These tests require two page objects, the SecretRecipePage and the LoginPage. SInce Protractor tests run in Node, each page can live in a distinct module. First, the SecretRecipePage.

var config = require("./config"); 

var SecretPage = function () { 

    this.go = function() {
        browser.get(SecretPage.url);
    }; 

}; 

SecretPage.url = config.baseUrl + "security/shell.html#/secret"; 

module.exports = SecretPage;

And the LoginPage.

var config = require("./config"); 

var LoginPage = function () { 

    this.go = function() {
        browser.get(LoginPage.url);
    }; 

    this.login = function(username, password) {
        $(".container [name=username]").sendKeys(username);
        $(".container [name=password]").sendKeys(password);
        $(".container [name=loginForm]").submit();
    }; 
}; 

LoginPage.url = config.baseUrl + "security/shell.html#/login"; 

module.exports = LoginPage;

Both of these modules depend on a config module to remove hard coded URLs and magic strings. A simple config might look like the following.

var config = {
    baseUrl: http://localhost:9000/Apps/
}; 

module.exports = config;

Now all the spec file needs to do is require the two page modules …...

var SecretPage = require("../pages/SecretPage");
var LoginPage = require("../pages/LoginPage.js"); 

describe("The security application", function () { 

    // …... 

});

And presto! Readable Protractor tests are passing.

image