Our Engineers can Write as well

Why automate AngularJS applications with Protractor rather than Selenium? – Part II

Protractor Locators

The integral part in UI test automation of an application page is identifying desired DOM elements, communicating with them and grabbing the information about the current state of the application. To achieve this, we use locators. This week we will see how to identify the DOM elements in a web page and communicate with them using Protractor designated locators.

High level view:
  • Protractor has a global function called element, that grabs the locator from the application and return an element finder.

1. element – It identifies single element from the application.

2. element.all – It identifies all the matching elements with same property from the application.

Once the required element or elements are identified within the web page, other methods such as click(), sendKeys() and clear() are utilized to perform specific actions on these element(s).

It would be an asynchronous action to find an element and perform an action using Protractor and these asynchronous tasks are being controlled by JSON Webdriver Wire Protocol. Browser executes actions just like a user.

What is a locator? How do we use Protractor locators in Angular apps?
  • A locator tells Protractor how to identify a certain DOM element just as Selenium locators. We very well know that Protractor works on top of Selenium WebDriver so it uses Selenium locators also. Protractor locators are applicable only for Angular based pages/applications.

  • If Protractor locators (ng-model, ng-repeat, ng-binding etc.) are used in non-angular pages then we will get an error since non-angular pages do not support Protractor locators,

  • Protractor exports locator factories on the global by object. A few common locators and how they are passed to the element() are explained as below,

To identify an element using ID in protractor

 

Application codeProtractor code
<button id=”product-addtocart-button” class=”btn btn-primary addpassenger ng-binding” type=”button” data-toggle=”modal” data-target=”#myModal”>View passenger Details</button>var input = element( by.id(‘product-addtocart-button’));

To identify an element with a certain ng-model

 

Application codeProtractor code
<input id=”startingPoint” class=”floating-input form-control ng-pristine ng-empty ng-invalid ng-invalid-required ng-touched” tabindex=”7″ autocomplete=”off” name=”spoint” required=”” type=”text” placeholder=” ” aria-invalid=”true”>var input = element(by.model(‘departure’));

To identify an element with ng-repeat

 

Application codeProtractor code
<th title=”” ng-repeat=”$column in $columns” ng-class=”{
‘sortable’: $column.sortable(this),
‘sort-asc’: params.sorting()[$column.sortable(this)]==’asc’,
‘sort-desc’: params.sorting()[$column.sortable(this)]==’desc’
}” ng-click=”sortBy($column, $event)” ng-if=”$column.show(this)” ng-init=”template = $column.headerTemplateURL(this)” class=”header ” role=”button” tabindex=”0″ style=”min-width: 134px; max-width: 134px;”> <!– ngIf: !template –><div ng-if=”!template” class=”ng-table-header ng-scope” ng-class=”{‘sort-indicator’: params.settings().sortingIndicator == ‘div’}”> <span ng-bind=”$column.title(this)” ng-class=”{‘sort-indicator’: params.settings().sortingIndicator == ‘span’}” class=”ng-binding sort-indicator”>Request type</span> </div><!– end ngIf: !template –> <!– ngIf: template –> </th>
var list = element(by.repeater(‘$column in $columns’).row(0));
How actions are associated with locators?

Once element() function returns an ElementFinder object, now element finder knows how to interact with element in DOM but it won’t perform anything until an action method has been called, so once element has been located/identified in the DOM we have to perform any desired action in application/browser

The most frequently used methods are,Variable declarations like what we saw in the table above.

  • To click a web element such as a button – element( by.id(‘product-addtocart-button’)).click();
  • To send input to a web element such as a text box – element(by.model(‘departure’)).sendKeys(“Chennai”);
  • To clear the text in an element (usually an input) – element(by.model(‘departure’)).clear();
  • To get the value of an attribute, say example, get the value of an input field – element(by.model(‘departure’)).getAttribute(‘value’);

We very well know that all actions are asynchronous, and it returns the promise. So, to print the text from input box to console we have to define it as follow,

var input = element(by.model(‘departure’));
departure.getText().then(function(text){
console.log(text);
});

How to find multiple elements?

In-order to find multiple elements with same property, we use element.all finder

element.all(by.repeater(‘$column in $columns’).then(function(elements){
// returns an array of elements
});

With element.all(), we can do many actions as below,

  • To get the count of matching elements – element.all(by.repeater(‘$column in $columns’)count();
  • To get the index of specific matching elements – element.all(by.repeater(‘$column in $columns’).get(index);
  • To get the first and last values of matching elements use first() and last() respectively –

element.all(by.repeater(‘$column in $columns’).first();

element.all(by.repeater(‘$column in $columns’).last();

How to find sub-elements?

In order to find sub-elements, simply chain element and element.all functions jointly.

  • To find a sub-element with chained locators: element(by.id(‘self-proxy-radiobutton’).element(by.tagName(‘proxy’));
  • To find a list of sub-elements: element(by.id(‘self-proxy-radiobutton’).all(by.tagName(‘proxy’));

You can chain with get/first/last as well like so:

element.all(by.id(‘self-proxy-radiobutton’).first().element(by.tagName(‘proxy’));

element.all(by.id(‘self-proxy-radiobutton’).get(index).element(by.tagName(‘proxy’));

element.all(by.id(‘self-proxy-radiobutton’).first().all(by.tagName(‘proxy’));

parthiban - Software Test Engineer

Contributed by:

Parthiban
Software Testing Engineer

There is 1 comment
  1. Aditya

    Well explained

Your email address will not be published. Required fields are marked *