SlideShare a Scribd company logo
1 of 79
Download to read offline
Three simple chords of Alternative
“PageObjects” and Hardcore of
LoadableComponents
Iakiv Kramarenko
Conventions :)
● Sympathy colors***:
Green =
Orange =
Red =
*** often are subjective and applied to specific context ;)
● At project with no Web UI automation, no unit testing
● With 4(5) Manual QA
– Using checklists + long detailed End to End test cases
● With 1 QA Automation found
Testing single page web app
● Ajax
● only <div>, <a>, <input>
– Inconsistent implementation
● No confident urls
● One current Frame/Page with content per user step
– Deep structure:
● Authorization > Menus > SubMenus > Tabs > Extra > Extra
– Modal dialogs
Met Requirements
● Automate high level scenarios
– use AC from stories
– existed Manual Scenarios
●
Use 3rd
party solutions
– Java Desired
● Involve Manual QA
– provide easy to use solution
– BDD Desired
● In Tough Deadlines :)
Dreaming of framework...
● Fast in development
– Using instruments quite agile to adapt to project specifics
● Extremely easy to use and learn
● With DRY and handy
page loading
● Simple DSL for tests
● BDD – light and DRY as
much as possible
Choosing Programming Paradigm
For WebUI Automation
Based on https://bitbucket.org/yashaka/oopbucket/src
OOP or not to OOP
That is the question
OOP can impose you to
● Learn much
– Concept itself
– Design Patterns
● Have bulky structured implementation
– Coupled via inheritance
– Having too many layers of abstractions
● Work harder to implement DSL
Do you need this?
OOP can give you
● Batch common operations on pages/steps ***
E.g.
– Reporting per steps
– abstract open() per page
– abstract getExpectedElements() per page
● Obligations over conventions
● Certainty in future refactoring
Do you need this?
Sometimes...
● Batch/common operations may be redundant for pages/steps
– Sufficient reporting can be implemented in low-level libraries
– “batch” open() may be called on LoadableComponent separately
– IHaveExpectedElements may give no advantages for smoke
testing in your project
● And still can be implemented separately in e.g.
LoadableComponent
● Or via Reflection
– Some “common” implementation can be moved from pages to
“widgets” and still be implemented with OOP
Sometimes...
● Conventions can be very easy
● No severe refactoring is coming
– Test Automation Project is not a NASA Space Shuttle ;).
So Think Always!
Procedural
Functional
OOP
And
Balance!
Classic PageObject Pattern
public class LoginClassicPageObject extends BasePage {
@FindBy(css = "#login-form")
private WebElement container;
@FindBy(name = "username")
private WebElement usernameField;
@FindBy(name = "password")
private WebElement passwordField;
@FindBy(css = ".ui-button[value='Log in']")
private WebElement loginButton;
public void WebElement getContainer(){
return container;
}
@Override
public void open(String baseurl) {
driver.get(baseurl);
}
public void doLogin(String login, String pass){
usernameField.sendKeys(login);
passwordField.sendKeys(pass);
loginButton.click();
}
public LoginClassicPageObject(
WebDriver driver, String baseurl) {
PageFactory.initElements(driver, this);
this.driver = driver;
this.baseurl = baseurl;
}
private String baseurl;
private WebDriver driver;
}
Involving
public class LoginSelenidePageObject extends BasePage {
private final String container = "#login-form";
private final By username = By.name("username");
private final By password = By.name("password");
private final String loginButton = ".ui-button[value='Log in']";
public void SelenideElement getContainer(){
return $(container);
}
@Override
public void open(String baseurl) {
open(baseurl);
}
public void doLogin(String login, String password){
$(username).setValue(login);
$(password).sendKeys(password);
$(loginButton).click();
}
public LoginSelenidePageObject(String baseurl) {
this.baseurl = baseurl;
}
private String baseurl;
}
public class LoginSelenidePageObject2 extends BasePage {
public void SelenideElement сontainer(){ return $("#login-form");}
public void SelenideElement usernameField(){ return $(By.name("username"));}
public void SelenideElement passwordField(){ return $(By.name("password"));}
public void SelenideElement loginButton(){ return $(".ui-button[value='Log in']");}
@Override
public void open(String baseurl) {
open(baseurl);
}
public void doLogin(String login, String password){
usernameField().setValue(login);
passwordField().setValue(password);
loginButton.click();
}
public LoginSelenidePageObject(String baseurl) {
this.baseurl = baseurl;
}
private String baseurl;
}
“Procedural” approach to
implement “PageObjects”
PageUtils
public class Login{
public static void open(String baseurl) {
Selenide.open(baseurl);
}
public static SelenideElement container() { return $("#login-form");}
public static SelenideElement usernameField(){ return $(By.name("username"));}
public static SelenideElement passwordField(){ return $(By.name("password"));}
public static SelenideElement loginButton(){ return $(".ui-button[value='Log in']");}
public static void doLogin(String login, String password){
usernameField().setValue(login);
passwordField().setValue(password);
loginButton().click();
}
}
A
l
t
e
r
n
a
t
I
v
E
Or...
public class Login{
public static void open(String baseurl) {
Selenide.open(baseurl);
}
public static final String container = "#login-form";
public static final By username = By.name("username");
public static final By password = By.name("password");
public static final String loginButton = ".ui-button[value='Log in']";
public static void doLogin(String login, String password){
$(username).setValue(login);
$(password).sendKeys(password);
$(loginButton).click();
}
}
A
l
t
e
r
n
a
t
I
v
E
PageUtils usage
Login.open(baseurl);
Login.doLogin(username, password);
Home.addProduct("Product_1");
UserPanel.doLogout();
Login.container().shouldBe(visible);
PageObjects usage
loginPage = new LoginPage(baseurl);
loginPage.open();
loginPage.doLogin(username, password);
homePage = new HomePage();
homePage.addProduct("Product_1");
homePage.doLogout();
loginPage.getContainer().shouldBe(visible);
C
o
m
p
a
r
e
Three Chords of “Procedural”
PageUtils :)
1. Abstraction
Factor out implementation details into helper methods
doLogin(username, password);
public static void doLogin(String login, String
password){
usernameField().setValue(login);
passwordField().setValue(password);
loginButton().click();
}
public static SelenideElement usernameField(){
return $(By.name("username"));
}
2. Modularity
Collect your helpers in classes of correspondent context
3. Try to Be “Functional”
– write functions returning result only based on passed
parameters
– write smaller functions and use them in a 'chain':
select(dropdownIn(userPanel()), “En”)
– Instead of
selectLanguageDropdownInUserPanel(“En”)
– Use Composition over Inheritance
P.S. Be smart ;)
– You can't use inheritance.
● If you have any conventions you need to remember to
follow them
When Use?
● Need to involve and teach Manual/Junior Automation QA
● Need a fast solution
● Language support Functional Paradigm
– At least first-class functions
● You know what you do:)
When maybe not use?
● All committers to test framework are either Senior QA
Automation or Developers
● No need to teach Manual QA/Juniors
● No tough deadlines
● Java (only)
When not use?
● Your are Junior/Middle
– And/Or Manager/Lead/Dev says: OOP or DIE! :)
● You can't predict what features your framework may need
in future
This is how
your test
model may
look
“What are those classes
in pagegetters
package?”
:)
Here come
Loadable Components...
public abstract class SimpleLoadableComponent {
public void get() {
try {
isLoaded();
} catch (Error e) {
load();
isLoaded();
}
}
protected abstract void load();
protected abstract void isLoaded() throws Error;
}
What's the point?
O_o
From :(
Login.open(baseurl);
Home.open(username, password);
Home.ensureHasProduct("Product_1");
Product.open("Product_1");
ProductTestTables.open();
ProductTestTables.addCategoryButton().shouldBe
(visible);
Technically To
(new ProductTestTablesPage(
new ProductPage(
new HomePage(
new LoginPage(baseurl),
username, password),
"Product_1"))).get();
Actually To :)
ProductTestTables.page("Product_1").get();
Selenium LoadableComponent
public abstract class LoadableComponent<T extends LoadableComponent<T>> {
@SuppressWarnings("unchecked")
public T get() {
try {
isLoaded();
return (T) this;
} catch (Error e) {
load();
}
isLoaded();
return (T) this;
}
protected abstract void load();
protected abstract void isLoaded() throws Error;
}
Ajax?
> Selenium SlowLoadableComponent
Calm down, no code, just link:)
● (c) A LoadableComponent which might not have finished
loading when load() returns. After a call to load(), the isLoaded()
method should continue to fail until the component has fully
loaded.
Once you need some abstract
classes to DRY your code...
public abstract class
AbstractPage<T extends SlowLoadableComponent<T>>
extends SlowLoadableComponent<T>{
O_O
Typical isLoaded()
Implementations
'url-based' isLoaded implementation
protected void isLoaded() throws Error {
String url = driver.getCurrentUrl();
assertTrue(url.contains(pageUrl));
}
If you want to identify pages by actual
content
protected void isLoaded() throws Error {
try {
WebElement div = driver.findElement(By.id("login-select"));
} catch (NoSuchElementException e) {
fail("Cannot locate user name link");
}
}
Once you use @FindBy
public void isLoaded() throws Error {
if (loginButton != null) {
assertElementIsDisplayed(loginButton);
} else {
fail("Login button is not loaded");
}
}
Typical Selenide isLoaded()
implementation
public void isLoaded(){
Login.container().shouldBe(visible);
}
Selenide LoadableComponent
public abstract class SelenideLoadableComponent {
public void get() {
long originalTimeout = Configuration.timeout;
try {
Configuration.timeout = 0;
isLoaded();
Configuration.timeout = originalTimeout;
} catch (Error e) {
Configuration.timeout = originalTimeout;
load();
isLoaded();
}
}
protected abstract void load();
protected abstract void isLoaded();
}
“slow”,
ajax-friendly
by default
“no”
<T extends
Madness>
If you wish...
public abstract class AbstractPage extends
SelenideLoadableComponent {
public abstract void isLoaded();
}
Home.page().get();
doCrazyStuff();
Home.page().isLoaded() // still?
Implementation Example
Initialize
public class ProductPage extends SelenideLoadablePage{
private HomePage parent;
protected String productName;
public ProductPage(HomePage parent, String productName){
this.parent = parent;
this.productName = productName;
}
….
Load
protected void load() {
parent.get();
Home.ensureHasProduct(productName);
Product.open(productName);
}
isLoaded()
public void isLoaded() {
Breadcrumb.productLink(productName).shouldBe(visible);
Product.testTableItem().shouldBe(visible);
}
Factory
public class Product {
public static ProductPage page(String productName){
return new ProductPage(Home.page(), productName);
}
…
}
If it would be so
“simple”...
But it would not :p
public class AuthorizedPage extends AbstractPage {
protected AbstractPage parent;
private String username;
private String password;
public AuthorizedPage(
LoginPage parent, String username, String password) {
this.parent = parent;
this.username = username;
this.password = password;
}
public AuthorizedPage(AuthorizedPage parent){
this.parent = parent;
}
...
Initialize
public class ProductPage extends AuthorizedPage{
protected String productName;
public ProductPage(HomePage parent, String productName){
super(parent);
this.productName = productName;
}
public ProductPage(ProductPage parent){ //It's possible to “load” page from itself
super(parent);
this.productName = parent.getProductName();
}
….
Load
protected void load() {
parent.get();
if (parent instanceof ProductPage) {
Breadcrumb.productLink(((ProductPage) parent).getProductName()).click();
} else { //parent instanceof HomePage
Home.ensureHasProduct(productName);
Product.open(productName);
}
}
Though...
The beast is not so scary after you write up to 10 first Lions
Components :)
And
You still can live only with PageUtils and keep LoadableComponents
as options to be implemented by crazy devs:)
QA Dev
scenario "Surf Pages", {
where "Page is #page", {
page = [ Login.page(),
Home.page(),
Settings.page(),
Login.page(Authorized.page()),
Product.page(TEST_PRODUCT),
Login.page(Authorized.page()),
Settings.page(),
Product.page(Home.page(Settings.page()), "Product_1"),
Product.page(Product.page(TEST_PRODUCT)),
ProductTestTables.page(TEST_PRODUCT),
Login.page(Authorized.page())]
}
then "go to #page", { page.get() }
}
Bonus :)
When Maybe Use?
● No confident urls
● Complex “deep” page hierarchy
● Authorization > Menus > SubMenus > Tabs > Extra >
Extra...
When Use?
● Desired dependent End to End scenarios with “walking
through pages” feature
– emulating real user experience
– big amount of such test cases
When maybe not use?
● Too many ways to load the same page
● Though you still can implement LC for 1 way, if you
need to use it often.
● Too many pages, especially “visible” at the same time
When not use?
● URL-based loading is enough
– Or work around via custom JS load helpers is enough
● what is true for most cases...
● Have no “deep” pages
All Together
● PageUtils:
class Login
– Page smart loader:
Login.page().get()
– Page root html element:
Login.container()
– Method to open Page once preconditions satisfied:
Login.open()
– Page elements:
Login.signInButton()
– Page business steps:
Login.doLogin(“guest”, “1234”)
● LoadableComponent:
class LoginPage
isLoaded()
load()
Conventions
Ideas to think about
LoadableComponent
● Is not PageObject
– Though you can integrate it into PageObject, violating Single
Responsibility principle
● It's an object incapsulating page loading logic.
– Initializing the “loading way” through LC constructor
● It's possible also to move logic into separate loadable
components fro each “way”, though this may lead to
overcomplicated hierarchy
– choosing the “way” in load() implementation
– And then just get() your page
LoadableComponent Integration
● PageUtils + LoadableComponent
– Two classes instead of one
● PageObject + LoadableComponent
– May be harder to achieve friendly tests code
● PageObject extends LoadableComponent
– Bulky
– Harder to explain to juniors/interns
– Violates Single Responsibility Principle
LoadableComponent Factory
Too more calls to page() ?
Use Singleton Pattern
PageUtils
Page elements as functions
public static SelenideElement usernameField(){
return $(By.name("username"));
}
…
Login.usernameField().setVal("guest");
Page elements as locators
public static final By usernameField = By.name("username");
…
$(Login.usernameField).setVal("guest");
C
o
m
p
a
r
e
Functional “Scales”
● Main cons of Procedural approach is that it may be not
DRY
● In most cases you can fix this with high-order functions in
much more concise way than with OOP
– Though less obvious for non-FP user
Ideas for improvements
● Use Groovy as main language
– in order to simplify implementation.
– Finally Java is the OOP language
● and not adapted for both procedural and functional styles.
– In Groovy OOP may be not “bulky”
● and with some functional & metaprogramming features you
can achieve the same level of simplicity still powerful
– and easy to explain to juniors “how to use” (though not
“how to understand details”)
Did it work for Manual QA?
Demo
Q&A
Resources, Links
● Src of example test framework:
https://github.com/yashaka/gribletest
● Programming Paradigms Comparison:
https://bitbucket.com/yashaka/oopbucket/src
● Functional Thinking articles:
http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=fun
● Application under test used in easyb examples:
http://grible.org/download.php
● Instruments
– http://selenide.org/
– http://code.google.com/p/selenium/wiki/LoadableComponent
● To Artem Chernysh for implementation of main base part
of the test framework for this presentation
– https://github.com/elaides/gribletest
● To Maksym Barvinskyi for application under test
– http://grible.org/
Contacts
● yashaka@gmail.com
● skype: yashaolin
● twitter: @yashaka
● http://www.linkedin.com/in/iakivkramarenko

More Related Content

What's hot

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
 
Better Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component PatternBetter Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component PatternSQALab
 
A journey beyond the page object pattern
A journey beyond the page object patternA journey beyond the page object pattern
A journey beyond the page object patternRiverGlide
 
Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Iakiv Kramarenko
 
Web ui tests examples with selenide, nselene, selene & capybara
Web ui tests examples with  selenide, nselene, selene & capybaraWeb ui tests examples with  selenide, nselene, selene & capybara
Web ui tests examples with selenide, nselene, selene & capybaraIakiv Kramarenko
 
Out of box page object design pattern, java
Out of box page object design pattern, javaOut of box page object design pattern, java
Out of box page object design pattern, javaCOMAQA.BY
 
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
 
Node.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideNode.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideMek Srunyu Stittri
 
Selenium - The page object pattern
Selenium - The page object patternSelenium - The page object pattern
Selenium - The page object patternMichael Palotas
 
Fullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year laterFullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year laterMek Srunyu Stittri
 
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
 
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
 
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
 
Testing Web Applications
Testing Web ApplicationsTesting Web Applications
Testing Web ApplicationsSeth McLaughlin
 
Test automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubinTest automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubinOren Rubin
 

What's hot (20)

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...
 
Better Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component PatternBetter Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component Pattern
 
A journey beyond the page object pattern
A journey beyond the page object patternA journey beyond the page object pattern
A journey beyond the page object pattern
 
Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015Polyglot automation - QA Fest - 2015
Polyglot automation - QA Fest - 2015
 
Web ui tests examples with selenide, nselene, selene & capybara
Web ui tests examples with  selenide, nselene, selene & capybaraWeb ui tests examples with  selenide, nselene, selene & capybara
Web ui tests examples with selenide, nselene, selene & capybara
 
Out of box page object design pattern, java
Out of box page object design pattern, javaOut of box page object design pattern, java
Out of box page object design pattern, java
 
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
 
Node.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideNode.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java side
 
Selenium - The page object pattern
Selenium - The page object patternSelenium - The page object pattern
Selenium - The page object pattern
 
Fullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year laterFullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year later
 
Gems Of Selenium
Gems Of SeleniumGems Of Selenium
Gems Of Selenium
 
Page object pattern
Page object patternPage object pattern
Page object pattern
 
Marcin Wasilczyk - Page objects with selenium
Marcin Wasilczyk - Page objects with seleniumMarcin Wasilczyk - Page objects with selenium
Marcin Wasilczyk - Page objects with selenium
 
My Test Automation Journey
My Test Automation JourneyMy Test Automation Journey
My Test Automation Journey
 
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
 
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
 
Lets make a better react form
Lets make a better react formLets make a better react form
Lets make a better react form
 
Testing Web Applications
Testing Web ApplicationsTesting Web Applications
Testing Web Applications
 
Night Watch with QA
Night Watch with QANight Watch with QA
Night Watch with QA
 
Test automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubinTest automation & Seleniun by oren rubin
Test automation & Seleniun by oren rubin
 

Viewers also liked

Better Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component PatternBetter Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component PatternSargis Sargsyan
 
You do not need automation engineer - Sqa Days - 2015 - EN
You do not need automation engineer  - Sqa Days - 2015 - ENYou do not need automation engineer  - Sqa Days - 2015 - EN
You do not need automation engineer - Sqa Days - 2015 - ENIakiv Kramarenko
 
Write Selenide in Python 15 min
Write Selenide in Python 15 minWrite Selenide in Python 15 min
Write Selenide in Python 15 minIakiv Kramarenko
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Iakiv Kramarenko
 
Automation is Easy! (python version)
Automation is Easy! (python version)Automation is Easy! (python version)
Automation is Easy! (python version)Iakiv Kramarenko
 
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшeQA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшeQAFest
 
Web testing with Selenium
Web testing with SeleniumWeb testing with Selenium
Web testing with SeleniumXBOSoft
 
Continuous Testing Meets the Classroom at Code.org
Continuous Testing Meets the Classroom at Code.orgContinuous Testing Meets the Classroom at Code.org
Continuous Testing Meets the Classroom at Code.orgSauce Labs
 
Pivotal Failure - Lessons Learned from Lean Startup Machine DC
Pivotal Failure - Lessons Learned from Lean Startup Machine DCPivotal Failure - Lessons Learned from Lean Startup Machine DC
Pivotal Failure - Lessons Learned from Lean Startup Machine DCDave Haeffner
 
How To Use Selenium Successfully
How To Use Selenium SuccessfullyHow To Use Selenium Successfully
How To Use Selenium SuccessfullyDave Haeffner
 
Full Stack Testing Done Well
Full Stack Testing Done WellFull Stack Testing Done Well
Full Stack Testing Done WellDave Haeffner
 
Agile testing for mere mortals
Agile testing for mere mortalsAgile testing for mere mortals
Agile testing for mere mortalsDave Haeffner
 
Cross Platform Appium Tests: How To
Cross Platform Appium Tests: How ToCross Platform Appium Tests: How To
Cross Platform Appium Tests: How ToGlobalLogic Ukraine
 
Getting Started with Selenium
Getting Started with SeleniumGetting Started with Selenium
Getting Started with SeleniumDave Haeffner
 

Viewers also liked (19)

Better Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component PatternBetter Page Object Handling with Loadable Component Pattern
Better Page Object Handling with Loadable Component Pattern
 
KISS Automation.py
KISS Automation.pyKISS Automation.py
KISS Automation.py
 
You do not need automation engineer - Sqa Days - 2015 - EN
You do not need automation engineer  - Sqa Days - 2015 - ENYou do not need automation engineer  - Sqa Days - 2015 - EN
You do not need automation engineer - Sqa Days - 2015 - EN
 
Write Selenide in Python 15 min
Write Selenide in Python 15 minWrite Selenide in Python 15 min
Write Selenide in Python 15 min
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
 
Automation is Easy! (python version)
Automation is Easy! (python version)Automation is Easy! (python version)
Automation is Easy! (python version)
 
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшeQA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
 
Web testing with Selenium
Web testing with SeleniumWeb testing with Selenium
Web testing with Selenium
 
Selenium
SeleniumSelenium
Selenium
 
Continuous Testing Meets the Classroom at Code.org
Continuous Testing Meets the Classroom at Code.orgContinuous Testing Meets the Classroom at Code.org
Continuous Testing Meets the Classroom at Code.org
 
Pivotal Failure - Lessons Learned from Lean Startup Machine DC
Pivotal Failure - Lessons Learned from Lean Startup Machine DCPivotal Failure - Lessons Learned from Lean Startup Machine DC
Pivotal Failure - Lessons Learned from Lean Startup Machine DC
 
How To Use Selenium Successfully
How To Use Selenium SuccessfullyHow To Use Selenium Successfully
How To Use Selenium Successfully
 
Full Stack Testing Done Well
Full Stack Testing Done WellFull Stack Testing Done Well
Full Stack Testing Done Well
 
Agile testing for mere mortals
Agile testing for mere mortalsAgile testing for mere mortals
Agile testing for mere mortals
 
The Testable Web
The Testable WebThe Testable Web
The Testable Web
 
Selenium Basics
Selenium BasicsSelenium Basics
Selenium Basics
 
Cross Platform Appium Tests: How To
Cross Platform Appium Tests: How ToCross Platform Appium Tests: How To
Cross Platform Appium Tests: How To
 
Getting Started with Selenium
Getting Started with SeleniumGetting Started with Selenium
Getting Started with Selenium
 
Bdd lessons-learned
Bdd lessons-learnedBdd lessons-learned
Bdd lessons-learned
 

Similar to Three simple chords of Alternative "PageObjects

Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Testing ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETTesting ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETBen Hall
 
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Java Web Programming on Google Cloud Platform [3/3] : Google Web ToolkitJava Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Java Web Programming on Google Cloud Platform [3/3] : Google Web ToolkitIMC Institute
 
Apache Wicket Web Framework
Apache Wicket Web FrameworkApache Wicket Web Framework
Apache Wicket Web FrameworkLuther Baker
 
SharePoint Cincy 2012 - jQuery essentials
SharePoint Cincy 2012 - jQuery essentialsSharePoint Cincy 2012 - jQuery essentials
SharePoint Cincy 2012 - jQuery essentialsMark Rackley
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenerytoddbr
 
Stencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrivedStencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrivedGil Fink
 
Stencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrivedStencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrivedGil Fink
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsJeff Durta
 
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...Applitools
 
Web UI test automation instruments
Web UI test automation instrumentsWeb UI test automation instruments
Web UI test automation instrumentsArtem Nagornyi
 
MVC & SQL_In_1_Hour
MVC & SQL_In_1_HourMVC & SQL_In_1_Hour
MVC & SQL_In_1_HourDilip Patel
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e bigAndy Peterson
 
Built to last javascript for enterprise
Built to last   javascript for enterpriseBuilt to last   javascript for enterprise
Built to last javascript for enterpriseMarjan Nikolovski
 
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
 
Workshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsWorkshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsSami Ekblad
 

Similar to Three simple chords of Alternative "PageObjects (20)

Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
End-to-end testing with geb
End-to-end testing with gebEnd-to-end testing with geb
End-to-end testing with geb
 
Testing ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETTesting ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NET
 
Gwt.create
Gwt.createGwt.create
Gwt.create
 
Frontend training
Frontend trainingFrontend training
Frontend training
 
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Java Web Programming on Google Cloud Platform [3/3] : Google Web ToolkitJava Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
 
Apache Wicket Web Framework
Apache Wicket Web FrameworkApache Wicket Web Framework
Apache Wicket Web Framework
 
SharePoint Cincy 2012 - jQuery essentials
SharePoint Cincy 2012 - jQuery essentialsSharePoint Cincy 2012 - jQuery essentials
SharePoint Cincy 2012 - jQuery essentials
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
 
Stencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrivedStencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrived
 
Stencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrivedStencil the time for vanilla web components has arrived
Stencil the time for vanilla web components has arrived
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
Mastering UI automation at Scale: Key Lessons and Best Practices (By Fernando...
 
Google Web Toolkit
Google Web ToolkitGoogle Web Toolkit
Google Web Toolkit
 
Web UI test automation instruments
Web UI test automation instrumentsWeb UI test automation instruments
Web UI test automation instruments
 
MVC & SQL_In_1_Hour
MVC & SQL_In_1_HourMVC & SQL_In_1_Hour
MVC & SQL_In_1_Hour
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e big
 
Built to last javascript for enterprise
Built to last   javascript for enterpriseBuilt to last   javascript for enterprise
Built to last javascript for enterprise
 
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
 
Workshop: Building Vaadin add-ons
Workshop: Building Vaadin add-onsWorkshop: Building Vaadin add-ons
Workshop: Building Vaadin add-ons
 

Recently uploaded

Congestive Cardiac Failure..presentation
Congestive Cardiac Failure..presentationCongestive Cardiac Failure..presentation
Congestive Cardiac Failure..presentationdeepaannamalai16
 
Textual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHSTextual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHSMae Pangan
 
4.11.24 Mass Incarceration and the New Jim Crow.pptx
4.11.24 Mass Incarceration and the New Jim Crow.pptx4.11.24 Mass Incarceration and the New Jim Crow.pptx
4.11.24 Mass Incarceration and the New Jim Crow.pptxmary850239
 
Concurrency Control in Database Management system
Concurrency Control in Database Management systemConcurrency Control in Database Management system
Concurrency Control in Database Management systemChristalin Nelson
 
ClimART Action | eTwinning Project
ClimART Action    |    eTwinning ProjectClimART Action    |    eTwinning Project
ClimART Action | eTwinning Projectjordimapav
 
31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...
31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...
31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...Nguyen Thanh Tu Collection
 
Expanded definition: technical and operational
Expanded definition: technical and operationalExpanded definition: technical and operational
Expanded definition: technical and operationalssuser3e220a
 
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptxQ4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptxlancelewisportillo
 
ICS2208 Lecture6 Notes for SL spaces.pdf
ICS2208 Lecture6 Notes for SL spaces.pdfICS2208 Lecture6 Notes for SL spaces.pdf
ICS2208 Lecture6 Notes for SL spaces.pdfVanessa Camilleri
 
Man or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptx
Man or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptxMan or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptx
Man or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptxDhatriParmar
 
Mental Health Awareness - a toolkit for supporting young minds
Mental Health Awareness - a toolkit for supporting young mindsMental Health Awareness - a toolkit for supporting young minds
Mental Health Awareness - a toolkit for supporting young mindsPooky Knightsmith
 
Mythology Quiz-4th April 2024, Quiz Club NITW
Mythology Quiz-4th April 2024, Quiz Club NITWMythology Quiz-4th April 2024, Quiz Club NITW
Mythology Quiz-4th April 2024, Quiz Club NITWQuiz Club NITW
 
Q-Factor HISPOL Quiz-6th April 2024, Quiz Club NITW
Q-Factor HISPOL Quiz-6th April 2024, Quiz Club NITWQ-Factor HISPOL Quiz-6th April 2024, Quiz Club NITW
Q-Factor HISPOL Quiz-6th April 2024, Quiz Club NITWQuiz Club NITW
 
Q-Factor General Quiz-7th April 2024, Quiz Club NITW
Q-Factor General Quiz-7th April 2024, Quiz Club NITWQ-Factor General Quiz-7th April 2024, Quiz Club NITW
Q-Factor General Quiz-7th April 2024, Quiz Club NITWQuiz Club NITW
 
Active Learning Strategies (in short ALS).pdf
Active Learning Strategies (in short ALS).pdfActive Learning Strategies (in short ALS).pdf
Active Learning Strategies (in short ALS).pdfPatidar M
 
Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...
Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...
Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...DhatriParmar
 
Unraveling Hypertext_ Analyzing Postmodern Elements in Literature.pptx
Unraveling Hypertext_ Analyzing  Postmodern Elements in  Literature.pptxUnraveling Hypertext_ Analyzing  Postmodern Elements in  Literature.pptx
Unraveling Hypertext_ Analyzing Postmodern Elements in Literature.pptxDhatriParmar
 
ROLES IN A STAGE PRODUCTION in arts.pptx
ROLES IN A STAGE PRODUCTION in arts.pptxROLES IN A STAGE PRODUCTION in arts.pptx
ROLES IN A STAGE PRODUCTION in arts.pptxVanesaIglesias10
 
4.11.24 Poverty and Inequality in America.pptx
4.11.24 Poverty and Inequality in America.pptx4.11.24 Poverty and Inequality in America.pptx
4.11.24 Poverty and Inequality in America.pptxmary850239
 

Recently uploaded (20)

Congestive Cardiac Failure..presentation
Congestive Cardiac Failure..presentationCongestive Cardiac Failure..presentation
Congestive Cardiac Failure..presentation
 
Textual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHSTextual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHS
 
4.11.24 Mass Incarceration and the New Jim Crow.pptx
4.11.24 Mass Incarceration and the New Jim Crow.pptx4.11.24 Mass Incarceration and the New Jim Crow.pptx
4.11.24 Mass Incarceration and the New Jim Crow.pptx
 
Concurrency Control in Database Management system
Concurrency Control in Database Management systemConcurrency Control in Database Management system
Concurrency Control in Database Management system
 
ClimART Action | eTwinning Project
ClimART Action    |    eTwinning ProjectClimART Action    |    eTwinning Project
ClimART Action | eTwinning Project
 
31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...
31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...
31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...
 
Expanded definition: technical and operational
Expanded definition: technical and operationalExpanded definition: technical and operational
Expanded definition: technical and operational
 
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptxQ4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
 
ICS2208 Lecture6 Notes for SL spaces.pdf
ICS2208 Lecture6 Notes for SL spaces.pdfICS2208 Lecture6 Notes for SL spaces.pdf
ICS2208 Lecture6 Notes for SL spaces.pdf
 
Man or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptx
Man or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptxMan or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptx
Man or Manufactured_ Redefining Humanity Through Biopunk Narratives.pptx
 
Mental Health Awareness - a toolkit for supporting young minds
Mental Health Awareness - a toolkit for supporting young mindsMental Health Awareness - a toolkit for supporting young minds
Mental Health Awareness - a toolkit for supporting young minds
 
Mythology Quiz-4th April 2024, Quiz Club NITW
Mythology Quiz-4th April 2024, Quiz Club NITWMythology Quiz-4th April 2024, Quiz Club NITW
Mythology Quiz-4th April 2024, Quiz Club NITW
 
Q-Factor HISPOL Quiz-6th April 2024, Quiz Club NITW
Q-Factor HISPOL Quiz-6th April 2024, Quiz Club NITWQ-Factor HISPOL Quiz-6th April 2024, Quiz Club NITW
Q-Factor HISPOL Quiz-6th April 2024, Quiz Club NITW
 
Q-Factor General Quiz-7th April 2024, Quiz Club NITW
Q-Factor General Quiz-7th April 2024, Quiz Club NITWQ-Factor General Quiz-7th April 2024, Quiz Club NITW
Q-Factor General Quiz-7th April 2024, Quiz Club NITW
 
Active Learning Strategies (in short ALS).pdf
Active Learning Strategies (in short ALS).pdfActive Learning Strategies (in short ALS).pdf
Active Learning Strategies (in short ALS).pdf
 
Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...
Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...
Beauty Amidst the Bytes_ Unearthing Unexpected Advantages of the Digital Wast...
 
INCLUSIVE EDUCATION PRACTICES FOR TEACHERS AND TRAINERS.pptx
INCLUSIVE EDUCATION PRACTICES FOR TEACHERS AND TRAINERS.pptxINCLUSIVE EDUCATION PRACTICES FOR TEACHERS AND TRAINERS.pptx
INCLUSIVE EDUCATION PRACTICES FOR TEACHERS AND TRAINERS.pptx
 
Unraveling Hypertext_ Analyzing Postmodern Elements in Literature.pptx
Unraveling Hypertext_ Analyzing  Postmodern Elements in  Literature.pptxUnraveling Hypertext_ Analyzing  Postmodern Elements in  Literature.pptx
Unraveling Hypertext_ Analyzing Postmodern Elements in Literature.pptx
 
ROLES IN A STAGE PRODUCTION in arts.pptx
ROLES IN A STAGE PRODUCTION in arts.pptxROLES IN A STAGE PRODUCTION in arts.pptx
ROLES IN A STAGE PRODUCTION in arts.pptx
 
4.11.24 Poverty and Inequality in America.pptx
4.11.24 Poverty and Inequality in America.pptx4.11.24 Poverty and Inequality in America.pptx
4.11.24 Poverty and Inequality in America.pptx
 

Three simple chords of Alternative "PageObjects

  • 1. Three simple chords of Alternative “PageObjects” and Hardcore of LoadableComponents Iakiv Kramarenko
  • 2. Conventions :) ● Sympathy colors***: Green = Orange = Red = *** often are subjective and applied to specific context ;)
  • 3. ● At project with no Web UI automation, no unit testing ● With 4(5) Manual QA – Using checklists + long detailed End to End test cases ● With 1 QA Automation found
  • 4. Testing single page web app ● Ajax ● only <div>, <a>, <input> – Inconsistent implementation ● No confident urls ● One current Frame/Page with content per user step – Deep structure: ● Authorization > Menus > SubMenus > Tabs > Extra > Extra – Modal dialogs
  • 5. Met Requirements ● Automate high level scenarios – use AC from stories – existed Manual Scenarios ● Use 3rd party solutions – Java Desired ● Involve Manual QA – provide easy to use solution – BDD Desired ● In Tough Deadlines :)
  • 6. Dreaming of framework... ● Fast in development – Using instruments quite agile to adapt to project specifics ● Extremely easy to use and learn ● With DRY and handy page loading ● Simple DSL for tests ● BDD – light and DRY as much as possible
  • 7. Choosing Programming Paradigm For WebUI Automation Based on https://bitbucket.org/yashaka/oopbucket/src
  • 8. OOP or not to OOP That is the question
  • 9. OOP can impose you to ● Learn much – Concept itself – Design Patterns ● Have bulky structured implementation – Coupled via inheritance – Having too many layers of abstractions ● Work harder to implement DSL Do you need this?
  • 10. OOP can give you ● Batch common operations on pages/steps *** E.g. – Reporting per steps – abstract open() per page – abstract getExpectedElements() per page ● Obligations over conventions ● Certainty in future refactoring Do you need this?
  • 11. Sometimes... ● Batch/common operations may be redundant for pages/steps – Sufficient reporting can be implemented in low-level libraries – “batch” open() may be called on LoadableComponent separately – IHaveExpectedElements may give no advantages for smoke testing in your project ● And still can be implemented separately in e.g. LoadableComponent ● Or via Reflection – Some “common” implementation can be moved from pages to “widgets” and still be implemented with OOP
  • 12. Sometimes... ● Conventions can be very easy ● No severe refactoring is coming – Test Automation Project is not a NASA Space Shuttle ;).
  • 16. public class LoginClassicPageObject extends BasePage { @FindBy(css = "#login-form") private WebElement container; @FindBy(name = "username") private WebElement usernameField; @FindBy(name = "password") private WebElement passwordField; @FindBy(css = ".ui-button[value='Log in']") private WebElement loginButton; public void WebElement getContainer(){ return container; } @Override public void open(String baseurl) { driver.get(baseurl); } public void doLogin(String login, String pass){ usernameField.sendKeys(login); passwordField.sendKeys(pass); loginButton.click(); } public LoginClassicPageObject( WebDriver driver, String baseurl) { PageFactory.initElements(driver, this); this.driver = driver; this.baseurl = baseurl; } private String baseurl; private WebDriver driver; }
  • 18. public class LoginSelenidePageObject extends BasePage { private final String container = "#login-form"; private final By username = By.name("username"); private final By password = By.name("password"); private final String loginButton = ".ui-button[value='Log in']"; public void SelenideElement getContainer(){ return $(container); } @Override public void open(String baseurl) { open(baseurl); } public void doLogin(String login, String password){ $(username).setValue(login); $(password).sendKeys(password); $(loginButton).click(); } public LoginSelenidePageObject(String baseurl) { this.baseurl = baseurl; } private String baseurl; }
  • 19. public class LoginSelenidePageObject2 extends BasePage { public void SelenideElement сontainer(){ return $("#login-form");} public void SelenideElement usernameField(){ return $(By.name("username"));} public void SelenideElement passwordField(){ return $(By.name("password"));} public void SelenideElement loginButton(){ return $(".ui-button[value='Log in']");} @Override public void open(String baseurl) { open(baseurl); } public void doLogin(String login, String password){ usernameField().setValue(login); passwordField().setValue(password); loginButton.click(); } public LoginSelenidePageObject(String baseurl) { this.baseurl = baseurl; } private String baseurl; }
  • 21. PageUtils public class Login{ public static void open(String baseurl) { Selenide.open(baseurl); } public static SelenideElement container() { return $("#login-form");} public static SelenideElement usernameField(){ return $(By.name("username"));} public static SelenideElement passwordField(){ return $(By.name("password"));} public static SelenideElement loginButton(){ return $(".ui-button[value='Log in']");} public static void doLogin(String login, String password){ usernameField().setValue(login); passwordField().setValue(password); loginButton().click(); } } A l t e r n a t I v E
  • 22. Or... public class Login{ public static void open(String baseurl) { Selenide.open(baseurl); } public static final String container = "#login-form"; public static final By username = By.name("username"); public static final By password = By.name("password"); public static final String loginButton = ".ui-button[value='Log in']"; public static void doLogin(String login, String password){ $(username).setValue(login); $(password).sendKeys(password); $(loginButton).click(); } } A l t e r n a t I v E
  • 23. PageUtils usage Login.open(baseurl); Login.doLogin(username, password); Home.addProduct("Product_1"); UserPanel.doLogout(); Login.container().shouldBe(visible); PageObjects usage loginPage = new LoginPage(baseurl); loginPage.open(); loginPage.doLogin(username, password); homePage = new HomePage(); homePage.addProduct("Product_1"); homePage.doLogout(); loginPage.getContainer().shouldBe(visible); C o m p a r e
  • 24. Three Chords of “Procedural” PageUtils :)
  • 25. 1. Abstraction Factor out implementation details into helper methods doLogin(username, password); public static void doLogin(String login, String password){ usernameField().setValue(login); passwordField().setValue(password); loginButton().click(); } public static SelenideElement usernameField(){ return $(By.name("username")); }
  • 26. 2. Modularity Collect your helpers in classes of correspondent context
  • 27. 3. Try to Be “Functional” – write functions returning result only based on passed parameters – write smaller functions and use them in a 'chain': select(dropdownIn(userPanel()), “En”) – Instead of selectLanguageDropdownInUserPanel(“En”) – Use Composition over Inheritance
  • 28. P.S. Be smart ;) – You can't use inheritance. ● If you have any conventions you need to remember to follow them
  • 29. When Use? ● Need to involve and teach Manual/Junior Automation QA ● Need a fast solution ● Language support Functional Paradigm – At least first-class functions ● You know what you do:)
  • 30. When maybe not use? ● All committers to test framework are either Senior QA Automation or Developers ● No need to teach Manual QA/Juniors ● No tough deadlines ● Java (only)
  • 31. When not use? ● Your are Junior/Middle – And/Or Manager/Lead/Dev says: OOP or DIE! :) ● You can't predict what features your framework may need in future
  • 32. This is how your test model may look
  • 33. “What are those classes in pagegetters package?” :)
  • 34. Here come Loadable Components... public abstract class SimpleLoadableComponent { public void get() { try { isLoaded(); } catch (Error e) { load(); isLoaded(); } } protected abstract void load(); protected abstract void isLoaded() throws Error; }
  • 37. Technically To (new ProductTestTablesPage( new ProductPage( new HomePage( new LoginPage(baseurl), username, password), "Product_1"))).get();
  • 39. Selenium LoadableComponent public abstract class LoadableComponent<T extends LoadableComponent<T>> { @SuppressWarnings("unchecked") public T get() { try { isLoaded(); return (T) this; } catch (Error e) { load(); } isLoaded(); return (T) this; } protected abstract void load(); protected abstract void isLoaded() throws Error; }
  • 40. Ajax? > Selenium SlowLoadableComponent Calm down, no code, just link:) ● (c) A LoadableComponent which might not have finished loading when load() returns. After a call to load(), the isLoaded() method should continue to fail until the component has fully loaded.
  • 41. Once you need some abstract classes to DRY your code... public abstract class AbstractPage<T extends SlowLoadableComponent<T>> extends SlowLoadableComponent<T>{ O_O
  • 43. 'url-based' isLoaded implementation protected void isLoaded() throws Error { String url = driver.getCurrentUrl(); assertTrue(url.contains(pageUrl)); }
  • 44. If you want to identify pages by actual content protected void isLoaded() throws Error { try { WebElement div = driver.findElement(By.id("login-select")); } catch (NoSuchElementException e) { fail("Cannot locate user name link"); } }
  • 45. Once you use @FindBy public void isLoaded() throws Error { if (loginButton != null) { assertElementIsDisplayed(loginButton); } else { fail("Login button is not loaded"); } }
  • 46. Typical Selenide isLoaded() implementation public void isLoaded(){ Login.container().shouldBe(visible); }
  • 47. Selenide LoadableComponent public abstract class SelenideLoadableComponent { public void get() { long originalTimeout = Configuration.timeout; try { Configuration.timeout = 0; isLoaded(); Configuration.timeout = originalTimeout; } catch (Error e) { Configuration.timeout = originalTimeout; load(); isLoaded(); } } protected abstract void load(); protected abstract void isLoaded(); } “slow”, ajax-friendly by default “no” <T extends Madness>
  • 48. If you wish... public abstract class AbstractPage extends SelenideLoadableComponent { public abstract void isLoaded(); } Home.page().get(); doCrazyStuff(); Home.page().isLoaded() // still?
  • 50. Initialize public class ProductPage extends SelenideLoadablePage{ private HomePage parent; protected String productName; public ProductPage(HomePage parent, String productName){ this.parent = parent; this.productName = productName; } ….
  • 51. Load protected void load() { parent.get(); Home.ensureHasProduct(productName); Product.open(productName); }
  • 52. isLoaded() public void isLoaded() { Breadcrumb.productLink(productName).shouldBe(visible); Product.testTableItem().shouldBe(visible); }
  • 53. Factory public class Product { public static ProductPage page(String productName){ return new ProductPage(Home.page(), productName); } … }
  • 54. If it would be so “simple”...
  • 55. But it would not :p public class AuthorizedPage extends AbstractPage { protected AbstractPage parent; private String username; private String password; public AuthorizedPage( LoginPage parent, String username, String password) { this.parent = parent; this.username = username; this.password = password; } public AuthorizedPage(AuthorizedPage parent){ this.parent = parent; } ...
  • 56. Initialize public class ProductPage extends AuthorizedPage{ protected String productName; public ProductPage(HomePage parent, String productName){ super(parent); this.productName = productName; } public ProductPage(ProductPage parent){ //It's possible to “load” page from itself super(parent); this.productName = parent.getProductName(); } ….
  • 57. Load protected void load() { parent.get(); if (parent instanceof ProductPage) { Breadcrumb.productLink(((ProductPage) parent).getProductName()).click(); } else { //parent instanceof HomePage Home.ensureHasProduct(productName); Product.open(productName); } }
  • 58. Though... The beast is not so scary after you write up to 10 first Lions Components :)
  • 59. And You still can live only with PageUtils and keep LoadableComponents as options to be implemented by crazy devs:) QA Dev
  • 60. scenario "Surf Pages", { where "Page is #page", { page = [ Login.page(), Home.page(), Settings.page(), Login.page(Authorized.page()), Product.page(TEST_PRODUCT), Login.page(Authorized.page()), Settings.page(), Product.page(Home.page(Settings.page()), "Product_1"), Product.page(Product.page(TEST_PRODUCT)), ProductTestTables.page(TEST_PRODUCT), Login.page(Authorized.page())] } then "go to #page", { page.get() } } Bonus :)
  • 61. When Maybe Use? ● No confident urls ● Complex “deep” page hierarchy ● Authorization > Menus > SubMenus > Tabs > Extra > Extra...
  • 62. When Use? ● Desired dependent End to End scenarios with “walking through pages” feature – emulating real user experience – big amount of such test cases
  • 63. When maybe not use? ● Too many ways to load the same page ● Though you still can implement LC for 1 way, if you need to use it often. ● Too many pages, especially “visible” at the same time
  • 64. When not use? ● URL-based loading is enough – Or work around via custom JS load helpers is enough ● what is true for most cases... ● Have no “deep” pages
  • 66. ● PageUtils: class Login – Page smart loader: Login.page().get() – Page root html element: Login.container() – Method to open Page once preconditions satisfied: Login.open() – Page elements: Login.signInButton() – Page business steps: Login.doLogin(“guest”, “1234”) ● LoadableComponent: class LoginPage isLoaded() load() Conventions
  • 67. Ideas to think about
  • 68. LoadableComponent ● Is not PageObject – Though you can integrate it into PageObject, violating Single Responsibility principle ● It's an object incapsulating page loading logic. – Initializing the “loading way” through LC constructor ● It's possible also to move logic into separate loadable components fro each “way”, though this may lead to overcomplicated hierarchy – choosing the “way” in load() implementation – And then just get() your page
  • 69. LoadableComponent Integration ● PageUtils + LoadableComponent – Two classes instead of one ● PageObject + LoadableComponent – May be harder to achieve friendly tests code ● PageObject extends LoadableComponent – Bulky – Harder to explain to juniors/interns – Violates Single Responsibility Principle
  • 70. LoadableComponent Factory Too more calls to page() ? Use Singleton Pattern
  • 71. PageUtils Page elements as functions public static SelenideElement usernameField(){ return $(By.name("username")); } … Login.usernameField().setVal("guest"); Page elements as locators public static final By usernameField = By.name("username"); … $(Login.usernameField).setVal("guest"); C o m p a r e
  • 72. Functional “Scales” ● Main cons of Procedural approach is that it may be not DRY ● In most cases you can fix this with high-order functions in much more concise way than with OOP – Though less obvious for non-FP user
  • 73. Ideas for improvements ● Use Groovy as main language – in order to simplify implementation. – Finally Java is the OOP language ● and not adapted for both procedural and functional styles. – In Groovy OOP may be not “bulky” ● and with some functional & metaprogramming features you can achieve the same level of simplicity still powerful – and easy to explain to juniors “how to use” (though not “how to understand details”)
  • 74. Did it work for Manual QA?
  • 75. Demo
  • 76. Q&A
  • 77. Resources, Links ● Src of example test framework: https://github.com/yashaka/gribletest ● Programming Paradigms Comparison: https://bitbucket.com/yashaka/oopbucket/src ● Functional Thinking articles: http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=fun ● Application under test used in easyb examples: http://grible.org/download.php ● Instruments – http://selenide.org/ – http://code.google.com/p/selenium/wiki/LoadableComponent
  • 78. ● To Artem Chernysh for implementation of main base part of the test framework for this presentation – https://github.com/elaides/gribletest ● To Maksym Barvinskyi for application under test – http://grible.org/
  • 79. Contacts ● yashaka@gmail.com ● skype: yashaolin ● twitter: @yashaka ● http://www.linkedin.com/in/iakivkramarenko