Click here to Skip to main content
13,258,269 members (42,324 online)
Click here to Skip to main content
Add your own
alternative version

Stats

14K views
10 bookmarked
Posted 21 Dec 2015

Introduction of Protractor for AngularJS Application

, 21 Dec 2015
Rate this:
Please Sign up or sign in to vote.
Using Protractor for E2E testing of AngularJS application in Visual Studio

Download source code from Github

Introduction

Protractor is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.Integrating Protractor for AngualrJS application in Visual Studio needs some configuration,

Background

GitHub Repository:  GitHub Link

Follow below steps to integrate it in your project.

Step 1: Install Node.js

Install any of the version, I have tested both.

After installation confirm its successful completion, by opening up window CMD (type cmd on run dialogue box)

Command:
node –version

Step 2: Install Node.js Tools for VS

This will add node.js template in VS, add intellisense for node project, activate npm integration

Step 3: Install Web Essentials

This will add cool features in your project like JSHint, minification, Source Maps, Find references, Intellisense, Bundling, ZenCoding, validation etc

Step 4: Install Java Development Kit

Chose any version, I have tested using both 8u66 and 8u65 ( should be greater then >8)

After installation confirm its successful completion, by opening up window CMD (type cmd on run dialogue box)

Command:
java -version

Step 5: Install Protractor (Globally or Locally)

  • Right click on project and choose Open Command prompt here (we can do this in CMD too, but for a moment lets stick to VS environment)
    • If you want to install protractor globally, execute the below command
      <code>npm install -g protractor
      </code>
    • If you want to install protractor locally, execute the below command
      <code>npm install protractor --save-dev</code>



      After installation confirm its successful completion, by opening up window CMD (type cmd on run dialogue box)

      Command:
      protractor –version

Step 6: Update selenium standalone server

  • Right click on project and choose Open Command prompt here (we can do this in CMD too, but for a moment lets stick to VS environment)
  • Update selenium driver, execute the below command
    <code>webdriver-manager update</code>

Step 7: Start selenium standalone server

  • Right click on project and choose Open Command prompt here (we can do this in CMD too, but for a moment lets stick to VS environment)
  • start selenium driver, execute the below command
    <code>webdriver-manager start</code>

Please Note:

Don’t close this CMD window until you are done with testing under protractor umbrella

Once the driver manager starts, open any browser and check if the listener is up by typing the URL http://localhost:4444/wd/hub in the browser.

Using the code

Step 1: Setup Node.js Console Application

Add New Project in main solution file

Search for Nodejs console application template and name it

Step 2: Add conf.js file for protractor configuration

For sample just add below code in file named as ‘conf.js’

<code>  // An example configuration file. 
  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'
      //}, 

      multiCapabilities: [{
              'browserName': 'chrome'
          }, {
              'browserName': 'firefox'
          }],

      // Spec patterns are relative to the current working directly when 
      // protractor is called. 
      specs: ['customConfig.js', 'menu.js', 'homePage.js' , 'candidatePage.js'], 

      // Options to be passed to Jasmine-node. 
      jasmineNodeOpts: {
          showColors: true, 
          defaultTimeoutInterval: 30000
      }
  };
</code>

Please Note:

using multiCapabilities will run all the tests in each of the browsers

https://hassantariqblog.wordpress.com/2015/11/09/execute-protractor-test-in-parallel-on-different-browser/

Step 3: Build Project and get URL of project

Press CTRL + F5 and note down localhost URL for your application.

For Example: http://localhost:3472/#/

Step 4: Syntax Understanding

Protractor API: http://angular.github.io/protractor/#/api

Note: Most commands return promises, so you only resolve their values through using jasmine expect API or using .then(function()) structure.

Protractor Cheatsheet

Control browser

<code>browser.get('yoururl// Load address, can also use '#yourpage'
browser.navigate().back();
browser.navigate().forward();
browser.sleep(10000); // if your test is outrunning the browser
browser.pause();
browser.debugger();
browser.waitForAngular(); // if your test is outrunning the browser
browser.getLocationAbsUrl() // get the current address
</code>

Check Visibility

<code>element(by.id('create')).isPresent();
element(by.id('create')).isEnabled();
element(by.id('create')).isDisplayed();
</code>

Find an element by id, model, binding

<code>element(by.id('user_name');
element(by.css('#myItem');
element(by.model('person.name');
element(by.binding('person.concatName'));
element(by.textarea('person.extraDetails'));
element(by.input('username'));
element(by.input('username')).clear();
element(by.buttonText('Save'));
element(by.partialButtonText('Save'));
element(by.linkText('Save'));
element(by.partialLinkText('Save'));
element(by.css('[ng-click="cancel()"]'));

var dog = element(by.cssContainingText('.pet', 'Dog'));
var allOptions = element.all(by.options('c c in colors'));
</code>

Find collection of elements by css, repeater, xpath..

<code>var list = element.all(by.css('.items'));
var list2 = element.all(by.repeater('personhome.results'));
var list3 = element.all(by.xpath('//div');
expect(list.count()).toBe(3);

element(by.id('user_name')).sendKeys('user1');
sendKeys(protractor.Key.ENTER);
sendKeys(protractor.Key.TAB);
element(by.id('user_name')).clear();
element(by.id('item1')).getLocation().then(function(location) {
    var x = location.x;
    var y = location.y;
});
element(by.id('item1')).getSize().then(function(size) {
 var width = size.width;
 var height = size.height;
});
</code>

For more detail, check out this cheat sheet

Protractor Concepts

<code>describe("A suite is just a function", function() {
  var a;
  it("and so is a spec", function() {
    a = true;
    expect(a).toBe(true);
  });
});
</code>
  • describe Your TestsA test suite begins with a call to the global Protractor function describe with two parameters: a string and a function. The string is a name or title for a spec suite – usually what is being tested. The function is a block of code that implements the suite. SpecsSpecs are defined by calling the global Protractor function it, which, like describe takes a string and a function. The string is the title of the spec and the function is the spec, or test. A spec contains one or more expectations that test the state of the code. An expectation in Protractor is an assertion that is either true or false. A spec with all true expectations is a passing spec. A spec with one or more false expectations is a failing spec.

  • It’s Just FunctionsSince describe and it blocks are functions, they can contain any executable code necessary to implement the test. JavaScript scoping rules apply, so variables declared in a describe are available to any it block inside the suite.

  • ExpectationsExpectations are built with the function expect which takes a value, called the actual. It is chained with a Matcher function, which takes the expected value.

  • MatchersEach matcher implements a boolean comparison between the actual value and the expected value. It is responsible for reporting to Protractor if the expectation is true or false. Protractor will then pass or fail the spec.Any matcher can evaluate to a negative assertion by chaining the call to expect with a not before calling the matcher.

  • Setup and TeardownTo help a test suite DRY up any duplicated setup and teardown code, Protractor provides the global beforeEach and afterEach functions. As the name implies, the beforeEach function is called once before each spec in the describe in which it is called, and the afterEach function is called once after each spec. Here is the same set of specs written a little differently. The variable under test is defined at the top-level scope — the describe block — and initialization code is moved into a beforeEach function. The afterEach function resets the variable before continuing.

  • waitForAngular() Instruct webdriver to wait until Angular has finished rendering and has no outstanding $http or $timeout calls before continuing. Note that Protractor automatically applies this command before every WebDriver action.

  • sendKeys() Schedules a command to type/update a value on the DOM element represented by this instance. I know its bit hard to understand, here is the simple one: “Send one or more keystrokes to the active window as if they were typed at the keyboard”. For example in order to enter value of any text input, we use sendKeys() function.

Step 5a: Add first test spec file for e2e testing

For sample just add below code in file named as ‘menu.js’

<code>describe('menu check', function () {
    beforeEach(function () {
        browser.get('http://localhost:3472/#/');
        browser.waitForAngular();
    });

    it('Should route to the candidates page from menu', function () {
        element(by.linkText('Users')).click();
        expect(browser.getCurrentUrl()).toMatch('http://localhost:3472/#/candidates');
    });

    it('Should route to the home page from menu', function () {
        element(by.linkText('Home')).click();
        expect(browser.getCurrentUrl()).toMatch('http://localhost:3472/#/');
    });
});
</code>

Tests in this file will click on menu item and confirm their updated URL matches with test case expected values i.e. Home and Users

Copy URL from step 3 to browser.get statement in menu.js file Name of file should be similar to what you have defined in conf.js under specs node

<code>// An example configuration file. 
exports.config = {
  // Spec patterns are relative to the current working directly when 
  // protractor is called. 
  specs: ['menu.js'], 
};
</code>

Step 5b: Add Second test spec file for e2e testing

For sample just add below code in file named as ‘homePage.js’

<code>describe('Testing Homepage', function () {  
    beforeEach(function () {
        browser.get('http://localhost:3472/#/');    
        browser.waitForAngular();
    });

    it('should have a title', function () {
        expect(browser.getTitle()).toEqual('TAC Sample Angular Utility');
    });

    it('shaould have header of page', function () {
        var header = element(by.binding('type'));
        expect(header.getText()).toMatch('Admin Page');
    });

    it('Should update the url', function () {
        expect(browser.getCurrentUrl()).toMatch('http://localhost:3472/#/');
    });

    it('Should route to the candidates page', function () {
        element(by.linkText('candidates')).click();
        expect(browser.getCurrentUrl()).toMatch('http://localhost:3472/#/candidates');
    });

    it('Should search and return rows', function () {
        var name = element(by.model('search.first_name'));
        name.sendKeys('jack');
        browser.waitForAngular();
        var candidates = element.all(by.repeater('candidate in vm.candidates'));
        expect(candidates.count()).toBe(1);
    });
});
</code>

Tests in this file will check page title, page header, url, click on href link and count of search result as highlight in image below

Name of file should be similar to what you have defined in conf.js under specs node

<code>// An example configuration file. 
exports.config = {
    // Spec patterns are relative to the current working directly when 
    // protractor is called. 
    specs: ['menu.js', 'homePage.js'], 
};
</code>

Step 5c: Add Second test spec file for e2e testing

For sample just add below code in file named as ‘candidatePage.js’

<code>describe('Testing Candidate Page', function () {

    beforeEach(function () {
        browser.get('http://localhost:3472/#/candidates');
        browser.waitForAngular();
    });

    it('Should add candidates and return rows', function () {
        element(by.model('vm.newCandidate.first_name')).sendKeys('aaq');
        element(by.model('vm.newCandidate.middle_initial')).sendKeys('aa');
        element(by.model('vm.newCandidate.last_name')).sendKeys('aac');
        element(by.model('vm.newCandidate.email')).sendKeys('haa@aa.com');
        element(by.model('vm.newCandidate.expected_salary')).sendKeys('234');

        element(by.css('.btn-primary')).click();

        browser.waitForAngular();
        var candidates = element.all(by.repeater('candidate in vm.candidates'));
        expect(candidates.count()).toBe(11);
    });

    it('Should invalidate email', function () {
        element(by.model('vm.newCandidate.email')).sendKeys('haa@com');
        element(by.model('vm.newCandidate.expected_salary')).sendKeys('111');

        browser.waitForAngular();

        element(by.model('vm.newCandidate.email')).getCssValue('background-color').then(function (color) {
            expect(color).toEqual('rgba(255, 255, 0, 1)');
        });
    });

    it('Should add edit candidates', function () {

        element.all(by.repeater('candidate in vm.candidates')).then(function (candidates) {
            candidates[0].element(by.buttonText('Edit')).click();
            candidates[0].element(by.model('vm.itemToEdit.first_name')).clear().then(function () {
                candidates[0].element(by.model('vm.itemToEdit.first_name')).sendKeys('BillBBP');
            });
            candidates[0].element(by.model('vm.itemToEdit.middle_initial')).clear().then(function () {
                candidates[0].element(by.model('vm.itemToEdit.middle_initial')).sendKeys('BBP');
            });
            candidates[0].element(by.model('vm.itemToEdit.last_name')).clear().then(function () {
                candidates[0].element(by.model('vm.itemToEdit.last_name')).sendKeys('GatesBBP');
            });
            candidates[0].element(by.model('vm.itemToEdit.email')).clear().then(function () {
                candidates[0].element(by.model('vm.itemToEdit.email')).sendKeys('BbP@aa.com');
            });
            candidates[0].element(by.model('vm.itemToEdit.expected_salary')).clear().then(function () {
                candidates[0].element(by.model('vm.itemToEdit.expected_salary')).sendKeys('800');
            });
            candidates[0].element(by.buttonText('Save')).click();
        });

        browser.waitForAngular();
        element.all(by.repeater('candidate in vm.candidates')).then(function (candidates) {
            var fName = candidates[0].element(by.binding('candidate.first_name'));
            expect(fName.getText()).toEqual('BillBBP');
        });
    });

});
</code>

Tests in this file will add candidate record in grid as highlight in image below

Tests in this file will check invalidate email value during adding record as highlight in image below

Tests in this file will edit first candidate record in grid as highlight in image below

Name of file should be similar to what you have defined in conf.js under specs node

<code>// An example configuration file. 
exports.config = {
    // Spec patterns are relative to the current working directly when 
    // protractor is called. 
    specs: ['menu.js', 'homePage.js', 'candidatePage.js'], 
};
</code>

Step 6(optional): Reduce Speed of Protractor Tests

You may witness quick execution of these tests, browser will be quickly invoked and these test will be run in flash of seconds. In order to reduce speed follow below steps:

For sample just add below code in file named as ‘customConfig.js’

<code>var origFn = browser.driver.controlFlow().execute;

browser.driver.controlFlow().execute = function () {
    var args = arguments;

    origFn.call(browser.driver.controlFlow(), function () {
        //increase or reduce time value, its in millisecond
        return protractor.promise.delayed(100);
    });

    return origFn.apply(browser.driver.controlFlow(), args);
};
</code>

Name of file should be similar to what you have defined in conf.js under specs node

<code>// An example configuration file. 
exports.config = {
    // Spec patterns are relative to the current working directly when 
    // protractor is called. 
    specs: ['customConfig.js', 'menu.js', 'homePage.js', 'candidatePage.js'] 
};
</code>

Step 7: Run Test Specs

Right click on project and choose Open Command prompt here (we can do this in CMD too, but for a moment lets stick to VS environment) run protractor for example_spec file, execute the below command

<code>protractor conf.js
</code>

Chrome and Firefox Browser behind CMD is opened by selenium web driver and execute our test and output is generated in CMD as below:

Video of protractor executing these tests is below:

Download Video

https://www.youtube.com/watch?v=rX9eeg4mNBo

Points of Interest

There might be some error while installing protractor like dependencies missing for instance python is missing, for that follow my blog post

Error: Protractor 2.0 errors during npm install due to dependencies – cant find the python executable

Execute Protractor Test in parallel on different browser

Reduce Speed of Angular E2E Protractor Tests

Bower Error – fatal: unable to connect to github.com

For the complete source code, please see:

https://github.com/m-hassan-tariq/ProtractorForAngularJS

https://hassantariqblog.wordpress.com/2015/11/09/using-protractor-for-e2e-testing-of-angularjs-application-in-visual-studio/

API Reference

History

Keep a running update of any changes or improvements you've made here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Muhammad Hassan Tariq
Software Developer
United States United States
Five+ years of demonstrated work experience in developing and implementing business technology applications, systems integration and testing solutions with in-depth domain knowledge of industries like Healthcare, Telecom, Call Center, Financial Instruments, Payroll, HR, and skills including, but not limited to, software analysis, design and development.

Comprehensive understanding of NET Framework 4.5, 4.0, 2.0 and C#, ASP.Net, ADO.Net, Entity Framework, LINQ, Web Service, WCF, AJAX Control Toolkit, Advanced JavaScript, HTML 5.0, CSS3.0, jQuery, SSIS, SSRS, XML, XSLT, JSON.

Expertise in end to end development of enterprise web application and Single Page Application (SPA) using ASP.NET MVC, ASP.NET Web Forms, ASP.NET Web API, AngularJS, TypeScript, NodeJS, SQL Server and Design Pattern fanatic.

You may also be interested in...

Pro
Pro

Comments and Discussions

 
GeneralMessage Closed Pin
30-Aug-17 2:06
memberMember 1338545630-Aug-17 2:06 
QuestionNode console project can't be found Pin
bonis77711-Jan-16 1:46
memberbonis77711-Jan-16 1:46 
GeneralMy vote of 4 Pin
Omar Nasri22-Dec-15 6:40
memberOmar Nasri22-Dec-15 6:40 
QuestionNice Pin
Slacker00722-Dec-15 0:21
professionalSlacker00722-Dec-15 0:21 
GeneralMy vote of 5 Pin
D V L21-Dec-15 23:22
professionalD V L21-Dec-15 23:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171114.1 | Last Updated 21 Dec 2015
Article Copyright 2015 by Muhammad Hassan Tariq
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid