Do I really need e2e tests for my application?
Let’s say we have written plenty of unit tests and also some integration tests covering some services. Would that be enough? The short answer is always “no”. You can have your application secured with as many unit tests as you want. You may have the confidence that your application is bulletproof with integration tests but in the end your web application must be loaded in a browser and there are a lot of layers that must match together when the client is calling the application that your backend is serving. Many things can fail, that’s why you should add some end to end tests to your application covering at least your application’s most important flows, emulating a user behaviour. Because at the end of the day what we want to ensure is that our clients are able to use the features we built for them.
Protractor is a node framework aimed for testing web applications. It is developed by Google and it is optimized for testing AngularJS and Angular applications, however it can fully work with other non-angular applications. Protractor is built on top of WebDriverJS which is based on promises.
Protractor will execute the test scripts communicating through WebDriver API via http with Selenium Server that could be started embedded or standalone. The selenium server will then translate the instructions send by Protractor script and then will send these translated instructions to the browser driver though a JSON Protocol in a language the browser can understand.
For more info about how works the communication between protractor and web driver you can go here.
In order to be able to select DOM elements, Protractor makes use of Locators. These locators are exposed through the global by object. There are some locators that are added by Protractor itself and there are also some that are just extended from webdriver.By Object. For example:
Locators inherited from webdriver.By
For more info about Protractor.By Object you can go here.
The locators are passed to the element function, as below:
The element() function returns an ElementFinder object. The ElementFinder uses the locator you passed in order to locate the DOM element, but it has not actually done so yet. It will not call the browser until an action method has been called.
Protractor gives us the possibility to add some custom locators. You can use the addLocator method from by object. You can just add the locator in you protractor config file:
Then you add this html attribute on every element you want to locate. The value of this attribute will be used to locate this element:
And lastly you can locate these elements in your page object by using your custom locators:
In our project we established as good practice to use always testIds through custom locator to locate the elements we want to find. This locator will be based on an attribute of the html element. The reason behind the idea of avoiding normal locators (className, id, …) is that the name of the class could change because of many reasons and that would break our tests. If we use this custom attribute for locating elements, every developer in team is aware that this attribute is used exclusively for test purposes and that this can not be changed or deleted without adapting the tests.
The minimal version for a protractor configuration consists of only two files:
We execute our test:
Running the tests
Step 1: Install the protractor executable:
shell:npm install -g protractor
Step 2: Install the webdriver package:
shell:npm install -g webdriver-manager
Step 3: Start the webdriver:
Step 4: Run the protractor executable and as parameter we will pass the protractor.conf.js file:
Step 5: Optionally we could indicate the suite we want to run (if no suite is passed, all tests will run):
shell:protractor protractor.conf.js --suite=basic
Note: Steps 1-3 could be skipped if we have protractor and webdriver-manager installed locally through a package.json file.
We can see that we have the protractor package listed in the dependencies section. Also, a couple of npm scripts were added in order to build protractor project (download protractor package and webdrivers) or/and running the tests. For example for building and running the tests we could just run:
shell:npm run build-and-test
If you have to write e2e-tests is always a good idea to follow the Page Object pattern. The idea behind that is that for every page (or section) we create a file where we define all the elements from the page itself and, as well, we can create methods that perform the possible activities on the page. In this way we can import the page object in the spec file and call these page object methods, enhancing the readability of the tests, favouring the DRY principle and also making the code more maintainable. If we change a element or something related to a page we only have to adapt the change in the page object.
A page object look like this:
And then the spec file is much simpler and much more readable:
Like said before end-to-end tests have a vital importance for ensuring your applications functionality. However they have a drawback: they are flaky. Since in these tests we are testing all of the application’s layers, every infrastructure problem or timing issue could lead to an error. Therefore these kind of tests tend to give false positives very often.
Because of this inherent flakiness it is extremely important to have tools that ease the analysis of possibly failed builds. There are many report plugins for protractor, but in our project we use the library protractor-jasmine2-html-reporter. When we use this library a screenshot will be generated at the end of every spec (very handy for analyzing errors) and at the end of the execution also a html site will be generated, showing the info from the run specs and their corresponding screenshots:
In order to enable we will have to add the package in our package.json file and import the Reporter in our protractor.conf.js file. There you could configure the path where the screenshots and the html are going to be saved:
You can find the test examples from this blogpost in this repository.
- protractor.org: Protractor Website
- Jason Watmore AngularJS Login Application: Jenkins Pipeline Tutorial