Protractor Tutorial Quality in Agile 2015
-
Upload
andrew-eisenberg -
Category
Internet
-
view
218 -
download
2
Transcript of Protractor Tutorial Quality in Agile 2015
UI Testing with Protractor
Andrew Eisenberg
Tasktop Technologies
• Sr. Software Engineer @ Tasktop Technologies
• PhD from UBC in programming languages & IDEs
A Cautionary Tale
100% Code Coverage!!!
…but I was playing the wrong game.
Testing an app in 7+ easy steps
1. Installing and running Protractor
2. First tests
3. Creating test scenarios
4. Real tests
5. Synchronicity and Asynchronicity
6. Page object pattern
7. Debugging, screen capture, and other tips
8. Discussion items and gotchas
BACKGROUND
Step 0
Kinds of testing
• Unit testing
• Integration testing
• System testing (or Functional testing)
– UI Testing Using Protractor
A simplification!
What is Protractor?
• “End-to-End testing”
– Well, not really. Just UI testing
• Built to work with AngularJS
• Built on top of Selenium
• Is a node app
http://www.thoughtworks.com/insights/blog/testing-angularjs-apps-protractor
When should I use Protractor?
• UI stable
• Use cases well established
• Already unit-tested
• Uses AngularJS
• UI unstable
• Use cases in flux
• Not unit-tested
• Doesn’t use AngularJS
Do it Avoid
INSTALLING AND RUNNING PROTRACTOR
Step 1
Installing and running Protractor
• Install node/npm from https://nodejs.org/
• Install protractor, grunt
– npm install -g protractor
– npm install -g grunt-cli
• Update webdriver
– webdriver-manager update
Getting tutorial code
• git clone https://github.com/aeisenberg/angular-app.git
• cd angular-app
• git checkout qia-step-1
• Open file: Quality-in-Agile-Protractor-Tutorial.md
• Follow instructions in file
Run the app and play
user: [email protected]: nuthing
FIRST TESTS
Step 2
Protractor & Jasmine
describe('Home Page', function () {
it('should be the default page',
function () {
browser.get(browser.baseUrl);
expect(browser.getCurrentUrl())
.toEqual(browser.baseUrl +
'projectsinfo');
});
});
Let’s Code!
• Getting started
– git checkout qia-step-2-before
• If you get stuck:
– git checkout qia-step-2-after
SKETCHING TEST SCENARIOS
Step 3
AuthenticationUser
management
Project management
Backlogmanagement
Sprintmanagement
USE CASE-BASED TEST SCENARIOS
Step 4
ElementFinderelement(by.css(‘#run-command’));
element(by.css(‘#run-command’)).isPresent();
element(by.css(‘button.command’)).click();
element.all(by.css(‘button.command’)).click();
element(by.css(‘#my-input’)).getText();
element(by.cssContainingText(‘button.command’, ‘Run’)).click();
browser.waitForAngular();
Let’s Code!
• Getting started
– git checkout qia-step-4-before
• If you get stuck:
– git checkout qia-step-4-after
MORE COMPLEX TEST
Step 5
Secretly, everything is a promise
This throws an exception:
This does not:
var text = element(
by.css(‘#my-input’)).getText();
expect(text.split(‘,’)[0]).toBe(‘sumthin’);
var text = element(
by.css(‘#my-input’)).getText();
expect(text).toContain(‘sumthin’);
JavaScript Promises
• (Eventually) contains result of computation
• Asynchronous programming
• Composable, chainable, and…FUN!
• A standard
promise.then(function(result) {
verify(result);
}).then(function(result) {
display(result);
});
ElementFinder returns promise
element(by.css(‘#my-input’))
.sendKeys(‘Hello’)
.getText()
.then(function(text) {
console.log(text);
});
All ElementFinder methods return promises
element(by.css(‘#my-button’)).click();
element(by.css(‘#my-button’))
.isDisplayed();
element(by.css(‘#my-button’))
.click()
.isDisplayed();
element(by.css(‘#my-button’))
.click().then(function() {
element(by.css(‘#my-button’))
.isDisplayed();
});
Protractor and `expect`
• expect accepts promises
– delays execution until promise is resolved
var text = element(
by.css(‘#my-input’)).getText();
expect(text.split(‘,’)[0]).toBe(‘sumthin’);
var text = element(
by.css(‘#my-input’)).getText();
expect(text).toContain(‘sumthin’);
Let’s Code!
• Getting started
– git checkout qia-step-5-before
• If you get stuck:
– git checkout qia-step-5-after
PAGEOBJECT PATTERN
Step 6
The PageObject pattern
• Readable DSL for tests
• Promotes reuse
• Centralizes UI coupling
PageObject Big Idea
• Extract CSS ugliness
– element(by.css('#login')).click();
• Into semantically meaningful actions
– loginPage.openDialog();
Tests do not touch DOM directly
var loginPage = new require(‘./LoginPage)();
loginPage.login(‘[email protected]’, ‘secret’);
expect(loginPage.isLoggedIn().toBeTruthy();
loginPage.logout();
Let’s Code!
• Page Object Skeleton
– git checkout qia-step-6-before
• Getting started
– git checkout qia-step-6-middle
• If you get stuck:
– git checkout qia-step-6-after
DEBUGGING AND OTHER FUN THINGS
Step 7
Let’s Code!
• Getting started
– git checkout qia-step-7
Focused tests
• fit & fdescribe
• Focus protractor
– on a single test or set of tests
Debug mode
• protractor debug protractor.conf.js
• Enter node’s debugger
– debugger;
• Enter debugger (webdriver aware)
– browser.debugger();
• Enter debugger (new feature doesn’t work too well)
– browser.pause();
Element Explorer
• protractor --elementExplorer
• Interactive invoking of webdriver commands
Interactive login
> element(by.css('#login')).click()
>
> element(by.css('#login-email').sendKeys(’[email protected]')
>
> element(by.css('#login-password').sendKeys(’nuthin')
>
> element(by.css('#do-login')).click()
Screenshots
browser.takeScreenshot().then(function(png) {
var stream = fs.createWriteStream(filename);
stream.write(new Buffer(png, 'base64'));
stream.end();
});
Jasmine reporters
• Hook into jasmine spec lifecycle
– before/after test/suite/jasmine
• Things to do
– Format test results
– Grab screenshot on failure
– Cleanup before/after tests
– Start/stop resources
– …
Do something on failure
jasmine.getEnv().addReporter({
specDone: function(result) {
if (result.failedExpectations
.length > 0) {
console.log(‘I am a failure…’);
}
}
});
SOME PHILOSOPHICAL QUESTIONS
What should be unit tested?
What should be UI tested?
How much refactoring in production code is
appropriate?
Should test use id attributes or complex
CSS expressions?
THE TRUTH BEHIND PROTRACTOR
It ain’t perfect
• Timing problems
• Difficult to debug
• Inconsistent behavior
• Failures hard to reproduce
• Expensive to maintain
• Tests can be slow
Protractor is appropriate
• When…
– Using AngularJS
– UI is mature
– Front end is well unit-tested
– Use cases well described
• Until then…
…use manual automation
Protractor is…
• For UI testing
• AngularJS-aware
• Secretly powered by Selenium
• Asynchronous and event-based
• A powerful and clean way to test UI
But…
• Expensive to maintain