Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Protractor framework – how to make stable e2e tests for Angular applications

3,683 views

Published on

Ludmila Nesvitiy for Selenium Camp 2017
Protractor framework – how to make stable e2e tests for Angular applications

Published in: Technology
  • D0WNL0AD FULL ▶ ▶ ▶ ▶ http://1lite.top/UwNme ◀ ◀ ◀ ◀
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hi, your presentation has more information about the protractor.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Protractor framework – how to make stable e2e tests for Angular applications

  1. 1. Protractor framework – how to make stable e2e tests for Angular applications
  2. 2. Ludmila Nesvitiy QA Automation Engineer https://github.com/ludmilanesvitiy https://ua.linkedin.com/in/ludmila-nesvitiy-58094ab7 ludmilawork@gmail.com
  3. 3. Choosing a testing strategy
  4. 4. E2E approach Separation On reusing components, parts, functions Describing Each test-case Writing Easy to read and run Supporting Easy to support and rewrite
  5. 5. Optimal coverage quantity e2e / time for running manual tests => min different goals = different testing scope Customer: “Automate everything” PM: “Automate everything, that you can” QA: “I can automate everything, but i know my priorities”
  6. 6. Test-cases priorities
  7. 7. Protractor framework
  8. 8. 5 main points ➢Performance ➢Stability ➢Timeouts ➢Testing different modules ➢Supporting
  9. 9. Performance 1
  10. 10. Protractor.conf specs: ['../test/**/*.e2e-spec.ts'], exclude: ['../test/**/needToExclude.e2e-spec.ts'], framework: 'jasmine', allScriptsTimeout: 110000, directConnect: true
  11. 11. multiCapabilities multiCapabilities: [ {browserName: 'chrome'}, {browserName: 'firefox'}, {browserName: 'internet explorer'} ],
  12. 12. shardTestFiles + maxInstances multiCapabilities: [{ browserName: 'chrome', shardTestFiles: true, maxInstances: 1 }, { browserName: 'firefox', shardTestFiles: true, maxInstances: 3 }, { browserName: 'internet explorer', shardTestFiles: false, maxInstances: 4 }],
  13. 13. count
  14. 14. useAllAngular2AppRoots
  15. 15. Stability 2
  16. 16. onPrepare: function () onPrepare: () => { browser.ignoreSynchronization = true; browser.driver.manage().window().maximize(); jasmine.getEnv().addReporter(new SpecReporter()); }
  17. 17. 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' }] };
  18. 18. PROMISES
  19. 19. Timeouts 3
  20. 20. 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);
  21. 21. Testing different modules 4
  22. 22. Browser.ignoreSynchronization or Testing non-angular modules
  23. 23. 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]); }); }); });
  24. 24. Supporting 5
  25. 25. Main reasons of failed tests Selectors Waits for loading elements Incorrect configuration Lobster Failures Protractor framework
  26. 26. How to hold of the browser's console? browser.manage().logs().get('browser').then((browserLog) => { console.log('log: ' + require('util').inspect(browserLog)); });
  27. 27. Screenshots with Protractor describe('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'); }); }); }); });
  28. 28. Make screenshot for failures jasmine.getEnv().addReporter(() => { this.specDone = (result: any) => { if (result.failedExpectations.length > 0) { takeScreenShot(); } }; });
  29. 29. Tips & Tricks
  30. 30. Protractor + Page Object Main Page Login Page Abstract Page Test beforeAll : Login test: Main Page using: Abstract Page
  31. 31. 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, 'test@gmail.com'); AbstractPage.sendQuery(this.passwordInput, 'testPass'); this.loginButton.click();};}
  32. 32. 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(); }); });
  33. 33. Protractor + Page Object + Data Provider Main Page Login Page Abstract Page Test beforeAll : Login test: Main Page using: Abstract Page DataProvider
  34. 34. 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
  35. 35. 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; }; }
  36. 36. 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)); }); }); });
  37. 37. 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/'); }); });
  38. 38. A few lines of code = many different tests using(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==>
  39. 39. 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/ludmilanesvitiy https://ua.linkedin.com/in/ludmila-nesvitiy-58094ab7 ludmilawork@gmail.com

×