Angular is one of the most popular Javascript frameworks for building web applications. There are three popular versions of Angular upto date — Angular 1 (also known as AngularJS), followed by Angular 2, which is succeeded by Angular 4. It is gaining in popularity because it extends the functionality of HTML and can be used to quick launch applications.
Although the developers take too much time in developing the application by using different tactics and critical thinking but ultimately the client or user is the person who is actually going to pass or use the application.
It is very important to test the UI in all aspects so that the user will not get any trouble while using the application. What is important is the application should be easy to use and if the UI is tested properly it makes the usability of application easier.
What is Protractor?
Protractor is an end-to-end testing framework for AngularJS applications and works as a solution integrator combining powerful tools and technologies such as NodeJS, Selenium WebDriver, Jasmine, Cucumber and Mocha. It was initially developed by Google Developers to support angular applications and later it is released as an open source framework. Now protractor supports both angular and Non-Angular applications. The protractor is wrapper written on top of Webdriver.js, all the features which are supported in Selenium Webdriver are supported by it, in addition to angular specific features.
WebDriverJs is the official javascript implementation of Selenium. It uses the Selenium JSON-Wire-Protocol to interact with the browser as selenium java does. Protractor depends on WebdriverJs to interact with the browser.
Features of Protractor Automation tool
Let’s have a look at some of the salient features of the Protractor Automation tool:
- Built on the top of WebdriverJS and Selenium server
- Introduced new simple syntax to write tests
- Allows running tests targeting remote addresses
- Can take advantage of Selenium grid to run multiple browsers at once
- Can use Jasmine or Mocha to write test suites
Protractor Installation Steps
Here, we’ve used the protractor framework and configured on a windows environment. Below are the steps for installation:
Install Protractor Globally on Environment
Step 1: Download and install NodeJS. Make sure its path is configured correctly after installation. Also check that you should find node from command prompt. Ignore if you already have nodejs installed.
Step 2: Open the command prompt and type in the following command to install protractor globally.
npm install –g protractor
Install Protractor Locally
For local installation type the following command in the command prompt of your project directory :
npm install protractor
To verify your installation, please type in the command
Protractor --version
If Protractor is installed successfully then the system will display the installed version. Otherwise you will have to recheck the installation.
Step 3: If you don’t have the Selenium server on your machine, then download the latest version onto your machine. If you want to run tests on different browsers, then please download the respective drivers as well. For example, Chrome driver will come in handy to run tests on the Chrome browser.
You are good to go now.
Finally the main step.
Write Your Test Cases
Create a clean folder for testing. Protractor needs two files to run, a spec file and a configuration file.
Copy the following into spec.js:
// spec.js describe('Protractor Demo App', function() { it('should have a title', function() { browser.get('https://www.aimdek.com'); expect(browser.getTitle()).toEqual('aimdek'); }); });
The describe and it syntax is from the Jasmine framework. browser is a global created by Protractor, which is used for browser-level commands such as navigation with browser.get.
Now create the configuration file. Copy the following into conf.js:
// conf.js exports.config = { framework: 'jasmine', seleniumAddress: 'http://localhost:4444/wd/hub', specs: ['spec.js'] }
This configuration tells Protractor where your test files (specs) are, and where to talk to your Selenium Server (seleniumAddress). It specifies that we will be using Jasmine for the test framework. It will use the defaults for all other configuration. Chrome is the default browser.
Now run the test with
protractor conf.js
You should see a Chrome browser window open up and navigate to the Calculator, then close itself (this should be very fast!). The test output should be 1 tests, 1 assertion, 0 failures. Congratulations, you’ve run your first Protractor test!
Step 1 – Interacting with elements
Now let’s modify the test to interact with elements on the page. Change spec.js to the following:
// spec.js describe('Protractor Demo App', function() { it('should add one and two', function() { browser.get('https://www.aimdek.com'); element(by.model('first')).sendKeys(1); element(by.model('second')).sendKeys(2); element(by.id('gobutton')).click(); expect(element(by.binding('latest')).getText()). toEqual('5'); // This is wrong! }); });
This uses the globals element and by, which are also created by Protractor. The element function is used for finding HTML elements on your webpage. It returns an ElementFinder object, which can be used to interact with the element or get information from it. In this test, we use sendKeys to type into <input>s, click to click a button, and getText to return the content of an element.
element takes one parameter, a Locator, which describes how to find the element. The by object creates Locators. Here, we’re using three types of Locators:
- by.model(‘first’) to find the element with ng-model=”first”. If you inspect the Calculator page source, you will see this is <input type=”text” ng-model=”first”>.
- by.id(‘gobutton’) to find the element with the given id. This finds <button id=”gobutton”>.
- by.binding(‘latest’) to find the element bound to the variable latest. This finds the span containing {{latest}}
Learn more about locators and ElementFinders.
Run the tests with
protractor conf.js
You should see the page enter two numbers and wait for the result to be displayed. Because the result is 3, not 5, our test fails. Fix the test and try running it again.
Step 2 – Writing multiple scenarios
Let’s put these two tests together and clean them up a bit. Change spec.js to the following:
// spec.js describe('Protractor Demo App', function() { var firstNumber = element(by.model('first')); var secondNumber = element(by.model('second')); var goButton = element(by.id('gobutton')); var latestResult = element(by.binding('latest')); beforeEach(function() { browser.get('http://www.aimdek.com/'); }); it('should have a title', function() { expect(browser.getTitle()).toEqual('aimdek'); }); it('should add one and two', function() { firstNumber.sendKeys(1); secondNumber.sendKeys(2); goButton.click(); expect(latestResult.getText()).toEqual('3'); }); it('should add four and six', function() { // Fill this in. expect(latestResult.getText()).toEqual('10'); }); it('should read the value from an input', function() { firstNumber.sendKeys(1); expect(firstNumber.getAttribute('value')).toEqual('1'); }); });
Here, we’ve pulled the navigation out into a beforeEach function which is run before every it block. We’ve also stored the ElementFinders for the first and second input in nice variables that can be reused. Fill out the second test using those variables, and run the tests again to ensure they pass.
In the last assertion we read the value from the input field with firstNumber.getAttribute(‘value’) and compare it with the value we have set before.
Step 3 – Changing the configuration
Now that we’ve written some basic tests, let’s take a look at the configuration file. The configuration file lets you change things like which browsers are used and how to connect to the Selenium Server. Let’s change the browser. Change conf.js to the following:
// conf.js exports.config = { framework: 'jasmine', seleniumAddress: 'http://localhost:4444/wd/hub', specs: ['spec.js'], capabilities: { browserName: 'firefox' } }
Try running the tests again. You should see the tests running on Firefox instead of Chrome. The capabilities object describes the browser to be tested against. For a full list of options, see the config file.
You can also run tests on more than one browser at once. Change conf.js to:
// conf.js exports.config = { framework: 'jasmine', seleniumAddress: 'http://localhost:4444/wd/hub', specs: ['spec.js'], multiCapabilities: [{ browserName: 'firefox' }, { browserName: 'chrome' }] }
Try running once again. You should see the tests running on Chrome and Firefox simultaneously, and the results reported separately on the command line.
Step 4 – Lists of elements
Let’s go back to the test files. Feel free to change the configuration back to using only one browser.
Sometimes, you will want to deal with a list of multiple elements. You can do this with element.all, which returns an ElementArrayFinder. In our calculator application, every operation is logged in the history, which is implemented on the site as a table with ng-repeat. Let’s do a couple of operations, then test that they’re in the history. Change spec.js to:
// spec.js describe('Protractor Demo App', function() { var firstNumber = element(by.model('first')); var secondNumber = element(by.model('second')); var goButton = element(by.id('gobutton')); var latestResult = element(by.binding('latest')); var history = element.all(by.repeater('result in memory')); function add(a, b) { firstNumber.sendKeys(a); secondNumber.sendKeys(b); goButton.click(); } beforeEach(function() { browser.get('http://juliemr.github.io/protractor-demo/'); }); it('should have a history', function() { add(1, 2); add(3, 4); expect(history.count()).toEqual(2); add(5, 6); expect(history.count()).toEqual(0); // This is wrong! }); });
We’ve done a couple things here – first, we created a helper function, add. We’ve added the variable history. We’ve used element.all with the by.repeater Locator to get an ElementArrayFinder. In our spec, we assert that history has the expected length using the count method. Fix the test so that the second expectation pass.
ElementArrayFinder has many methods in addition to count. Let’s use last to get an ElementFinder that matches the last element found by the Locator. Change the test to:
it('should have a history', function() { add(1, 2); add(3, 4); expect(history.last().getText()).toContain('1 + 2'); expect(history.first().getText()).toContain('foo'); // This is wrong! });
Since the Calculator reports the oldest result at the bottom, the oldest addition (1 + 2) be the last history entry. We’re using the toContain Jasmine matcher to assert that the element text contains “1 + 2”. The full element text will also contain the timestamp and the result.
Fix the test so that it correctly expects the first history entry to contain the text “3 + 4”.
ElementArrayFinder also has methods each, map, filter, and reduce which are analogous to JavaScript Array methods. Read the API for more details.
This should get you started writing tests. To learn more, see the documentation Table of Contents.
Conclusion
“As some of you know that Selenium does the same thing but selenium is more tester specific. Here protractor does it in an easy way and for a developer, it is much easier to write protractor test case rather than using selenium”.
“Software testing does not make software; they only make them better.” – Anonymous
Want to get deeper knowledge into Angular applications, our services, and how we work, contact us today to one of our business consultants.