Protractor – Objects

This chapter discusses in detail the objects in Protractor.

What are Page Objects?

The page object is a design pattern that has become popular for writing e2e tests in order to enhance test maintenance and reducing code duplication. It may be defined as an object-oriented class serving as an interface to a page of your AUT (application under test). But, before diving deep into page objects, we must have to understand the challenges with automated UI testing and the ways to handle them.

Challenges with automated UI testing

Followings are some common challenges with automates UI testing −

UI Changes

The very common issue while working with UI testing is the changes that happen in UI. For example, it happens most of the time that buttons or textboxes, etc. usually got change and creates issues for UI testing.

Lack of DSL(Domain Specific Language) support

Another issue with UI testing is the lack of DSL support. With this issue, it becomes very hard to understand what is being tested.

Lots of repetition/Code duplication

The next common problem in UI testing is that there is lots of repetition or code duplication. It can be understood with the help of the following lines of code −

element(by.model(‘event.name’)).sendKeys(‘An Event’);
element(by.model(‘event.name’)).sendKeys(‘Module 3’);
element(by.model(‘event.name’));

Tough maintenance

Due to the above challenges, it becomes a headache for maintenance. It is because we have to find all the instances, replace them with the new name, selector & other code. We also need to spend lots of time to keep tests in line with refactoring.

Broken tests

Another challenge in UI testing is the happening of lots of failures in tests.

Ways to Handle Challenges

We have seen some common challenges of UI testing. Some of the ways to handle such challenges are as follows −

Updating References Manually

The very first option for handling the above challenges is to update the references manually. The problem with this option is that we must do the manual change in the code as well as our tests. This can be done when you have one or two tests files but what if you have hundreds of tests files in a project?

Using Page Objects

Another option for handling the above challenges is to use page objects. A page object is basically plain JavaScript that encapsulates the properties of an Angular template. For example, the following specification file is written without and with page objects to understand the difference −

Without Page Objects

describe('angularjs homepage', function() {
   it('should greet the named user', function() {
      browser.get('http://www.angularjs.org');
      element(by.model('yourName')).sendKeys('Julie');
      var greeting = element(by.binding('yourName'));
      expect(greeting.getText()).toEqual('Hello Julie!');
   });
});

With Page Objects

For writing the code with Page Objects, the first thing we need to do is to create a Page Object. Hence, a Page Object for the above example could look like this −

var AngularHomepage = function() {
   var nameInput = element(by.model('yourName'));
   var greeting = element(by.binding('yourName'));
 
   this.get = function() {
      browser.get('http://www.angularjs.org');
   };
 
   this.setName = function(name) {
      nameInput.sendKeys(name);
   };
   
   this.getGreetingText = function() {
      return greeting.getText();
   };
};
module.exports = new AngularHomepage();

Using Page Objects to Organize Tests

We have seen the use of page objects in the above example to handle the challenges of UI testing. Next, we are going to discuss how we can use them to organize the tests. For this, we need to modify the test script without modifying the functionality of the test script.

Example

To understand this concept we are taking the above configuration file with page objects. We need to modify the test script as follows −

var angularHomepage = require('./AngularHomepage');
describe('angularjs homepage', function() {
   it('should greet the named user', function() {
      angularHomepage.get();
 
      angularHomepage.setName('Julie');
   
      expect(angularHomepage.getGreetingText()).toEqual
      ('Hello Julie!');
   });
});

Here, note that the path to the page object will be relative to your specification.

On the same note, we can also separate our test suite into various test suites. The configuration file then can be changed as follows

exports.config = {
   // The address of a running selenium server.
   seleniumAddress: 'http://localhost:4444/wd/hub',
 
   // Capabilities to be passed to the webdriver instance.
   capabilities: {
      'browserName': 'chrome'
   },
   // Spec patterns are relative to the location of the spec file. They may
   // include glob patterns.
   suites: {
      homepage: 'tests/e2e/homepage/**/*Spec.js',
      search: ['tests/e2e/contact_search/**/*Spec.js',
         'tests/e2e/venue_search/**/*Spec.js']
   },
 
   // Options to be passed to Jasmine-node.
   jasmineNodeOpts: {
      showColors: true, // Use colors in the command line report.
   }
};

Now, we can easily switch between running one or the other suite of tests. The following command will run only the homepage section of the test −

protractor protractor.conf.js --suite homepage

Similarly, we can run specific suites of tests with the command as follows −

protractor protractor.conf.js --suite homepage,search

Leave a Reply