© 2016 The Future Group - http://bit.ly/2eDaWio
Improving Your Selenium WebDriver
Tests
Roy de KleijnTechnical Test ConsultantEmail: [email protected]: @TheWebTesterWebsite: http://www.rdekleijn.nlGithub: https://github.com/roydekleijn
© 2016 The Future Group - http://bit.ly/2eDaWio
Question #1
What makes your Selenium WebDriver tests suck?
© 2016 The Future Group - http://bit.ly/2eDaWio
Answer #1
Depending on third-party data
Synchronization issues
Cross-browser issues
Hard to locate elements
testdata
Slow feedback cycle
Flaky tests
High maintenance costs
© 2016 The Future Group - http://bit.ly/2eDaWio
Lack of confidence
Results in …
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Maintenance testM
aint
enan
ce e
ffort
Time
Start
with re
cord an
d playbac
k
Convert
recorded te
sts in
to code
Awesome, it
works
! Let’s
create
more UI te
sts Reality: code ends up into unmaintainable spaghetti
Design patt
erns applie
d
Implement fe
atures t
o mak
e tests
robust
wish
© 2016 The Future Group - http://bit.ly/2eDaWio
Testing Pyramid
unit
UI
API
feed
back
-cyc
le
- Extremely fast- Smallest units of the application / isolates failure- Executed during build time- No dependency on data
- Extremely slow- Requires running application- Will change frequently- Dependency on data
- Fast- Covering boundary conditions- Start early in SD process - Requires running application- (some) dependency on data
© 2016 The Future Group - http://bit.ly/2eDaWio
Mock External Interfaces
application
Interface 1
Interface 2
Interface 3
application
Interface 1
Interface 2
Interface 3m
ock
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Question #2
What is wrong with these locators?
#1.//*[@id='wx-header-wrap']/div/div/div/div[2]/div[2]/div/section/div/form/input
#2.//*[@id='gnav-header-inner']/div/ul/li[2]/a
© 2016 The Future Group - http://bit.ly/2eDaWio
Answer #2
They contain too much information about the location
© 2016 The Future Group - http://bit.ly/2eDaWio
Closer look #1
© 2016 The Future Group - http://bit.ly/2eDaWio
Closer look #1.//*[@id='wx-header-wrap']/div/div/div/div[2]/div[2]/div/section/div/form/input
What if the location of this element will change over time?
It can be written like this: input[class = ‘input--search’]Orinput.input—searchOrinput[name = ‘search’]
© 2016 The Future Group - http://bit.ly/2eDaWio
Closer look #2
© 2016 The Future Group - http://bit.ly/2eDaWio
Closer look #2.//*[@id='gnav-header-inner']/div/ul/li[2]/a
What if the order of the links will change over time ?
It can be written like this: a[id=register]Ora#register
© 2016 The Future Group - http://bit.ly/2eDaWio
Attribute selectorscss xpath
Equals e[a=v] //e[@a=v]
Contains e[a*=v] //e[contains(@a, ‘v’)]
Starts-with e[a^=v] //e[starts-with(@a, ‘v’)]
Ends-with e[a$=v] //e[ends-with(@a, ‘v’)]
© 2016 The Future Group - http://bit.ly/2eDaWio
Tip: only use Xpath…
If you need to walk up the DOM
Demofile://localhost/Users/roydekleijn/Documents/whenXpath.html
© 2016 The Future Group - http://bit.ly/2eDaWio
AngularJS - elements
• Different way of locating elements• Binding• Model• Repeat
• ngWebDriver library (create by Paul Hammant)• https://github.com/paul-hammant/ngWebDriver• Logic from Protractor project
© 2016 The Future Group - http://bit.ly/2eDaWio
• Enable debug info• Call angular.reloadWithDebugInfo(); in your browser debug
console
• Execute the following snippet to reveal all the elements:
§
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Speed-up and stabilize your tests Windows 7
IEFF
Chrome
Windows vistaIEFF
UbuntuFF
Opera
Mac OSFF
ChromeOpera
…
Nodes
Hub
Specification
HUB
Test Scripts
© 2016 The Future Group - http://bit.ly/2eDaWio
Docker Selenium
• Disposable Selenium Grid (in seconds)• Autoscaling features
• https://hub.docker.com/r/selenium/
© 2016 The Future Group - http://bit.ly/2eDaWio
Docker-composeseleniumhub: image: selenium/hub ports: - 4444:4444firefoxnode: image: selenium/node-firefox environment: SCREEN_WIDTH: 2880 SCREEN_HEIGHT: 1800 ports: - 5900 links: - seleniumhub:hub
chromenode: image: selenium/node-chrome environment: SCREEN_WIDTH: 2880 SCREEN_HEIGHT: 1800 ports: - 5900 links: - seleniumhub:hub
© 2016 The Future Group - http://bit.ly/2eDaWio
Docker commands
Start containers:docker-compose up –d
-d: Run containers in the background--force-recreate: Recreate containers entirely
IP of docker engine:docker-machine ip
Autoscaling:docker-compose scale firefoxnode=5 chromenode=1
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Problems that arise
• Unmaintainable• Unreadable test scripts• Creation of test scripts is time consuming• Code duplication
© 2016 The Future Group - http://bit.ly/2eDaWio
From problem to solution
© 2016 The Future Group - http://bit.ly/2eDaWio
Solution
Each page contains only a part of the total functionality available on the website
Put page specific functionality in a class with a corresponding name
© 2016 The Future Group - http://bit.ly/2eDaWio
Step-by-step plan
1. Identify necessary WebElements2. Create a class3. Define WebElements in corresponding classes4. Model the functionality of a page into methods5. Model the page flow by setting returntypes
© 2016 The Future Group - http://bit.ly/2eDaWio
Identify necessary WebElements
© 2016 The Future Group - http://bit.ly/2eDaWio
Create a class
A class with the name of the page extending from LoadableComponent
public class HomePage extends LoadableComponent<HomePage> { private WebDriver driver;
public HomePage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
© 2016 The Future Group - http://bit.ly/2eDaWio
Define WebElementsOn class level (above the methods)
@FindBy(css = "a.login")
private WebElement loginLink;
© 2016 The Future Group - http://bit.ly/2eDaWio
Model the functionality
public LoginPage clickOnLoginLink() { loginLink.click(); return new LoginPage(driver); }
© 2016 The Future Group - http://bit.ly/2eDaWio
Model the page flow
• Prerequisite:• Multiple pages are modelled
• Modify returntype• The returntype is the name of the page (class) where you are navigating
towards• Use the current class name, if you stay on the same page
© 2016 The Future Group - http://bit.ly/2eDaWio
Model the page flow
public LoginPage clickOnLoginLink() { loginLink.click(); return new LoginPage(driver); }
Returning page
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Data Objects final CustomerAccount account = new CustomerAccount.CustomerAccountBuilder("[email protected]","1qazxsw2").build();
Access data:account.getEmail()
account.getPassword()
© 2016 The Future Group - http://bit.ly/2eDaWio
Data Objects - Complex final Order order = new Order.OrderBuilder()//
.withInvoiceAddress(new Address.AddressBuilder("abc street", "1234ab").build())// .withShippingAddress(new Address.AddressBuilder("shipstreet”, "4321ab").withCountry("The Netherlands").build())//
.build();
// Retrieve data from the objectSystem.out.println(order.getInvoiceAddress().getStreet());
System.out.println(order.getShippingAddress().getCountry());
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Synchronization issues
• Browser has to start• Page has to load• AJAX request need to be finished• Or, loader should be gone before we can continue
© 2016 The Future Group - http://bit.ly/2eDaWio
What NOT to do …
NEVER, use Thread.sleep();
• It will probably make your test unnecessary slow• You never know if you wait exactly long enough
© 2016 The Future Group - http://bit.ly/2eDaWio
What to do…• WebDriver build in wait mechanisms• implicitlyWait: poll till element is present
• Is not inline with fail-fast principle• setScriptTimeout: time to wait for an asynchronous script to finish• pageLoadTimeout: time to wait for a page load to complete
• ngWebDriver• waitForAngularRequestsToFinish – wait for outstanding angular requests
• Custom (gist)• checkPendingRequests – wait for all HTTP requests to be finished
© 2016 The Future Group - http://bit.ly/2eDaWio
Example 1
Wait for element to be clickable
@Testpublic void waitForElementToBeClickable() {
new WebDriverWait(driver, 20,100) //.until(ExpectedConditions.elementToBeClickable(
By.cssSelector("a.login")));}
© 2016 The Future Group - http://bit.ly/2eDaWio
Example 2
Wait for loader to be invisible
@Testpublic void waitForElementNotToBeVisable() {
new WebDriverWait(driver, 20, 100) //.until(ExpectedConditions.invisibilityOfElementLocated(
By.cssSelector("loader")));}
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
Play with ObjectsDownload sources from: https://github.com/roydekleijn/webdriver-workshop Or
http://bit.ly/2eDaWio
Website under test: http://demo.rdekleijn.nl
- Create Register test (model is in place)- Implement Search test (model not in place)- Implement Order test (if there is time left..)
© 2016 The Future Group - http://bit.ly/2eDaWio
Contents19:00 - 20:00 Part 1
• Introduction• Element locator tips & tricks• Speed-up and stabilize your tests (demo)• Implementing the Page Object Model• Utilize Data Objects
20:00 - 20:15 Coffee 20:15 - 21:15 Part 2
• Handle synchronization• Play with objects• What we have learned
We will start with an actual Page Object Model implementation today
© 2016 The Future Group - http://bit.ly/2eDaWio
What we have learned today
Depending on third-party data
Cross-browser issues
Hard to locate elements
testdata
Slow feedback cycle
Flaky tests
High maintenance costs
Synchronization issuesAvoid Thread.sleep() or other hardcoded
waits
Utilize Page Object Model
id > name > css > xpath > angular
Mock interfaces
Run tests in parallel
Mock interfaces
Mock interfaces, setup clean environments,
implement page object model
© 2016 The Future Group - http://bit.ly/2eDaWio
Thank you…
Roy de KleijnTechnical Test ConsultantEmail: [email protected]: @TheWebTesterWebsite: http://www.rdekleijn.nlGithub: https://github.com/roydekleijn