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
This will add node.js template in VS, add intellisense for node project, activate npm integration
This will add cool features in your project like JSHint, minification, Source Maps, Find references, Intellisense, Bundling, ZenCoding, validation etc
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
npm install -g protractor
- If you want to install protractor locally, execute the below command
npm install protractor --save-dev
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
webdriver-manager update
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
webdriver-manager start
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’
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
multiCapabilities: [{
'browserName': 'chrome'
}, {
'browserName': 'firefox'
}],
specs: ['customConfig.js', 'menu.js', 'homePage.js' , 'candidatePage.js'],
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
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
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
Check Visibility
element(by.id('create')).isPresent();
element(by.id('create')).isEnabled();
element(by.id('create')).isDisplayed();
Find an element by id, model, binding
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'));
Find collection of elements by css, repeater, xpath..
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;
});
For more detail, check out this cheat sheet
Protractor Concepts
describe("A suite is just a function", function() {
var a;
it("and so is a spec", function() {
a = true;
expect(a).toBe(true);
});
});
-
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’
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/#/');
});
});
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
exports.config = {
specs: ['menu.js'],
};
Step 5b: Add Second test spec file for e2e testing
For sample just add below code in file named as ‘homePage.js’
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);
});
});
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
exports.config = {
specs: ['menu.js', 'homePage.js'],
};
Step 5c: Add Second test spec file for e2e testing
For sample just add below code in file named as ‘candidatePage.js’
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');
});
});
});
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
exports.config = {
specs: ['menu.js', 'homePage.js', 'candidatePage.js'],
};
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’
var origFn = browser.driver.controlFlow().execute;
browser.driver.controlFlow().execute = function () {
var args = arguments;
origFn.call(browser.driver.controlFlow(), function () {
return protractor.promise.delayed(100);
});
return origFn.apply(browser.driver.controlFlow(), args);
};
Name of file should be similar to what you have defined in conf.js under specs node
exports.config = {
specs: ['customConfig.js', 'menu.js', 'homePage.js', 'candidatePage.js']
};
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
protractor conf.js
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
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
For the complete source code, please see: