In this chapter, let us learn in detail about the style guide for protractors.
Introduction
The style guide was created by two software engineers named, Carmen Popoviciu, a front-end engineer at ING, and Andres Dominguez, software engineer at Google. Hence, this style guide is also called Carmen Popoviciu and Google’s style guide for protractors.
This style guide can be divided into the following five key points −
- Generic rules
- Project Structure
- Locator strategies
- Page Objects
- Test suites
Generic Rules
The following are some general rules that must be taken care of while using a protractor for testing −
Do not end-to-end test what has been already unit tested
This is the very first generic rule given by Carmen and Andres. They suggested that we must not perform an e2e test on the code that has already been unit tested. The main reason behind it is that the unit tests are much faster than e2e tests. Another reason is that we must have to avoid duplicate tests (don’t perform both unit and e2e testing) for saving our time.
Use only one configuration file
Another important point recommended is that we must have to use only one configuration file. Do not create a configuration file for each environment you are testing. You can use grunt-protractor coverage in order to set up different environments.
Avoid using logic to your test
We must have to avoid using IF statements or FOR loops in our test cases because if we do so then the test may pass without testing anything or it may run very slow.
Make the test independent at file level
Protractors can run the test parallelly when sharing is enabled. These files are then executed across different browsers as and when they become available. Carmen and Andres recommended making the test independent at least at file level because the order in which they will be run by protractor is uncertain and moreover it is quite easy to run a test in isolation.
Project Structure
Another important key point regarding the style guide of Protractor is the structure of your project. The following is the recommendation about project structure −
Groping e2e test in a sensible structure
Carmen and Andres recommended that we must group our e2e tests in a structure that makes sense to the structure of your project. The reason behind this recommendation is that the finding of files would become easy and the folder structure would be more readable. This step will also separate e2e tests from unit tests. They recommended that the following kind of structure should be avoided −
|-- project-folder
|-- app
|-- css
|-- img
|-- partials
home.html
profile.html
contacts.html
|-- js
|-- controllers
|-- directives
|-- services
app.js
...
index.html
|-- test
|-- unit
|-- e2e
home-page.js
home-spec.js
profile-page.js
profile-spec.js
contacts-page.js
contacts-spec.js
On the other hand, they recommended the following kind of structure −
|-- project-folder
|-- app
|-- css
|-- img
|-- partials
home.html
profile.html
contacts.html
|-- js
|-- controllers
|-- directives
|-- services
app.js
...
index.html
|-- test
|-- unit
|-- e2e
|-- page-objects
home-page.js
profile-page.js
contacts-page.js
home-spec.js
profile-spec.js
contacts-spec.js
Locator Strategies
The following are some locator strategies that must be taken care of while using protractor for testing −
Never use XPATH
This is the first locator strategy that is recommended in the protractor style guide. The reason behind the same is that XPath is required lots of maintenance because the markup is very easily subject to change. Moreover, XPath expressions are the slowest and very hard to debug.
Always prefer protractor-specific locators such as by.model and by.binding
Protractor-specific locators such as by.model and by. binding are short, specific, and easy to read. With the help of them, it is very easy to write our locator also.
Example
View
<ul class = "red">
<li>{{color.name}}</li>
<li>{{color.shade}}</li>
<li>{{color.code}}</li>
</ul>
<div class = "details">
<div class = "personal">
<input ng-model = "person.name">
</div>
</div>
For the above code, it is recommended to avoid the following −
var nameElement = element.all(by.css('.red li')).get(0);
var personName = element(by.css('.details .personal input'));
On the other hand, the following is recommended to use −
var nameElement = element.all(by.css('.red li')).get(0);
var personName = element(by.css('.details .personal input'));
var nameElement = element(by.binding('color.name'));
var personName = element(by.model('person.name'));
When no Protractor locators are available, then it is recommended to prefer by.id and by.css.
Always avoid text locators for frequently changing text
We must have to avoid text-based locators such as by.linkText, by.buttonText, and by.cssContaningText because the text for buttons, links, and labels frequently change over time.
Page Objects
As discussed earlier, page objects encapsulate information about the elements on our application page and due to this help us write cleaner test cases. A very useful advantage of page objects is that they can be reused across multiple tests and in case if the template of our application has been changed, we only need to update the page object. Followings are some recommendations for page objects that must be taken care of while using protractor for testing −
To interact with page under test, use page objects
It is recommended to use page objects to interact with the page under test because they can encapsulate information about the element on the page under test and they can be reused also.
Always declare one-page object per file
We should define each page object in its own file because it keeps the code clean and finding things becomes easy.
At the end of page object file always uses a single module.exports
It is recommended that each page object should declare a single class so that we only need to export one class. For example, the following use of object file should be avoided −
var UserProfilePage = function() {};
var UserSettingsPage = function() {};
module.exports = UserPropertiesPage;
module.exports = UserSettingsPage;
But on the other hand, the following is recommended to use −
/** @constructor */
var UserPropertiesPage = function() {};
module.exports = UserPropertiesPage;
Declare all the required modules at the top
We should declare all the required modules at the top of the page object because it makes module dependencies clear and easy to find.
Instantiate all page objects at the beginning of the test suite
It is recommended to instantiate all the page objects at the beginning of the test suite because this will separate dependencies from the test code as well as makes the dependencies available to all the specifications of the suite.
Do not use expect() in page objects
We should not use expect() in page objects i.e. we should not make any assertions in our page objects because all the assertions must be done in test cases.
Another reason is that the reader of the test should be able to understand the behavior of the application by reading the test cases only.
Thanks again for the post. Awesome.