carmen popoviciu - protractor styleguide | codemotion milan 2015

Post on 12-Feb-2017

627 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

E2E Testing & Best Practices with Protractor

@CarmenPopoviciu

Agenda● E2E Testing

● Protractor

● Best Practices

E2E Testing

WHAT?

E2E testing is a means of verifying that all units of

an application interact as expected with each other

and that the system as a whole works as intended

What?● Testing from the user perspective

What?● Testing from the user perspective

● Main user interaction flows

What?● Testing from the user perspective

● Main user interaction flows

● Major subpages or routes in the site

What?● Testing from the user perspective

● Main user interaction flows

● Major subpages or routes in the site

● Essential elements on a page

WHY?

E2E testing will give you the confidence that

everything works OK

Why?● Prevents production incidents

Why?● Prevents production incidents

● Manual testing takes too much time

Why?● Prevents production incidents

● Manual testing takes too much time

● E2E tests are documentation

Why?● Prevents production incidents

● Manual testing takes too much time

● E2E tests are documentation

● Makes us better devs

Protractor

Protractor is an end-to-end testing framework for AngularJS applications

Protractor● Wrapper around WebdriverJS

● Adds Angular-specific locator strategies

● Runs tests against real browsers

● node.js program

Everything clear?

Let’s dive in a little deeper

Selenium WebDriver

¯\_(ツ)_/¯

Test Browser

Selenium WebDriver

¯\_(ツ)_/¯

Test Browser

WebDriverClient

Libraries

Test Browser

WebDriverClient

Librarieslanguage specific bindings for Selenium WebDriver API

Test Browser

language specific bindings for Selenium WebDriver API

JAVA

Ruby

Python

JS

Test Browser

JAVA

Ruby

Python

JS

WebDriverBrowser Drivers

Test Browser

WebDriver implementations specific to various browsers

JAVA

Ruby

Python

JS

WebDriverBrowser Drivers

Test Browser

Chrome Driver

Firefox Driver

IE Driver

JAVA

Ruby

Python

JS

WebDriver implementations specific to various browsers

Test Browser

Chrome Driver

Firefox Driver

IE Driver

JAVA

Ruby

Python

JS

Test Browser

Chrome Driver

Firefox Driver

IE Driver

JAVA

Ruby

Python

JS

Real browsers that can connect to anything internet can connect to, including the application under test

Test Browser

Chrome Driver

Firefox Driver

IE DriverJS

Python

Ruby

JAVA

Angular apps are written in JS, so we’ll use the JavaScript bindings for the Selenium WebDriver API

Test Browser

Chrome Driver

Firefox Driver

IE Driver

WebdriverJSJavaScript bindings for WebDriver

Test Browser

Chrome Driver

Firefox Driver

IE Driver

WebdriverJS- findElement()- getText()- click()...

JavaScript bindings for WebDriver

Test Browser

Chrome Driver

Firefox Driver

IE Driver

driver.get(url);

var el = driver.findElement( webdriver.By.name('greet'));el.sendKeys('Hi!');el.click();

Test Code

WebdriverJS- findElement()- getText()- click()...

Test Browser

Chrome Driver

Firefox Driver

IE Driver

Test Code

WebdriverJS- findElement()- getText()- click()...

Webdriver Wire Protocol

/session/:sessionId/element/:id/text/session/:sessionId/element/:id/click/session/:sessionId/keys….

Test Browser

Chrome Driver

Firefox Driver

IE Driver

Test Code

WebdriverJS- findElement()- getText()- click()...

Selenium Server

Test Browser

Chrome Driver

Firefox Driver

IE Driver

Test Code

WebdriverJS- findElement()- getText()- click()...

Selenium ServerProtractor

Test Browser

Chrome Driver

Firefox Driver

IE Driver

Test Code

WebdriverJS- findElement()- getText()- click()...

Selenium ServerProtractor

NodeJS

Still confused?

That’s OK. It will take another few attempts to get it right

(flashy green) Demo!

Control Flow

Control Flow● Non blocking API

Control Flow● Non blocking API

● WebdriverJS/Protractor APIs are purely

asynchronous

Control Flow● Non blocking API

● WebdriverJS/Protractor APIs are purely

asynchronous

● Every function returns a promise

Control Flowit('should greet’, function() {

browser.get('#/hello-world’);

var name = element(by.model(‘name’));

var greetBtn = element(by.tagName(‘button’));

var greeting = element(by.binding(‘greeting’));

name.sendKeys('DevfestRo');

greetBtn.click();

expect(greeting.getText()).toEqual('Hi DevfestRo!');

// ¯\_(ツ)_/¯

});

Control Flow● WebDriverJS maintains a queue of scheduled tasks

(pending promises), called the control flow

Control Flow● WebDriverJS maintains a queue of scheduled tasks

(pending promises), called the control flow

● Each task is executed once the one before it in the

queue is finished

Control Flow● WebDriverJS maintains a queue of scheduled tasks

(pending promises), called the control flow

● Each task is executed once the one before it in the

queue is finished

● Protractor adapts Jasmine so that each spec

automatically waits until the control flow is empty

before exiting

That was a LOT of text for one slide

Ready for another quick dive?

ControlFlow Class

Instancewebdriver.promise.controlFlow()

Task1

Task4

Task3

Task2

Queue

Task4

Task3

Task2

Task1

.execute(..)

Control Flowflow.execute(function() {

console.log('a');

});

flow.execute(function() {

console.log('b');

});

flow.execute(function() {

console.log('c');

});

// a

// b

// c

Control Flowflow.execute(function() {

console.log('a');

}).then(function() {

flow.execute(function() {

console.log('c');

});

});

flow.execute(function() {

console.log('b');

});

// a

// c

// b

(two seemingly random) Demos!

Best Practices

Use Page Objects to interact with the page under test

WHY?

Encapsulate information about the elements on the page under test

They can be reused across multiple tests

Decouple the test logic from implementation details

// avoid/* question.spec.js */

describe('Question page', function() { it('should answer any question', function() { var question = element(by.model('question.text')); var answer = element(by.binding('answer')); var button = element(by.css('.question-button'));

question.sendKeys('What is the purpose of life?'); button.click(); expect(answer.getText()).toEqual("Chocolate!"); });});

// recommended/* question.spec.js */

var QuestionPage = require('./question.page');

describe('Question page', function() { var question = new QuestionPage();

it('should ask any question', function() { question.ask('What is the purpose of meaning?'); expect(question.answer.getText()).toEqual('Chocolate'); });});

// recommended/* question.page.js */

var QuestionPage = function() { this.question = element(by.model('question.text')); this.answer = element(by.binding('answer')); this.button = element(by.className('question-button'));

this.ask = function(question) { this.question.sendKeys(question); this.button.click(); };};module.exports = QuestionPage;

Declare functions for operations that require more than one step

WHY?

Most elements are exposed by the Page Object and can be used directly in the test

Doing otherwise adds unnecessary complexity

Don't make any assertions in your Page Objects

WHY?

It is the responsibility of the test to do all the assertions

Reader of the test should be able to understand the behavior of the application by

looking at the test only

Prefer protractor locators when possible

WHY?

Access elements easier

Code is less likely to change than markup

More readable locators

<ul class="red"> <li>{{color.name}}</li> <li>{{color.shade}}</li> <li>{{color.code}}</li></ul>

/* avoid */var nameElem = element.all(by.css('.red li')).get(0);

/* recommended */var nameElem = element(by.binding('color.name'));

Prefer by.id and by.css when no protractor locators are available

WHY?

Access elements easier

Select markup that is less likely to change

More readable locators

NEVER use xpath

WHY?

Markup is very easily subject to change

xpath has performance issues

Unreadable locator

more athttps://github.com/CarmenPopoviciu/protractor-styleguide

https://goo.gl/1SmXer

THANK YOU!https://goo.gl/1SmXer

top related