SlideShare a Scribd company logo
1 of 69
Download to read offline
Page Objects 
Oren Rubin Testim.io
About Me
Talk Topics 
● Page Objects 
○ Why? 
○ How? 
○ When? 
● Synchronously 
○ Integrate in Page Objects 
○ Remove magic sleep
Talk Topics (we won't discuss) 
● Locators - best practice 
● Retrys 
○ Locator retry (SPA) 
○ Entire Test (stability)
Page Objects? 
A Design Pattern. 
Provides a programmatic API to drive and 
interrogate a UI
Naming things is hard 
● Originally "Window Drivers" - Martin Fowler, 2004 
● Only pages? what about: 
○ Header/footer 
○ Components/widgets 
○ Simple HTML elements (e.g., Tables)
Page Object Pattern 
Expose the service you're interacting with, not the 
implementation. -- Selenium Wiki 
If you have a WebDriver APIs in your test methods... 
You're doing it wrong. -- Simon Stewart
Step 1 - Expose The Service
Step 1 - Expose The Service 
<form id="gaia_loginform"> 
<input id="email"> 
<input id="passwd"> 
<input id="signIn" type="submit"> 
</form>
Step 1 - Expose The Service 
void testMyApp() { 
// login 
driver.findId("email").setText("u@app.com"); 
driver.findId("passwd").setText("12345"); 
driver.findId("signIn").click();; 
sleep(3000); // wait till page loads 
assert(...) // my assertions 
}
Step 1 - Expose The Service 
void testMyApp() { 
// login 
driver.findId("email").setText("u@app.com"); 
driver.findId("passwd").setText("12345"); 
driver.findId("signIn").click();; 
sleep(3000); // wait till page loads 
assert(...) // my assertions 
} 
Simon says no!
Test Automation 
the implementation of the automatic execution of some Business Logic 
Business Logic testMyApp() { 
testMyApp() { 
account.login(); 
gallery.showImage() 
} 
Implementation 
Class LoginPage() { 
login() { 
account.login(); 
// selenium code 
gallery.showImage() 
} 
} 
} 
Class GalleryPage() { 
showImage() {...} 
}
Step 1 - Expose The Service 
loginPage = new LoginPage(); 
loginPage.login(); 
public class LoginPage { 
public login(); 
}
Step 1 - Expose The Service 
loginPage = new LoginPage(); 
loginPage.login(); 
// compilation error: missing return type 
public class LoginPage { 
public ? login(); 
}
Step 1 - Expose The Service 
Option 1: void 
public class LoginPage { 
public void login(); 
}
Step 1 - Expose The Service 
void testMyApp() { 
// TODO move to @setup 
loginPage = new LoginPage(); 
loginPage.login(); 
sleep(3000); // wait till page loads 
assert(…) 
}
Step 1 - Expose The Service 
Pro - Only deals with login page 
● Don't interleave code relevant to other pages in 
this class. 
Con - Only deals with login page 
● Was the login successful? 
● On which page should we be? 
● Is the new page ready?
Step 1 - Expose The Service 
Option 2 (improved): Return a page object 
public class LoginPage { 
public GalleryPage login() {{ 
… 
return new GalleryPage(); 
} 
}
Step 1 - Expose The Service 
void testMyApp() { 
// TODO consider moving to @before 
loginPage = new LoginPage(); 
galleryPage = loginPage.login(); 
sleep(3000); 
galleryPage.showImageFullscreen(); 
assert(…) 
}
Q: What's the source of all evil? 
"No more war - no more blood shed"
A: Random waits 
random sleep 
"No more war - no more blood shed" 
Abie Nathan 
The voice of peace
Step 2 - Eliminate random sleep 
void testMyApp() { 
loginPage = new LoginPage(); 
galleryPage = loginPage.login(); 
sleep(3000); // should we move it? 
galleryPage.showImageFullscreen(); 
assert(…) 
}
Step 2 - option 2 
public class LoginPage { 
public GalleryPage login() { 
… 
sleep(3000); 
return new GalleryPage(); 
} 
}
Step 2 - option 2 
void testMyApp() { 
loginPage = new LoginPage(); 
// synchronous for testers 
galleryPage = loginPage.login(); 
galleryPage.showImageFullscreen(); 
assert(…) 
}
Step 2 - back to option 1 
public class LoginPage { 
void login() {…} 
} 
public class GalleryPage { 
void showImageFullscreen() {…} 
static GalleryPage waitForPage() {…} 
}
Step 2 - back to option 1 
void testMyApp() { 
loginPage = new LoginPage() 
loginPage.login(); // login() is void 
galleryPage = GalleryPage.waitForPage(); 
galleryPage.showImageFullscreen(); 
assert(…) 
}
Step 2 - Combining options 1+2 
public class LoginPage { 
public GalleryPage login() { 
… 
// return new GalleryPage(); 
return GalleryPage.waitForPage(); 
} 
}
Step 2 - Force API comformance 
public class LoginPage { 
static LoginPage waitForPage() {…} 
GalleryPage login() {…} 
} 
public class GalleryPage { 
static GalleryPage waitForPage() {…} 
void showImageFullscreen() {…} 
}
Step 2 - Basic code reuse 
abstract class BasicPage { 
// force derived classes 
public static BasicPage waitForPage(); 
} 
public class GalleryPage { 
public static BasicPage waitForPage() {…} 
}
Step 2 - Basic code reuse 
abstract class BasicPage { 
// force derived classes 
public static BasicPage waitForPage(); 
} 
public class GalleryPage { 
public static BasicPage waitForPage() {…} 
} Computer says no! 
Cannot override static methods!
Step 2 - Basic code reuse 
abstract class BasicPage { 
// force derived classes to implement 
public BasicPage waitForPage(); 
} 
public class GalleryPage { 
public BasicPage waitForPage() {…} 
} Computer says ok! 
But could be improved!
Step 2 - Basic code reuse 
abstract class BasicPage { 
// force derived classes to implement 
public BasicPage waitForPage(); 
} 
public class GalleryPage { 
public GalleryPage waitForPage() {…} 
}
Step 2 - Basic code reuse 
Another option is to use c'tor as wait 
public class GalleryPage { 
GalleryPage() { 
sleep(3000); 
} 
}
Step 2 - Basic code reuse 
Tip! 
Add all common utilities to base class 
abstract class BasicPage { 
public BasicPage waitForPage(); 
public void waitForSpinnerToFade(); 
}
What's next? 
Support Different Users
Step 3 - Params and overload 
Sounds simple! 
public class LoginPage { 
public GalleryPage login(user, password); 
}
Step 3 - Params and overload 
void testMyApp() { 
// bad password 
loginPage = new LoginPage(); 
loginPage = loginPage.login('a', 'wrong'); 
// good password 
galleryPage = loginPage.login('a', 'correct'); 
galleryPage.showImageFullscreen(); 
}
Step 3 - Params and overload 
What about different roles? what about failures 
public class LoginPage { 
public GalleryPage login(user, password); 
public OtherPage login(user, password); 
public LoginPage login(user, password); 
} 
// compilation error: 
can't distinguish overload by return type
Step 3 - Params and overload 
Compiles successfully 
public class LoginPage { 
public GalleryPage loginAsRegular(…); 
public OtherPage loginAsAdmin(…); 
public LoginPage loginAsBadCredintial(…); 
}
Step 3 - Overloading Philosophy 
The LoginPage is used for: 
1. Setup 
Drive the app to a specific state 
No one cares about the implementation 
2. Test the Login page itself 
Test the specific implementation
Step 3 - Overloading Philosophy 
1. Setup 
// look ma! no params! 
loginPage.login(); 
Implementation might be using 
● Username/password 
● Cookies 
● Google Account 
Might be hardcoded, or using config files
Step 3 - Overloading Philosophy 
2. Test the Login page itself 
○ Abstract everything 
login(username, password) 
○ Act on element wrappers (get/set kind) 
Definition: InputDriver getPasswordField() 
Usage: loginPage.getPasswordField.set('12345') 
* less recommended
Step 3 - Overloading Philosophy 
Should we put everything together? 
class LoginPage { 
login() {} 
login(username, password){} 
}
Step 3 - Overloading Philosophy 
Do we want more abstraction 
interface LoginPage { 
login(); 
LoginPageDriver getDriver(); 
} 
interface LoginPageDriver { 
login(username, password); 
}
Step 3 - Overloading Philosophy 
class LoginPageImpl 
implements LoginPage, LoginPageDriver { 
login() {} 
login(username, password); 
LoginPageDriver getDriver() { 
return this; 
} 
}
Step 4 - Page Factory 
public class LoginPage { 
private WebDriver driver; 
public LoginPage(driver) { 
this.driver = driver; 
} 
public GalleryPage login(username, password) { 
driver.findId("email").setText(username); 
… 
}
Step 4 - Page Factory 
public class LoginPage { 
private WebElement email; 
public LoginPage(driver) { 
email = driver.findById("email"); 
} 
public GalleryPage login(username, password) { 
email.setText(username); 
… 
}
Step 4 - Page Factory 
public class LoginPage { 
private WebElement email; 
private WebElement password; 
public LoginPage(driver) { 
email = driver.findById("email"); 
password = driver.findById("password"); 
// Linting error! too much glue code 
} 
}
Step 4 - Page Factory 
public class LoginPage { 
private WebElement email; 
private WebElement password; 
/* look ma.. no ctor! */ 
} 
// loginPage = new LoginPage(); 
loginPage = 
PageFactory.initElement(driver, LoginPage.class)
Step 4 - Page Factory 
Recommended way - in c'tor 
public class LoginPage { 
LoginPage() { 
// wait till ready 
sleep(3000); 
// init 
PageFactory.initElement(driver, this) 
} 
}
Step 4 - Page Factory Pseudo Code 
class PageFactory { 
public static initElements(driver, class){ 
obj = class.new(); 
obj.properties.forEach(function(property) { 
if (property.type === WebElement.class) { 
byId = driver.findById(property.name); 
byName = driver.findByName(property.name); 
obj[property.name] = byId || byName 
} 
});
Step 4 - Page Factory 
But this won't pass any code review 
public class GoogleLoginPage { 
private WebElement q; 
// Linting error! name too short 
and non descriptive 
}
Step 4 - Page Factory 
Annotations to the rescue! 
public class GoogleLoginPage { 
@FindBy(how = How.name, using = "q") 
private WebElement searchBox; 
}
Step 4 - Page Factory 
Shorthand FTW! 
public class GoogleLoginPage { 
@FindBy(name = "q") 
private WebElement searchBox; 
} 
Supports id, tagName and custom annotations!
Step 4 - Assertions 
Two options 
● Separate from Page Objects 
Community Recommends 
● Inside Page Object 
Maybe inside the BasicPage class
Off topic - No more sleep 
public class GalleryPage { 
public void waitForPage() { 
sleep(3000); 
} 
}
Off topic - No more sleep 
Some solutions 
1. The "No smoke without fire" - 
Wait for another element we know that loads last 
2. The "Take the time" 
Wait till state is what you expect (element exists, 
row count,..). Selenium's implicit wait helps. 
3. The "Coordinator" - Recommended! 
Wait for a sign from AUT
The Coordinator 
login() 
waitForTestEvent('logged') 
gallery.showImage() 
// injected code 
setInterval( function({ 
if (works) { 
// we're done 
callback(); 
} 
), 500ms)
The Coordinator 
Option 1 - Javascript 
The API 
driver.executeAsyncScript("some js.. callback()"); 
Translation - browser runs 
function executeAsync(codeToEval, callback) { 
// evaluated code has access to callback 
eval(codeToEval); 
}
The Coordinator 
Option 1 - Javascript 
The API 
driver.executeAsyncScript("some js.. callback()"); 
Translation - browser runs 
function executeAsync(codeToEval, callback) { 
// name 'callback' might change. last param guaranteed though 
eval(codeToEval); 
}
The Coordinator 
driver.executeAsyncScript(" 
some js.. 
// callback() 
var lastIndex = arguments.length; 
var workingCallback = arguments[lastIndex] 
workingCallback(); // now 
setTimeout(workingCallback, 5000); // later 
");
The Coordinator 
The API 
driver.executeAsyncScript("some js.. callback()"); 
Better implementation 
function executeAsync(codeToEval, callback) { 
// evaluated code has access to callback 
var lastArgument = "arguments[arguments.legnth - 1]" 
eval(" ( function(callback){" +codeToEval+" } )(lastArgument)"); 
}
The Coordinator - option 2 
login() 
waitForTestEvent('logged') 
gallery.showImage() 
// load things 
… 
// ready 
sendTestEvent('logged')
The Coordinator - option 2 
Testers wait for a known event 
public class LoginPage { 
public GalleryPage login() { 
… 
waitForTestEvent('gallery-ready') 
return new GalleryPage(); 
} 
}
The Coordinator - option 2 
Dev add html element in test mode 
<body> 
<div id="app"> app goes here </div> 
<div id="test"> test events go here </div> 
</body>
The Coordinator - option 2 
Imlement waitForTestEvent in base class 
abstract class BasicPage { 
void waitForTestEvent(eventName) { 
By selector = By.CSS("#test ." + eventName) 
driver.waitForElement(selector); 
WebElement element = driver.find(selector); 
driver.removeElement(element); 
} 
}
The Coordinator - option 2 
Dev add html element in test mode 
function loadGalleryPage() { 
callServer(function() { 
// page is loaded 
testing.sendTestEvent('gallery-ready') 
}) 
}
The Coordinator - option 2 
Dev add html element in test mode 
class Testing { 
sendTestEvent: function(ev) { 
if (!app.isInTest){ 
return; 
$('#test').append('<div class="+ev+">') 
}) 
} 
Illustration only, don't use jQuery. Use Angular.js / Ember.js
अंत! 
Thank You! 
Oren Rubin 
Testim.io | shexman@gmail | @shexman | linkedin

More Related Content

What's hot

Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and EasybIakiv Kramarenko
 
Webdriver cheatsheets summary
Webdriver cheatsheets summaryWebdriver cheatsheets summary
Webdriver cheatsheets summaryAlan Richardson
 
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...Alan Richardson
 
Top100summit 谷歌-scott-improve your automated web application testing
Top100summit  谷歌-scott-improve your automated web application testingTop100summit  谷歌-scott-improve your automated web application testing
Top100summit 谷歌-scott-improve your automated web application testingdrewz lin
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersDavid Rodenas
 
Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...
Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...
Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...Iakiv Kramarenko
 
20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_twTse-Ching Ho
 
Selenium - The page object pattern
Selenium - The page object patternSelenium - The page object pattern
Selenium - The page object patternMichael Palotas
 
jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksAddy Osmani
 
Test automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubinTest automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubinOren Rubin
 
Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Iakiv Kramarenko
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.jsMek Srunyu Stittri
 
The Screenplay Pattern: Better Interactions for Better Automation
The Screenplay Pattern: Better Interactions for Better AutomationThe Screenplay Pattern: Better Interactions for Better Automation
The Screenplay Pattern: Better Interactions for Better AutomationApplitools
 
Lets make a better react form
Lets make a better react formLets make a better react form
Lets make a better react formYao Nien Chung
 
Ten Minutes To Tellurium
Ten Minutes To TelluriumTen Minutes To Tellurium
Ten Minutes To TelluriumJohn.Jian.Fang
 
Enhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentEnhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentYao Nien Chung
 
Selenium withnet
Selenium withnetSelenium withnet
Selenium withnetVlad Maniak
 

What's hot (20)

Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and Easyb
 
Webdriver cheatsheets summary
Webdriver cheatsheets summaryWebdriver cheatsheets summary
Webdriver cheatsheets summary
 
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
 
Top100summit 谷歌-scott-improve your automated web application testing
Top100summit  谷歌-scott-improve your automated web application testingTop100summit  谷歌-scott-improve your automated web application testing
Top100summit 谷歌-scott-improve your automated web application testing
 
Basic Tutorial of React for Programmers
Basic Tutorial of React for ProgrammersBasic Tutorial of React for Programmers
Basic Tutorial of React for Programmers
 
Easy automation.py
Easy automation.pyEasy automation.py
Easy automation.py
 
Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...
Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...
Selenide Alternative in Practice - Implementation & Lessons learned [Selenium...
 
20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_tw
 
Selenium - The page object pattern
Selenium - The page object patternSelenium - The page object pattern
Selenium - The page object pattern
 
jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & Tricks
 
Intro to ReactJS
Intro to ReactJSIntro to ReactJS
Intro to ReactJS
 
Test automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubinTest automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubin
 
Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
 
The Screenplay Pattern: Better Interactions for Better Automation
The Screenplay Pattern: Better Interactions for Better AutomationThe Screenplay Pattern: Better Interactions for Better Automation
The Screenplay Pattern: Better Interactions for Better Automation
 
Lets make a better react form
Lets make a better react formLets make a better react form
Lets make a better react form
 
Ten Minutes To Tellurium
Ten Minutes To TelluriumTen Minutes To Tellurium
Ten Minutes To Tellurium
 
Enhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order componentEnhance react app with patterns - part 1: higher order component
Enhance react app with patterns - part 1: higher order component
 
React js
React jsReact js
React js
 
Selenium withnet
Selenium withnetSelenium withnet
Selenium withnet
 

Similar to Page Objects Pattern for Test Automation

A test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileA test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileGlobalLogic Ukraine
 
Desarrollo para Android con Groovy
Desarrollo para Android con GroovyDesarrollo para Android con Groovy
Desarrollo para Android con GroovySoftware Guru
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)Python Ireland
 
Android ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAndroid ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAravindharamanan S
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Dagger 2 vs koin
Dagger 2 vs koinDagger 2 vs koin
Dagger 2 vs koinJintin Lin
 
Parsing in ios to create an app
Parsing in ios to create an appParsing in ios to create an app
Parsing in ios to create an appHeaderLabs .
 
Unit Test 最後一哩路
Unit Test 最後一哩路Unit Test 最後一哩路
Unit Test 最後一哩路Hokila Jan
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andevMike Nakhimovich
 
WordPress - Custom Page Settings + Salesforce API Integration
WordPress - Custom Page Settings + Salesforce API IntegrationWordPress - Custom Page Settings + Salesforce API Integration
WordPress - Custom Page Settings + Salesforce API IntegrationKhoi Nguyen
 
How to write not breakable unit tests
How to write not breakable unit testsHow to write not breakable unit tests
How to write not breakable unit testsRafal Ksiazek
 
Java ppt Gandhi Ravi (gandhiri@gmail.com)
Java ppt  Gandhi Ravi  (gandhiri@gmail.com)Java ppt  Gandhi Ravi  (gandhiri@gmail.com)
Java ppt Gandhi Ravi (gandhiri@gmail.com)Gandhi Ravi
 
Drupal 8 Every Day: An Intro to Developing With Drupal 8
Drupal 8 Every Day: An Intro to Developing With Drupal 8Drupal 8 Every Day: An Intro to Developing With Drupal 8
Drupal 8 Every Day: An Intro to Developing With Drupal 8Acquia
 
Plug in development
Plug in developmentPlug in development
Plug in developmentLucky Ali
 
КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022
КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022
КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022GoQA
 

Similar to Page Objects Pattern for Test Automation (20)

Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
A test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobileA test framework out of the box - Geb for Web and mobile
A test framework out of the box - Geb for Web and mobile
 
Desarrollo para Android con Groovy
Desarrollo para Android con GroovyDesarrollo para Android con Groovy
Desarrollo para Android con Groovy
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)Google App Engine in 40 minutes (the absolute essentials)
Google App Engine in 40 minutes (the absolute essentials)
 
Android ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codesAndroid ui layouts ,cntls,webservices examples codes
Android ui layouts ,cntls,webservices examples codes
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Dagger 2 vs koin
Dagger 2 vs koinDagger 2 vs koin
Dagger 2 vs koin
 
End-to-end testing with geb
End-to-end testing with gebEnd-to-end testing with geb
End-to-end testing with geb
 
Parsing in ios to create an app
Parsing in ios to create an appParsing in ios to create an app
Parsing in ios to create an app
 
Unit Test 最後一哩路
Unit Test 最後一哩路Unit Test 最後一哩路
Unit Test 最後一哩路
 
Lecture 22
Lecture 22Lecture 22
Lecture 22
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
WordPress - Custom Page Settings + Salesforce API Integration
WordPress - Custom Page Settings + Salesforce API IntegrationWordPress - Custom Page Settings + Salesforce API Integration
WordPress - Custom Page Settings + Salesforce API Integration
 
How to write not breakable unit tests
How to write not breakable unit testsHow to write not breakable unit tests
How to write not breakable unit tests
 
Eclipse Tricks
Eclipse TricksEclipse Tricks
Eclipse Tricks
 
Java ppt Gandhi Ravi (gandhiri@gmail.com)
Java ppt  Gandhi Ravi  (gandhiri@gmail.com)Java ppt  Gandhi Ravi  (gandhiri@gmail.com)
Java ppt Gandhi Ravi (gandhiri@gmail.com)
 
Drupal 8 Every Day: An Intro to Developing With Drupal 8
Drupal 8 Every Day: An Intro to Developing With Drupal 8Drupal 8 Every Day: An Intro to Developing With Drupal 8
Drupal 8 Every Day: An Intro to Developing With Drupal 8
 
Plug in development
Plug in developmentPlug in development
Plug in development
 
КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022
КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022
КОСТЯНТИН КЛЮЄВ «Cypress.io : Let’s go farther» Online QADay 2022
 

Recently uploaded

Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 

Recently uploaded (20)

Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 

Page Objects Pattern for Test Automation

  • 1. Page Objects Oren Rubin Testim.io
  • 3. Talk Topics ● Page Objects ○ Why? ○ How? ○ When? ● Synchronously ○ Integrate in Page Objects ○ Remove magic sleep
  • 4. Talk Topics (we won't discuss) ● Locators - best practice ● Retrys ○ Locator retry (SPA) ○ Entire Test (stability)
  • 5. Page Objects? A Design Pattern. Provides a programmatic API to drive and interrogate a UI
  • 6. Naming things is hard ● Originally "Window Drivers" - Martin Fowler, 2004 ● Only pages? what about: ○ Header/footer ○ Components/widgets ○ Simple HTML elements (e.g., Tables)
  • 7. Page Object Pattern Expose the service you're interacting with, not the implementation. -- Selenium Wiki If you have a WebDriver APIs in your test methods... You're doing it wrong. -- Simon Stewart
  • 8. Step 1 - Expose The Service
  • 9. Step 1 - Expose The Service <form id="gaia_loginform"> <input id="email"> <input id="passwd"> <input id="signIn" type="submit"> </form>
  • 10. Step 1 - Expose The Service void testMyApp() { // login driver.findId("email").setText("u@app.com"); driver.findId("passwd").setText("12345"); driver.findId("signIn").click();; sleep(3000); // wait till page loads assert(...) // my assertions }
  • 11. Step 1 - Expose The Service void testMyApp() { // login driver.findId("email").setText("u@app.com"); driver.findId("passwd").setText("12345"); driver.findId("signIn").click();; sleep(3000); // wait till page loads assert(...) // my assertions } Simon says no!
  • 12. Test Automation the implementation of the automatic execution of some Business Logic Business Logic testMyApp() { testMyApp() { account.login(); gallery.showImage() } Implementation Class LoginPage() { login() { account.login(); // selenium code gallery.showImage() } } } Class GalleryPage() { showImage() {...} }
  • 13. Step 1 - Expose The Service loginPage = new LoginPage(); loginPage.login(); public class LoginPage { public login(); }
  • 14. Step 1 - Expose The Service loginPage = new LoginPage(); loginPage.login(); // compilation error: missing return type public class LoginPage { public ? login(); }
  • 15. Step 1 - Expose The Service Option 1: void public class LoginPage { public void login(); }
  • 16. Step 1 - Expose The Service void testMyApp() { // TODO move to @setup loginPage = new LoginPage(); loginPage.login(); sleep(3000); // wait till page loads assert(…) }
  • 17. Step 1 - Expose The Service Pro - Only deals with login page ● Don't interleave code relevant to other pages in this class. Con - Only deals with login page ● Was the login successful? ● On which page should we be? ● Is the new page ready?
  • 18. Step 1 - Expose The Service Option 2 (improved): Return a page object public class LoginPage { public GalleryPage login() {{ … return new GalleryPage(); } }
  • 19. Step 1 - Expose The Service void testMyApp() { // TODO consider moving to @before loginPage = new LoginPage(); galleryPage = loginPage.login(); sleep(3000); galleryPage.showImageFullscreen(); assert(…) }
  • 20. Q: What's the source of all evil? "No more war - no more blood shed"
  • 21. A: Random waits random sleep "No more war - no more blood shed" Abie Nathan The voice of peace
  • 22. Step 2 - Eliminate random sleep void testMyApp() { loginPage = new LoginPage(); galleryPage = loginPage.login(); sleep(3000); // should we move it? galleryPage.showImageFullscreen(); assert(…) }
  • 23. Step 2 - option 2 public class LoginPage { public GalleryPage login() { … sleep(3000); return new GalleryPage(); } }
  • 24. Step 2 - option 2 void testMyApp() { loginPage = new LoginPage(); // synchronous for testers galleryPage = loginPage.login(); galleryPage.showImageFullscreen(); assert(…) }
  • 25. Step 2 - back to option 1 public class LoginPage { void login() {…} } public class GalleryPage { void showImageFullscreen() {…} static GalleryPage waitForPage() {…} }
  • 26. Step 2 - back to option 1 void testMyApp() { loginPage = new LoginPage() loginPage.login(); // login() is void galleryPage = GalleryPage.waitForPage(); galleryPage.showImageFullscreen(); assert(…) }
  • 27. Step 2 - Combining options 1+2 public class LoginPage { public GalleryPage login() { … // return new GalleryPage(); return GalleryPage.waitForPage(); } }
  • 28. Step 2 - Force API comformance public class LoginPage { static LoginPage waitForPage() {…} GalleryPage login() {…} } public class GalleryPage { static GalleryPage waitForPage() {…} void showImageFullscreen() {…} }
  • 29. Step 2 - Basic code reuse abstract class BasicPage { // force derived classes public static BasicPage waitForPage(); } public class GalleryPage { public static BasicPage waitForPage() {…} }
  • 30. Step 2 - Basic code reuse abstract class BasicPage { // force derived classes public static BasicPage waitForPage(); } public class GalleryPage { public static BasicPage waitForPage() {…} } Computer says no! Cannot override static methods!
  • 31. Step 2 - Basic code reuse abstract class BasicPage { // force derived classes to implement public BasicPage waitForPage(); } public class GalleryPage { public BasicPage waitForPage() {…} } Computer says ok! But could be improved!
  • 32. Step 2 - Basic code reuse abstract class BasicPage { // force derived classes to implement public BasicPage waitForPage(); } public class GalleryPage { public GalleryPage waitForPage() {…} }
  • 33. Step 2 - Basic code reuse Another option is to use c'tor as wait public class GalleryPage { GalleryPage() { sleep(3000); } }
  • 34. Step 2 - Basic code reuse Tip! Add all common utilities to base class abstract class BasicPage { public BasicPage waitForPage(); public void waitForSpinnerToFade(); }
  • 35. What's next? Support Different Users
  • 36. Step 3 - Params and overload Sounds simple! public class LoginPage { public GalleryPage login(user, password); }
  • 37. Step 3 - Params and overload void testMyApp() { // bad password loginPage = new LoginPage(); loginPage = loginPage.login('a', 'wrong'); // good password galleryPage = loginPage.login('a', 'correct'); galleryPage.showImageFullscreen(); }
  • 38. Step 3 - Params and overload What about different roles? what about failures public class LoginPage { public GalleryPage login(user, password); public OtherPage login(user, password); public LoginPage login(user, password); } // compilation error: can't distinguish overload by return type
  • 39. Step 3 - Params and overload Compiles successfully public class LoginPage { public GalleryPage loginAsRegular(…); public OtherPage loginAsAdmin(…); public LoginPage loginAsBadCredintial(…); }
  • 40. Step 3 - Overloading Philosophy The LoginPage is used for: 1. Setup Drive the app to a specific state No one cares about the implementation 2. Test the Login page itself Test the specific implementation
  • 41. Step 3 - Overloading Philosophy 1. Setup // look ma! no params! loginPage.login(); Implementation might be using ● Username/password ● Cookies ● Google Account Might be hardcoded, or using config files
  • 42. Step 3 - Overloading Philosophy 2. Test the Login page itself ○ Abstract everything login(username, password) ○ Act on element wrappers (get/set kind) Definition: InputDriver getPasswordField() Usage: loginPage.getPasswordField.set('12345') * less recommended
  • 43. Step 3 - Overloading Philosophy Should we put everything together? class LoginPage { login() {} login(username, password){} }
  • 44. Step 3 - Overloading Philosophy Do we want more abstraction interface LoginPage { login(); LoginPageDriver getDriver(); } interface LoginPageDriver { login(username, password); }
  • 45. Step 3 - Overloading Philosophy class LoginPageImpl implements LoginPage, LoginPageDriver { login() {} login(username, password); LoginPageDriver getDriver() { return this; } }
  • 46. Step 4 - Page Factory public class LoginPage { private WebDriver driver; public LoginPage(driver) { this.driver = driver; } public GalleryPage login(username, password) { driver.findId("email").setText(username); … }
  • 47. Step 4 - Page Factory public class LoginPage { private WebElement email; public LoginPage(driver) { email = driver.findById("email"); } public GalleryPage login(username, password) { email.setText(username); … }
  • 48. Step 4 - Page Factory public class LoginPage { private WebElement email; private WebElement password; public LoginPage(driver) { email = driver.findById("email"); password = driver.findById("password"); // Linting error! too much glue code } }
  • 49. Step 4 - Page Factory public class LoginPage { private WebElement email; private WebElement password; /* look ma.. no ctor! */ } // loginPage = new LoginPage(); loginPage = PageFactory.initElement(driver, LoginPage.class)
  • 50. Step 4 - Page Factory Recommended way - in c'tor public class LoginPage { LoginPage() { // wait till ready sleep(3000); // init PageFactory.initElement(driver, this) } }
  • 51. Step 4 - Page Factory Pseudo Code class PageFactory { public static initElements(driver, class){ obj = class.new(); obj.properties.forEach(function(property) { if (property.type === WebElement.class) { byId = driver.findById(property.name); byName = driver.findByName(property.name); obj[property.name] = byId || byName } });
  • 52. Step 4 - Page Factory But this won't pass any code review public class GoogleLoginPage { private WebElement q; // Linting error! name too short and non descriptive }
  • 53. Step 4 - Page Factory Annotations to the rescue! public class GoogleLoginPage { @FindBy(how = How.name, using = "q") private WebElement searchBox; }
  • 54. Step 4 - Page Factory Shorthand FTW! public class GoogleLoginPage { @FindBy(name = "q") private WebElement searchBox; } Supports id, tagName and custom annotations!
  • 55. Step 4 - Assertions Two options ● Separate from Page Objects Community Recommends ● Inside Page Object Maybe inside the BasicPage class
  • 56. Off topic - No more sleep public class GalleryPage { public void waitForPage() { sleep(3000); } }
  • 57. Off topic - No more sleep Some solutions 1. The "No smoke without fire" - Wait for another element we know that loads last 2. The "Take the time" Wait till state is what you expect (element exists, row count,..). Selenium's implicit wait helps. 3. The "Coordinator" - Recommended! Wait for a sign from AUT
  • 58. The Coordinator login() waitForTestEvent('logged') gallery.showImage() // injected code setInterval( function({ if (works) { // we're done callback(); } ), 500ms)
  • 59. The Coordinator Option 1 - Javascript The API driver.executeAsyncScript("some js.. callback()"); Translation - browser runs function executeAsync(codeToEval, callback) { // evaluated code has access to callback eval(codeToEval); }
  • 60. The Coordinator Option 1 - Javascript The API driver.executeAsyncScript("some js.. callback()"); Translation - browser runs function executeAsync(codeToEval, callback) { // name 'callback' might change. last param guaranteed though eval(codeToEval); }
  • 61. The Coordinator driver.executeAsyncScript(" some js.. // callback() var lastIndex = arguments.length; var workingCallback = arguments[lastIndex] workingCallback(); // now setTimeout(workingCallback, 5000); // later ");
  • 62. The Coordinator The API driver.executeAsyncScript("some js.. callback()"); Better implementation function executeAsync(codeToEval, callback) { // evaluated code has access to callback var lastArgument = "arguments[arguments.legnth - 1]" eval(" ( function(callback){" +codeToEval+" } )(lastArgument)"); }
  • 63. The Coordinator - option 2 login() waitForTestEvent('logged') gallery.showImage() // load things … // ready sendTestEvent('logged')
  • 64. The Coordinator - option 2 Testers wait for a known event public class LoginPage { public GalleryPage login() { … waitForTestEvent('gallery-ready') return new GalleryPage(); } }
  • 65. The Coordinator - option 2 Dev add html element in test mode <body> <div id="app"> app goes here </div> <div id="test"> test events go here </div> </body>
  • 66. The Coordinator - option 2 Imlement waitForTestEvent in base class abstract class BasicPage { void waitForTestEvent(eventName) { By selector = By.CSS("#test ." + eventName) driver.waitForElement(selector); WebElement element = driver.find(selector); driver.removeElement(element); } }
  • 67. The Coordinator - option 2 Dev add html element in test mode function loadGalleryPage() { callServer(function() { // page is loaded testing.sendTestEvent('gallery-ready') }) }
  • 68. The Coordinator - option 2 Dev add html element in test mode class Testing { sendTestEvent: function(ev) { if (!app.isInTest){ return; $('#test').append('<div class="+ev+">') }) } Illustration only, don't use jQuery. Use Angular.js / Ember.js
  • 69. अंत! Thank You! Oren Rubin Testim.io | shexman@gmail | @shexman | linkedin