Upload
ludmila-nesvitiy
View
53
Download
0
Embed Size (px)
Citation preview
Protractor framework – how to make stable e2e tests for Angular applications
Ludmila NesvitiyQA Automation Engineer
https://github.com/ludmilanesvitiyhttps://ua.linkedin.com/in/[email protected]
Choosing a testing strategy
E2E approach
Separation On reusing components, parts, functions
Describing Each test-case
Writing Easy to read and run
Supporting Easy to support and rewrite
Optimal coverage
quantity e2e / time for runningmanual tests => mindifferent goals = different testing scope
Customer: “Automate everything”
PM:“Automate everything, that you can”
QA:“I can automate everything,
but i know my priorities”
Test-cases priorities
Protractor framework
5 main points
➢ Performance
➢ Stability
➢ Timeouts
➢ Testing different modules
➢ Supporting
Performance
1
Protractor.conf
specs: ['../test/**/*.e2e-spec.ts'],exclude: ['../test/**/needToExclude.e2e-spec.ts'],framework: 'jasmine',allScriptsTimeout: 110000,directConnect: true
multiCapabilities
multiCapabilities: [ {browserName: 'chrome'}, {browserName: 'firefox'}, {browserName: 'internet explorer'}],
shardTestFiles + maxInstances
multiCapabilities: [{ browserName: 'chrome', shardTestFiles: true, maxInstances: 1 }, { browserName: 'firefox', shardTestFiles: true, maxInstances: 3 }, { browserName: 'internet explorer', shardTestFiles: false, maxInstances: 4 }],
count
useAllAngular2AppRoots
Stability
2
onPrepare: function ()
onPrepare: () => { browser.ignoreSynchronization = true; browser.driver.manage().window().maximize(); jasmine.getEnv().addReporter(new SpecReporter());}
Cloud services
const browserstackUser = process.env.BROWSERSTACK_USERNAME;const browserstackKey = process.env.BROWSERSTACK_KEY;
exports.config = { multiCapabilities: [{ 'browserstack.user': browserstackUser, 'browserstack.key': browserstackKey, 'browserName': 'internet explorer', 'browser_version': '10' }]};
PROMISES
Timeouts
3
Wait - how much, why and where?
browser.get(address, timeout); // Default = 10
allScriptsTimeout: timeout; // Default = 11
getPageTimeout: timeout; // Default = 10
browser.sleep(timeout);
EC = protractor.ExpectedConditions;
browser.wait(EC.not(EC.visibilityOf(loader)), 80000); // not / and / or
browser.wait(EC.visibilityOf(menu), timeout);
browser.wait(EC.invisibilityOf(loader), timeout);
Testing different modules
4
Browser.ignoreSynchronization
or
Testing non-angular modules
Window handles, testing Share/Follow buttons
afterEach(() => browser.ignoreSynchronization = false);
it('Check twitter', () => { MatrixPage.hamburgerMenu.click(); MatrixPage.getShareButtonInHamburgerMenu('twitter').click().then(() => { browser.getAllWindowHandles().then((handles: any) => { browser.ignoreSynchronization = true; browser.switchTo().window(handles[1]).then(() => { expect(browser.getCurrentUrl()).toContain('Some URL'); expect(SharePages.inputFieldTwitter.getText()).toContain('Some text and link'); }); browser.switchTo().window(handles[0]); }); });});
Supporting
5
Main reasons of failed tests
Selectors
Waits for loading elements
Incorrect configuration
Lobster
Failures Protractor framework
How to hold of the browser's console?
browser.manage().logs().get('browser').then((browserLog) => { console.log('log: ' + require('util').inspect(browserLog));});
Screenshots with Protractordescribe('Take screenShot', () => { using(DataProvider.allUrls, (data: any, description: string) => { it('from page' + description, () => { browser.get(data.url); const writeScreenShot = (info: any, filename: string) => { let stream = fs.createWriteStream(filename); stream.write(new Buffer(info, 'base64')); stream.end(); }; browser.takeScreenshot().then((png: any) => { writeScreenShot(png, description + '.png'); }); }); });});
Make screenshot for failures
jasmine.getEnv().addReporter(() => { this.specDone = (result: any) => { if (result.failedExpectations.length > 0) { takeScreenShot(); } };});
Tips & Tricks
Protractor + Page Object
Main Page
Login Page
Abstract Page
Test
beforeAll : Login
test: Main Page
using: Abstract Page
export class AbstractPage { public static getEC(): ProtractorExpectedConditions { return protractor.ExpectedConditions; }; public static sendQuery(field: ElementFinder, query: string): any { field.clear().then(() => field.sendKeys(query)); };}
Abstract Page
Login Page
export class LoginPage { public static emailInput: ElementFinder = element(by.id('JobSeekerLogin')); public static passwordInput: ElementFinder = element(by.id('JobSeeker')); public static loginButton: ElementFinder = element(by.id('signin')); public static redirectWindow: ElementFinder = $('.inner-g');
public static login(): any { browser.get('/'); browser.wait(AbstractPage.getEC().inVisibilityOf(this.redirectWindow)), 9000); AbstractPage.sendQuery(this.emailInput, '[email protected]'); AbstractPage.sendQuery(this.passwordInput, 'testPass'); this.loginButton.click();};}
Test
describe('Main page ', () => { beforeAll(() => { LoginPage.login(); });
it('check visibility of elements ', () => { expect(MainPage.personifiedDropDown.isDisplayed()).toBe(false); expect(MainPage.filtersH3.getText()).toEqual('Test String H3'); expect(MainPage.searchButton.isPresent()).toBeTruthy(); });});
Protractor + Page Object + Data Provider
Main Page
Login Page
Abstract Page
Test
beforeAll : Login
test: Main Page
using: Abstract Page
DataProvider
Test
export class DataProvider { public static mainPageBoolean: any = { 'Logo': {element: (): ElementFinder => $('img[src*="Logo."]')}, 'LogOut Button': {element: (): ElementFinder => element(by.id('sign-out-link'))}, 'All Products button': {element: (): ElementFinder => $('a[class*="shopping"]')}, 'Input for keywords': {element: (): ElementFinder => $('input[class*="keyword"]')} };}
const using = require('jasmine-data-provider');describe('Main page ', () => { using(DataProvider.mainPageBoolean, (data: any, description: string) => { it('check visibility of: ' + description, () => { expect(data.element().isDisplayed()).toBe(true); }); });
DataProvider
Checking web-UI data after XLS parsing. -xlsjs- + Protractor
const xlsJs = require('xlsjs');
export class XLS { public static getDataFromXLS(cellId: string): string { let fileNamePath = './example.xls'; let workbook = xlsJs.readFile(fileNamePath); let sheetNumberlist = workbook.SheetNames; return workbook.Sheets[sheetNumberlist['1']][cellId].v; };}
Checking web-UI data after XLS parsing. -xlsjs- + Protractor
const using = require('jasmine-data-provider');const colEn: string = 'A';
describe('Checking countries in language: ', () => { using(DataProvider.countyPageId, (data: any, description: string) => { it('English, country: ' + description, () => { browser.get('country/en' + data.countryId); expect(CountryPage.countryName.getText()).toEqual(description); expect(CountryPage.countryName.getText())
.toEqual(XLS.getDataFromXLS(colEn + data.numberOfCell)); }); });});
Tests for drag&drop checking import { browser, protractor } from 'protractor';import { DropMePage } from '../pages/dropMePage';const dropFile = require('../helpers/dragAndDrop');let EC = protractor.ExpectedConditions;
describe('Drag and Drop Tests: ', () => { beforeAll(() => { browser.ignoreSynchronization = true; browser.get('https://dropfile.to/'); }); it('move files to service and check link as a result', () => { dropFile(DropMePage.inputFieldForImages, 'e2e/data/3.jpg'); DropMePage.startUploadingButton.click(); browser.wait(EC.visibilityOf(DropMePage.urlLoadedImage), 20000); expect(DropMePage.urlLoadedImage.getText()).toContain('https://dropfile.to/'); });});
A few lines of code = many different testsusing(DataProvider.searchKeywordsQuery, (data: any, query: string) => { it('check suggestions in search field by keywords: ' + query, () => { AbstractPage.sendQuery(MainPage.inputKeyword, query); expect(MainPage.suggestionsKeywordsField.count())
.toBe(data.quantitySuggestions);
MainPage.suggestionsKeywordsField.each((suggestion: any) => {
expect(suggestion.isDisplayed()).toBeTruthy(); }); });});
1 it
2 expect
20 tests
11 checks in each test==>
Questions?http://www.protractortest.org/
https://github.com/angular/protractor
https://github.com/angular/protractor/blob/master/CHANGELOG.md
https://github.com/ludmilanesvitiy/ProtractorExample
https://github.com/ludmilanesvitiyhttps://ua.linkedin.com/in/[email protected]