SlideShare a Scribd company logo
1 of 54
Download to read offline
Geb Best Practices
Marcin Erdmann
@marcinerdmann
•  Groovy enthusiast since 2010
•  Geb user since 2011
•  Geb lead since 2014
•  Open source contributor
•  Testing junkie
1.0!!!
08.10.2016
50 Geb contributors
•  Robert Fletcher
•  Peter Niederwieser
•  Alexander Zolotov
•  Christoph Neuroth
•  Antony Jones
•  Jan-Hendrik Peters
•  Tomás Lin
•  Jason Cahoon
•  Tomasz Kalkosiński
•  Rich Douglas Evans
•  Ian Durkan
•  Colin Harrington
•  Bob Herrmann
•  George T Walters II
•  Craig Atkinson
•  Andy Duncan
•  John Engelman
•  Michael Legart
•  Graeme Rocher
•  Craig Atkinson
•  Ken Geis
•  Chris Prior
•  Kelly Robinson
•  Todd Gerspacher
•  David M. Carr
•  Tom Dunstan
•  Brian Kotek
•  David W Millar
•  Ai-Lin Liou
•  Varun Menon
•  Anders D. Johnson
•  Hiroyuki Ohnaka
•  Erik Pragt
•  Vijay Bolleypally
•  Pierre Hilt
•  Yotaro Takahashi
•  Jochen Berger
•  Matan Katz
•  Victor Parmar
•  Berardino la Torre
•  Markus Schlichting
•  Andrey Hitrin
•  Leo Fedorov
•  Chris Byrneham
•  Aseem Bansal
•  Tomasz Przybysz
•  Brian Stewart
•  Jacob Aae Mikkelsen
•  Patrick Radtke
•  Leonard Brünings
Breaking changes in 1.0
•  Methods like isDisplayed() and
text() throw an exception when called
on multi element navigators
•  Weakly typed module() and
moduleList() removed
•  isDisabled() and isReadOnly()
removed from Navigator
Heresy warning...
Advanced usage
a.k.a. Tips & Tricks
Module is-a Navigator
•  Modules wrap around their base
Navigator
•  All Navigator methods can be called on
Module instances
•  Navigator methods can be used in
module implementations
Module is-a Navigator
<html>
<form method="post" action="login">
...
</from>
</html>
class LoginFormModule extends Module {
static base = { $("form") }
}

class LoginPage extends Page {
static content = {
form { module LoginFormModule }
}
}
Module is-a Navigator
to LoginPage
assert form.@method == "post”
assert form.displayed
Overriding value() on module
Class DatepickerModule extends Module {
LocalDate value() {
...
}

Navigator value(LocalDate date) {
...
}
}

class DatepickerPage extends Page {
static content = {
date { module DatepickerModule }
}
}
Overriding value() on module
to DatepickerPage
date.value(LocalDate.of(2017, 4, 1))
assert date.value() == LocalDate.of(2017, 4, 1)
to DatepickerPage
date = LocalDate.of(2017, 4, 1) 
assert date == LocalDate.of(2017, 4, 1)
Advanced navigation and types
•  Page.convertToPath(Object[]) is
used to translate arguments passed to
Browser.to() into a path
•  Consider overloading convertToPath()
for more expressive navigation
Advanced navigation and types
class PostPage extends Page {
static url = “posts”

String convertToPath(Post post) {
“${post.id}/${post.title.toLowerCase().replaceAll(“ ”, “-”)}”
}
}

def post = new Post(id: 1, title: “My first post”)

to PostPage, post
assert title == post.title
Parameterised pages
•  Pages can be instantiated and passed to
via(), to() and at()
•  Useful when you need to differ
implementation based on the object
represented by the page
Parameterised pages navigation
class PostPage extends Page {
Post post

String getPageUrl() {
“posts/${post.id}/${post.title.toLowerCase().replaceAll(“ ”, “-”)}”
}
}

def post = new Post(id: 1, title: “My first post”)

to(new PostPage(post: post))
assert title == post.title
Navigators are iterable
•  Navigators are backed by a collection of
WebElements
•  Navigators implement
Iterable<Navigator>
Navigators are iterable
<html>
<p>First paragraph</p>
<p>Second paragraph</p>
</html>
$(“p”).text() // throws exception
$(“p”)[0].text() // returns “First paragraph”
$(“p”)*.text() // returns [“First paragraph”, “Second paragraph”]

//returns [0: “First paragraph”, 1: “Second paragraph”]
$(“p”).withIndex().collectEntries { [(it.second): it.first.text()] }
What’s onLoad() for?
class CookieBarPage extends Page {
boolean autoCloseCookieBar = true
static content = {
cookieBar { module(CookieBarModule) }
}
void onLoad(Page previousPage) {
if (autoCloseCookieBar && cookieBar) {
cookieBar.close()
}
}

}
Injecting javascript into page
js.exec '''
var url = 'https://code.jquery.com/jquery-3.2.1.min.js';

var scriptElement = document.createElement('script');
scriptElement.setAttribute('src', url);
document.head.appendChild(scriptElement);
'''
Navigator’s elements in js
void waitForCssTransition(Navigator navigator, WaitingSupport waiting, JavascriptInterface js,
Closure trigger) {
js.exec(navigator.singleElement(), '''
var o = jQuery(arguments[0]);
window.setTransitionFinishedClass = function() {
$(this).addClass('transitionFinished');
}
o.bind('transitionend', window.setTransitionFinishedClass);
''')
try {
trigger.call()
waiting.waitFor { hasClass('transitionFinished') }
} finally {
js.exec(navigator.singleElement, '''
var o = jQuery(arguments[0]);
o.unbind('transitionend', window.setTransitionFinishedClass);
o.removeClass('transitionFinished')
window.setTransitionFinishedClass = undefined;
''')
}
}
Alternatives to inheritance
•  Using inheritance for code sharing leads to
complex inheritance structures
•  @Delegate can be used for code sharing
via delegation
•  Traits can be used for code sharing
Alternatives to inheritance
class TransitionSupport {
private final Navigator navigator
private final WaitingSupport waiting
private final JavascriptInterface js

TransitionSupport(Navigator navigator, WaitingSupport waiting, JavascriptInterface js) {
...
}
void waitForCssTransition(Closure trigger) {
...
}
}

class TransitioningModule extends Module {
@Delegate
TransitionSupport transitionSupport = new TransitionSupport(this, this, js)
}
Alternatives to inheritance
trait TransitionSupport implements Navigator, WaitingSupport {
abstract JavascriptInterface getJs()

void waitForCssTransition(Closure trigger) {
...
}
}

class TransitioningModule extends Module implements TransitionSupport {
}
Dynamic base url
class RatpackApplicationGebSpec extends GebSpec {

def application = new GroovyRatpackMainApplicationUnderTest()
def setup() {
browser.baseUrl = application.address.toString()
}

}
Testing responsive apps
class TestsMobileViewExtension extends 
AbstractAnnotationDrivenExtension<TestsMobileView> {
void visitFeatureAnnotation(TestsMobileView annotation, FeatureInfo feature) {
feature.addInterceptor { invocation ->
def window = new ConfigurationLoader().conf.driver.manage().window()
def originalSize = window.size
try {
window.size = new Dimension(320, 568)
invocation.proceed()
} finally {
window.size = originalSize
}
}
}
}
Best practices
a.k.a. Marcin’s musings
Strongly typed Geb code
•  Better authoring, i.e. autocompletion
•  Better navigation, i.e. going to method
definition, finding usages
•  Refactoring support
What IntelliJ understands?
•  Delegation to Browser methods in specs
•  Delegation to Page methods in specs
•  Content definitions
Tracking current page type
•  Capture current page in a variable
•  Use return values of via(), to() and
at()
•  Return new page instance from methods
triggering page transitions
Tracking current page
def homePage = to HomePage

homePage.loginPageLink.click()
def loginPage = at LoginPage

def securePage = loginPage.login("user", "password")
Tracking current page
to(HomePage).loginPageLink.click()

def securePage = at(LoginPage).login("user", "password")
At checks
•  Keep them quick and simple
•  Check if you are at the right page
•  Don’t test any page logic
What’s missing here?
class CookieBarPage extends Page {
boolean autoCloseCookieBar = true
static content = {
cookieBar { $('.cookie-message’) }
cookieBarText { $('.cookie-message-text').text() }
cookieBarCloseButton { $('.cookie-message-button > input') }
}

}
What are modules good for?
•  More than reuse
•  Modeling logical components
•  Hiding component structure from tests
•  Hiding complex interactions from tests
Invest time in fixture builders
•  Aim for easy, expressive and flexible data
setup
•  Keep data setup close to tests
•  Setup only the data necessary for the test
•  Groovy Remote Control can be very helpful
•  Fixtures are not not only about data
Geb’s test harness html fixture
def “can access element classes”() {
given:
html {
div(id: "a", 'class': "a1 a2 a3")
div(id: "b", 'class': "b1”)
}

expect:
$("#a").classes() == ["a1", "a2", "a3"]
$("#b").classes() == ["b1”]
}
Example data fixture DSL
bootstrapper.post {
id = “69f10bb6-118e-11e7-93ae-92361f002671”
title = “My first post”
tags = [“Groovy”, “Geb”]
author {
firstName = “Marcin”
lastName = “Erdmann”
}
}
Use real browser in CI
•  Available headless drivers are either
limited, not developed anymore or not
properly tested
•  Use a real browser with a virtual frame
buffer, i.e. Xvfb
•  Use a cloud browser provider
reportOnTestFailuresOnly
To waitFor() or
not?
To waitFor() or not?
•  Ask yourself if action is asynchronous
•  Watch out for quick asynchronous events
waitFor() considered harmful
•  Best not used directly in tests
•  Hide asynchronous behaviour in action
methods on modules and pages
Increasing the
timeout is
(usually) not the
answer
Use wait presets
Browser test are costly!
•  Slow, hard to maintain and flakey
•  Mind what you test at such high level
•  ...but they provide a lot of confidence
Cross browser
tests are costlier
Cloud browser providers
•  Gradle plugins for driving browsers with
Geb in BrowserStack and Suace Labs
•  Can test applications via a tunnel which are
not available on the Internet
Using attributes map selectors
•  Map selectors are now translated to CSS
attribute selectors
•  As quick as using css selectors but reads
better especially when using dynamic
values
Using attributes map selectors
$(‘button’, type: ‘select’)
$(‘button[type=“select”]’)

$(itemtype: ‘http://schema.org/Person’)
$(‘[itemtype=“http://schema.org/Person”]’)
Selecting by text is slow!
•  Selecting by text is a Geb extension not
something that CSS supports
•  Narrow down selected elements as much
as possible when selecting by text
Questions?
Thank you!

More Related Content

What's hot

Red Hat OpenShift V3 Overview and Deep Dive
Red Hat OpenShift V3 Overview and Deep DiveRed Hat OpenShift V3 Overview and Deep Dive
Red Hat OpenShift V3 Overview and Deep Dive
Greg Hoelzer
 
Redhat training &certification
Redhat training &certificationRedhat training &certification
Redhat training &certification
Ahmed Abbas Ahmed
 

What's hot (20)

Red Hat OpenShift V3 Overview and Deep Dive
Red Hat OpenShift V3 Overview and Deep DiveRed Hat OpenShift V3 Overview and Deep Dive
Red Hat OpenShift V3 Overview and Deep Dive
 
Kubernetes and Prometheus
Kubernetes and PrometheusKubernetes and Prometheus
Kubernetes and Prometheus
 
Flusso Continuous Integration & Continuous Delivery
Flusso Continuous Integration & Continuous DeliveryFlusso Continuous Integration & Continuous Delivery
Flusso Continuous Integration & Continuous Delivery
 
Finally, easy integration testing with Testcontainers
Finally, easy integration testing with TestcontainersFinally, easy integration testing with Testcontainers
Finally, easy integration testing with Testcontainers
 
Intro to vue.js
Intro to vue.jsIntro to vue.js
Intro to vue.js
 
KubeCon + CloudNative Con NA 2021 | A New Generation of NATS
KubeCon + CloudNative Con NA 2021 | A New Generation of NATSKubeCon + CloudNative Con NA 2021 | A New Generation of NATS
KubeCon + CloudNative Con NA 2021 | A New Generation of NATS
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
 
Docker introduction
Docker introductionDocker introduction
Docker introduction
 
DevOps avec Ansible et Docker
DevOps avec Ansible et DockerDevOps avec Ansible et Docker
DevOps avec Ansible et Docker
 
Realtime vs Cloud Firestore
Realtime vs Cloud Firestore Realtime vs Cloud Firestore
Realtime vs Cloud Firestore
 
Protecting Apps from Hacks in Kubernetes with NGINX
Protecting Apps from Hacks in Kubernetes with NGINXProtecting Apps from Hacks in Kubernetes with NGINX
Protecting Apps from Hacks in Kubernetes with NGINX
 
Introduction to docker
Introduction to dockerIntroduction to docker
Introduction to docker
 
NServiceBus
NServiceBusNServiceBus
NServiceBus
 
MySQL operator for_kubernetes
MySQL operator for_kubernetesMySQL operator for_kubernetes
MySQL operator for_kubernetes
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation Tool
 
Small, Simple, and Secure: Alpine Linux under the Microscope
Small, Simple, and Secure: Alpine Linux under the MicroscopeSmall, Simple, and Secure: Alpine Linux under the Microscope
Small, Simple, and Secure: Alpine Linux under the Microscope
 
Karate, the black belt of HTTP API testing?
Karate, the black belt of HTTP API testing?Karate, the black belt of HTTP API testing?
Karate, the black belt of HTTP API testing?
 
Kubernetes networking in AWS
Kubernetes networking in AWSKubernetes networking in AWS
Kubernetes networking in AWS
 
Redhat training &certification
Redhat training &certificationRedhat training &certification
Redhat training &certification
 
Cloud Native Networking & Security with Cilium & eBPF
Cloud Native Networking & Security with Cilium & eBPFCloud Native Networking & Security with Cilium & eBPF
Cloud Native Networking & Security with Cilium & eBPF
 

Similar to Geb Best Practices

Building Single-Page Web Appplications in dart - Devoxx France 2013
Building Single-Page Web Appplications in dart - Devoxx France 2013Building Single-Page Web Appplications in dart - Devoxx France 2013
Building Single-Page Web Appplications in dart - Devoxx France 2013
yohanbeschi
 
Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...
Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...
Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...
mfrancis
 

Similar to Geb Best Practices (20)

jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
Building Single-Page Web Appplications in dart - Devoxx France 2013
Building Single-Page Web Appplications in dart - Devoxx France 2013Building Single-Page Web Appplications in dart - Devoxx France 2013
Building Single-Page Web Appplications in dart - Devoxx France 2013
 
Whats new in MongoDB 24
Whats new in MongoDB 24Whats new in MongoDB 24
Whats new in MongoDB 24
 
Architecture Components In Real Life Season 2
Architecture Components In Real Life Season 2Architecture Components In Real Life Season 2
Architecture Components In Real Life Season 2
 
Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...
Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...
Modularity and Domain Driven Design - A killer combination - T De Wolf & S va...
 
MicroProfile: A Quest for a Lightweight and Modern Enterprise Java Platform
MicroProfile: A Quest for a Lightweight and Modern Enterprise Java PlatformMicroProfile: A Quest for a Lightweight and Modern Enterprise Java Platform
MicroProfile: A Quest for a Lightweight and Modern Enterprise Java Platform
 
Examiness hints and tips from the trenches
Examiness hints and tips from the trenchesExaminess hints and tips from the trenches
Examiness hints and tips from the trenches
 
Red Hat JBoss BRMS and BPMS Workbench and Rich Client Technology
Red Hat JBoss BRMS and BPMS Workbench and Rich Client TechnologyRed Hat JBoss BRMS and BPMS Workbench and Rich Client Technology
Red Hat JBoss BRMS and BPMS Workbench and Rich Client Technology
 
Modularity and Domain Driven Design; a killer combination?
Modularity and Domain Driven Design; a killer combination?Modularity and Domain Driven Design; a killer combination?
Modularity and Domain Driven Design; a killer combination?
 
5 x HTML5 worth using in APEX (5)
5 x HTML5 worth using in APEX (5)5 x HTML5 worth using in APEX (5)
5 x HTML5 worth using in APEX (5)
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017
 
node-crate: node.js and big data
 node-crate: node.js and big data node-crate: node.js and big data
node-crate: node.js and big data
 
CouchDB for Web Applications - Erlang Factory London 2009
CouchDB for Web Applications - Erlang Factory London 2009CouchDB for Web Applications - Erlang Factory London 2009
CouchDB for Web Applications - Erlang Factory London 2009
 
DSL's with Groovy
DSL's with GroovyDSL's with Groovy
DSL's with Groovy
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
 
Advanced guide to develop ajax applications using dojo
Advanced guide to develop ajax applications using dojoAdvanced guide to develop ajax applications using dojo
Advanced guide to develop ajax applications using dojo
 
Digital Publishing for Scale: The Economist and Go
Digital Publishing for Scale: The Economist and GoDigital Publishing for Scale: The Economist and Go
Digital Publishing for Scale: The Economist and Go
 
Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)
 

Recently uploaded

+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
Health
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
jaanualu31
 
Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
Neometrix_Engineering_Pvt_Ltd
 
DeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakesDeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakes
MayuraD1
 
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Kandungan 087776558899
 

Recently uploaded (20)

+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
 
Hostel management system project report..pdf
Hostel management system project report..pdfHostel management system project report..pdf
Hostel management system project report..pdf
 
Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
 
DeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakesDeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakes
 
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
 
Thermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptThermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.ppt
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
 
Design For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the startDesign For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the start
 
Bridge Jacking Design Sample Calculation.pptx
Bridge Jacking Design Sample Calculation.pptxBridge Jacking Design Sample Calculation.pptx
Bridge Jacking Design Sample Calculation.pptx
 
Rums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdfRums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdf
 
Work-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptxWork-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptx
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
 
Computer Lecture 01.pptxIntroduction to Computers
Computer Lecture 01.pptxIntroduction to ComputersComputer Lecture 01.pptxIntroduction to Computers
Computer Lecture 01.pptxIntroduction to Computers
 
School management system project Report.pdf
School management system project Report.pdfSchool management system project Report.pdf
School management system project Report.pdf
 
kiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal loadkiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal load
 
AIRCANVAS[1].pdf mini project for btech students
AIRCANVAS[1].pdf mini project for btech studentsAIRCANVAS[1].pdf mini project for btech students
AIRCANVAS[1].pdf mini project for btech students
 
Introduction to Serverless with AWS Lambda
Introduction to Serverless with AWS LambdaIntroduction to Serverless with AWS Lambda
Introduction to Serverless with AWS Lambda
 
Minimum and Maximum Modes of microprocessor 8086
Minimum and Maximum Modes of microprocessor 8086Minimum and Maximum Modes of microprocessor 8086
Minimum and Maximum Modes of microprocessor 8086
 

Geb Best Practices

  • 2. @marcinerdmann •  Groovy enthusiast since 2010 •  Geb user since 2011 •  Geb lead since 2014 •  Open source contributor •  Testing junkie
  • 3.
  • 5. 50 Geb contributors •  Robert Fletcher •  Peter Niederwieser •  Alexander Zolotov •  Christoph Neuroth •  Antony Jones •  Jan-Hendrik Peters •  Tomás Lin •  Jason Cahoon •  Tomasz Kalkosiński •  Rich Douglas Evans •  Ian Durkan •  Colin Harrington •  Bob Herrmann •  George T Walters II •  Craig Atkinson •  Andy Duncan •  John Engelman •  Michael Legart •  Graeme Rocher •  Craig Atkinson •  Ken Geis •  Chris Prior •  Kelly Robinson •  Todd Gerspacher •  David M. Carr •  Tom Dunstan •  Brian Kotek •  David W Millar •  Ai-Lin Liou •  Varun Menon •  Anders D. Johnson •  Hiroyuki Ohnaka •  Erik Pragt •  Vijay Bolleypally •  Pierre Hilt •  Yotaro Takahashi •  Jochen Berger •  Matan Katz •  Victor Parmar •  Berardino la Torre •  Markus Schlichting •  Andrey Hitrin •  Leo Fedorov •  Chris Byrneham •  Aseem Bansal •  Tomasz Przybysz •  Brian Stewart •  Jacob Aae Mikkelsen •  Patrick Radtke •  Leonard Brünings
  • 6. Breaking changes in 1.0 •  Methods like isDisplayed() and text() throw an exception when called on multi element navigators •  Weakly typed module() and moduleList() removed •  isDisabled() and isReadOnly() removed from Navigator
  • 9. Module is-a Navigator •  Modules wrap around their base Navigator •  All Navigator methods can be called on Module instances •  Navigator methods can be used in module implementations
  • 10. Module is-a Navigator <html> <form method="post" action="login"> ... </from> </html> class LoginFormModule extends Module { static base = { $("form") } } class LoginPage extends Page { static content = { form { module LoginFormModule } } }
  • 11. Module is-a Navigator to LoginPage assert form.@method == "post” assert form.displayed
  • 12. Overriding value() on module Class DatepickerModule extends Module { LocalDate value() { ... } Navigator value(LocalDate date) { ... } } class DatepickerPage extends Page { static content = { date { module DatepickerModule } } }
  • 13. Overriding value() on module to DatepickerPage date.value(LocalDate.of(2017, 4, 1)) assert date.value() == LocalDate.of(2017, 4, 1) to DatepickerPage date = LocalDate.of(2017, 4, 1) assert date == LocalDate.of(2017, 4, 1)
  • 14. Advanced navigation and types •  Page.convertToPath(Object[]) is used to translate arguments passed to Browser.to() into a path •  Consider overloading convertToPath() for more expressive navigation
  • 15. Advanced navigation and types class PostPage extends Page { static url = “posts” String convertToPath(Post post) { “${post.id}/${post.title.toLowerCase().replaceAll(“ ”, “-”)}” } } def post = new Post(id: 1, title: “My first post”) to PostPage, post assert title == post.title
  • 16. Parameterised pages •  Pages can be instantiated and passed to via(), to() and at() •  Useful when you need to differ implementation based on the object represented by the page
  • 17. Parameterised pages navigation class PostPage extends Page { Post post String getPageUrl() { “posts/${post.id}/${post.title.toLowerCase().replaceAll(“ ”, “-”)}” } } def post = new Post(id: 1, title: “My first post”) to(new PostPage(post: post)) assert title == post.title
  • 18. Navigators are iterable •  Navigators are backed by a collection of WebElements •  Navigators implement Iterable<Navigator>
  • 19. Navigators are iterable <html> <p>First paragraph</p> <p>Second paragraph</p> </html> $(“p”).text() // throws exception $(“p”)[0].text() // returns “First paragraph” $(“p”)*.text() // returns [“First paragraph”, “Second paragraph”] //returns [0: “First paragraph”, 1: “Second paragraph”] $(“p”).withIndex().collectEntries { [(it.second): it.first.text()] }
  • 20. What’s onLoad() for? class CookieBarPage extends Page { boolean autoCloseCookieBar = true static content = { cookieBar { module(CookieBarModule) } } void onLoad(Page previousPage) { if (autoCloseCookieBar && cookieBar) { cookieBar.close() } } }
  • 21. Injecting javascript into page js.exec ''' var url = 'https://code.jquery.com/jquery-3.2.1.min.js'; var scriptElement = document.createElement('script'); scriptElement.setAttribute('src', url); document.head.appendChild(scriptElement); '''
  • 22. Navigator’s elements in js void waitForCssTransition(Navigator navigator, WaitingSupport waiting, JavascriptInterface js, Closure trigger) { js.exec(navigator.singleElement(), ''' var o = jQuery(arguments[0]); window.setTransitionFinishedClass = function() { $(this).addClass('transitionFinished'); } o.bind('transitionend', window.setTransitionFinishedClass); ''') try { trigger.call() waiting.waitFor { hasClass('transitionFinished') } } finally { js.exec(navigator.singleElement, ''' var o = jQuery(arguments[0]); o.unbind('transitionend', window.setTransitionFinishedClass); o.removeClass('transitionFinished') window.setTransitionFinishedClass = undefined; ''') } }
  • 23. Alternatives to inheritance •  Using inheritance for code sharing leads to complex inheritance structures •  @Delegate can be used for code sharing via delegation •  Traits can be used for code sharing
  • 24. Alternatives to inheritance class TransitionSupport { private final Navigator navigator private final WaitingSupport waiting private final JavascriptInterface js TransitionSupport(Navigator navigator, WaitingSupport waiting, JavascriptInterface js) { ... } void waitForCssTransition(Closure trigger) { ... } } class TransitioningModule extends Module { @Delegate TransitionSupport transitionSupport = new TransitionSupport(this, this, js) }
  • 25. Alternatives to inheritance trait TransitionSupport implements Navigator, WaitingSupport { abstract JavascriptInterface getJs() void waitForCssTransition(Closure trigger) { ... } } class TransitioningModule extends Module implements TransitionSupport { }
  • 26. Dynamic base url class RatpackApplicationGebSpec extends GebSpec { def application = new GroovyRatpackMainApplicationUnderTest() def setup() { browser.baseUrl = application.address.toString() } }
  • 27. Testing responsive apps class TestsMobileViewExtension extends AbstractAnnotationDrivenExtension<TestsMobileView> { void visitFeatureAnnotation(TestsMobileView annotation, FeatureInfo feature) { feature.addInterceptor { invocation -> def window = new ConfigurationLoader().conf.driver.manage().window() def originalSize = window.size try { window.size = new Dimension(320, 568) invocation.proceed() } finally { window.size = originalSize } } } }
  • 29. Strongly typed Geb code •  Better authoring, i.e. autocompletion •  Better navigation, i.e. going to method definition, finding usages •  Refactoring support
  • 30. What IntelliJ understands? •  Delegation to Browser methods in specs •  Delegation to Page methods in specs •  Content definitions
  • 31. Tracking current page type •  Capture current page in a variable •  Use return values of via(), to() and at() •  Return new page instance from methods triggering page transitions
  • 32. Tracking current page def homePage = to HomePage homePage.loginPageLink.click() def loginPage = at LoginPage def securePage = loginPage.login("user", "password")
  • 33. Tracking current page to(HomePage).loginPageLink.click() def securePage = at(LoginPage).login("user", "password")
  • 34. At checks •  Keep them quick and simple •  Check if you are at the right page •  Don’t test any page logic
  • 35. What’s missing here? class CookieBarPage extends Page { boolean autoCloseCookieBar = true static content = { cookieBar { $('.cookie-message’) } cookieBarText { $('.cookie-message-text').text() } cookieBarCloseButton { $('.cookie-message-button > input') } } }
  • 36. What are modules good for? •  More than reuse •  Modeling logical components •  Hiding component structure from tests •  Hiding complex interactions from tests
  • 37. Invest time in fixture builders •  Aim for easy, expressive and flexible data setup •  Keep data setup close to tests •  Setup only the data necessary for the test •  Groovy Remote Control can be very helpful •  Fixtures are not not only about data
  • 38. Geb’s test harness html fixture def “can access element classes”() { given: html { div(id: "a", 'class': "a1 a2 a3") div(id: "b", 'class': "b1”) } expect: $("#a").classes() == ["a1", "a2", "a3"] $("#b").classes() == ["b1”] }
  • 39. Example data fixture DSL bootstrapper.post { id = “69f10bb6-118e-11e7-93ae-92361f002671” title = “My first post” tags = [“Groovy”, “Geb”] author { firstName = “Marcin” lastName = “Erdmann” } }
  • 40. Use real browser in CI •  Available headless drivers are either limited, not developed anymore or not properly tested •  Use a real browser with a virtual frame buffer, i.e. Xvfb •  Use a cloud browser provider
  • 43. To waitFor() or not? •  Ask yourself if action is asynchronous •  Watch out for quick asynchronous events
  • 44. waitFor() considered harmful •  Best not used directly in tests •  Hide asynchronous behaviour in action methods on modules and pages
  • 47. Browser test are costly! •  Slow, hard to maintain and flakey •  Mind what you test at such high level •  ...but they provide a lot of confidence
  • 49. Cloud browser providers •  Gradle plugins for driving browsers with Geb in BrowserStack and Suace Labs •  Can test applications via a tunnel which are not available on the Internet
  • 50. Using attributes map selectors •  Map selectors are now translated to CSS attribute selectors •  As quick as using css selectors but reads better especially when using dynamic values
  • 51. Using attributes map selectors $(‘button’, type: ‘select’) $(‘button[type=“select”]’) $(itemtype: ‘http://schema.org/Person’) $(‘[itemtype=“http://schema.org/Person”]’)
  • 52. Selecting by text is slow! •  Selecting by text is a Geb extension not something that CSS supports •  Narrow down selected elements as much as possible when selecting by text