e2e testing with protractor
Seriously? e2e?
Ronen Amiel
WHO ARE YOU?
- Software developer @wix and @codeoasis
- Developing the wix app market platform
- Top notch battlefield gamer
why is testing so important?
Testing is about gaining confidence that your code does what you think it should do
AREN'T UNIT TESTS ENOUGH?
what e2e tests are for?
- Do all the pieces work together?
- Can I release my code to production?
- Is my view working the way it should?
what are the problems with e2e testing?
- Installing and configuring selenium is painful
- Tests are difficult to write
- Tests are hard to debug
- Keeping tests up to date is requires a lot of work
meet protractor
setup
- Install node.js
- npm install -g protractor
- webdriver-manager update
create a config file
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js']
}
write your tests
describe('angularjs homepage', function() {
it('should have a title', function() {
browser.get('http://juliemr.github.io/protractor-demo/');
expect(browser.getTitle()).toEqual('Super Calculator');
});
});
let's run it
Demo available at: https://github.com/juliemr/protractor-demo
protractor api
- Browser: get(), refresh(), close()
- Element: by.model(), by.binding, by.className()
- Protractor: waitForAngular()
can i have an example?
describe('slow calculator', function() {
beforeEach(function() {
browser.get('http://localhost:3456');
});
it('should add numbers', function() {
element(by.model('first')).sendKeys(4);
element(by.model('second')).sendKeys(5);
element(by.id('gobutton')).click();
expect(element(by.binding('latest')).getText()).
toEqual('9');
});
describe('memory', function() {
var first, second, goButton;
beforeEach(function() {
first = element(by.model('first'));
second = element(by.model('second'));
goButton = element(by.id('gobutton'));
});
it('should start out with an empty memory', function () {
var memory =
element.all(by.repeater('result in memory'));
expect(memory.count()).toEqual(0);
});
it('should fill the memory with past results', function() {
first.sendKeys(1);
second.sendKeys(1);
goButton.click();
first.sendKeys(10);
second.sendKeys(20);
goButton.click();
var memory = element.all(by.repeater('result in memory').
column('result.value'));
memory.then(function (arr) {
expect(arr.length).toEqual(2);
expect(arr[0].getText()).toEqual('30'); // 10 + 20 = 30
expect(arr[1].getText()).toEqual('2'); // 1 + 1 = 2
});
});
});
});
let's quickly go over protractor's features
selecting by binding
In your test
element(by.binding('name'));
<div>{{ name }}</div>
selecting by model
In your test
element(by.model('age'));
<input type="text" ng-model="age" />
selecting by repeater
In your test
element(by.repeater('cat in pets').row(1));
<div ng-repeat="cat in pets">
<span>{{cat.name}}</span>
<span>{{cat.age}}</span>
</div>
By css containing text
In your test
element(by.cssContainingText('.pet', 'Dog'));
<ul>
<li class="pet">Dog</li>
<li class="pet">Cat</li>
</ul>
You can also trigger events!
trigger a click
In your test
element(by.css('[ng-click="submit()"]')).click();
<button ng-click="submit()"><button>
press keys
In your test
element(by.model('commentText')).sendKeys("Hi!", protractor.Key.ENTER);
<textarea ng-model="commentText"><textarea>
interested in more?
The element explorer
Playground for debugging tests
- webdriver-manager start
- ./bin/elementexplorer.js http://angularjs.org
page objects
Separate the code where you find the elements on the web page, from the test logic itself
An example of a page object
var AngularHomepage = function() {
this.nameInput = element(by.model('yourName'));
this.greeting = element(by.binding('yourName'));
this.get = function() {
browser.get('http://www.angularjs.org');
};
this.setName = function(name) {
this.nameInput.sendKeys(name);
};
};
var AngularHomepage = require('./homepage.po.js');
describe('HomePage Tests', function(){
var angularHomepage = new AngularHomepage();
angularHomepage.nameInput.sendKeys('world');
});
best practices for writing tests
- Use Protractor's by.model, by.binding and by.repeater instead of by.className or other dom specific methods
- Use page objects to make the tests easier to maintain
- Separate specs into different files and use node's .require() to run them
summery
- E2E tests don't replace unit tests but compliment them to create ultra safe production deployments
- Protractor makes it easier to write and maintain E2E tests for angular apps
- Try to ship a version to production 10 times a day or even more
- Have fun (:
questions?
Thank you (:
E2E testing with Protractor
By Ronen Amiel
E2E testing with Protractor
- 597