SlideShare a Scribd company logo
1
GEB FOR TESTING
YOUR GRAILS
APPLICATION
Jacob Aae Mikkelsen
2
SURVEY AND RULES
AGENDA
Functional testing
Geb - cudos and history
How Geb works
Geb and Grails 2 and 3
Browser support
Javascript
3 . 1
JACOB AAE MIKKELSEN
Senior Engineer at LEGO
Microservice based architechture on JVM
Previously 4 years at Gennemtænkt IT
Consultant on Groovy and Grails
External Associate Professor - University of Southern
Denmark
@JacobAae
Blogs The Grails Diary
3 . 24 . 1
FUNCTIONAL TESTING
4 . 2
WHY?
4 . 3
4 . 4
FUNCTIONAL TESTING
Ignores the specifics of the underlying software
component under test.
Whitebox / Greybox
Merely asserts that providing certain input results in
certain output.
Web-application: Programmatically controlling a web
browser to simulate the actions of a user on a web page.
4 . 5
BROWSER AUTOMATION
4 . 64 . 7
PAIN
Traditionally been tedious, cumbersome and brittle
to do

Geb helps ease the pain
4 . 8
GAIN
Any browser based application can be tested
5 . 1
GEB
5 . 2
GEB HISTORY
Started in November 2009
Created by Luke Daley
Current project lead Marcin Erdman
WHY GEB
jQuery like selector syntax
Power of WebDriver (Easier api)
Robustness of Page Object modeling
Expressiveness of the Groovy language
Integrates well with build systems (Gradle/Maven)
Excellent user manual/documentation
5 . 3
GEB IMPLEMENTATION
Build on top of the WebDriver browser automation library
successor to the Selenium Remote Control (RC) testing
framework.
Selenium RC → JavaScript to interact
WebDriver → native browser drivers
Use JUnit or Spock
5 . 4
WEBDRIVER
Very active development
Stable API and feature set
Verbose
Low level
Not a complete solution
5 . 5
6 . 1
USING GEB
5 . 6
6 . 2
NAVIGATOR
The $() method returns a Navigator object
General format
$ ( < c s s s e l e c t o r > , < i n d e x / r a n g e > , < a t t r i b u t e / t e x t m a t c h e r s > )
GEB SELECTORS (1)
Jquery like selecter syntax
/ / m a t c h a l l ' p ' e l e m e n t s o n p a g e
$ ( " p " )
/ / m a t c h t h e f i r s t ' p ' e l e m e n t o n t h e p a g e
$ ( " p " , 0 )
/ / A l l ' d i v ' e l e m e n t s w i t h a t i t l e v a l u e ' s e c t i o n '
$ ( " d i v " , t i t l e : " s e c t i o n " )
/ / m a t c h t h e f i r s t ' d i v ' e l e m e n t t e x t ' s e c t i o n '
$ ( " d i v " , 0 , t e x t : " s e c t i o n " )
/ / m a t c h t h e f i r s t ' d i v ' e l e m e n t w i t h t h e c l a s s ' m a i n '
$ ( " d i v . m a i n " , 0 )
6 . 3
GEB SELECTORS (2)
Text attribute supports regex
/ / A n y d i v w i t h t h e t e x t s t a r t i n g w i h G R 8
$ ( " d i v " , t e x t : ~ / G R 8 . + / )
$ ( " p " , t e x t : s t a r t s W i t h ( " G R 8 " ) )
/ / A n d o t h e r h a n d y p r e d i c a t e s
$ ( " d i v " , c l a s s : c o n t a i n s ( " u i - " ) )
6 . 4
GEB SELECTORS (3)
Selecting returns Navigatorobjects
/ / T h e p a r e n t o f t h e f i r s t d i v
$ ( " d i v " , 0 ) . p a r e n t ( )
/ / A l l t a b l e s w i t h a c e l l s p a c i n g
/ / a t t r i b u t e v a l u e o f 0 t h a t a r e n e s t e d i n a p a r a g r a p h
$ ( " p " ) . f i n d ( " t a b l e " , c e l l s p a c i n g : ' 0 ' )
6 . 56 . 6
CSS SUPPORT
$ ( " t a b l e t r : n t h - c h i l d ( 2 n + 1 ) t d " )
6 . 7
RETRIVING INFORMATION
$ ( " p " ) . t e x t ( ) = = " a "
$ ( " p " ) . t a g ( ) = = " p "
$ ( " p " ) . @ t i t l e = = " a "
$ ( " p " ) . c l a s s e s ( ) = = [ " a " , " p a r a " ]
INTERACTION WITH CONTENT
click()
isDisplayed()
withConfirm{}
withAlert{}
$ ( " a . b t n " ) . c l i c k ( )
$ ( " d i v " ) . i s D i s p l a y e d ( )
w i t h C o n f i r m {
$ ( " b u t t o n . d e l e t e " ) . c l i c k ( )
}
6 . 86 . 9
SENDING INPUT
i m p o r t o r g . o p e n q a . s e l e n i u m . K e y s
/ / S h o r t h a n d f o r s e n d K e y s ( ) m e t h o d o f W e b D r i v e r .
$ ( " d i v " ) < < " a b c "
$ ( " i n p u t " , n a m e : " f o o " ) < < K e y s . c h o r d ( K e y s . C O N T R O L , " c " )
6 . 10
INTERACTION
Using ActionsAPI from WebDriver is possible.
But Geb provides the interactclosure
6 . 11
CONTROL-CLICKING
i m p o r t o r g . o p e n q a . s e l e n i u m . K e y s
i n t e r a c t {
k e y D o w n K e y s . C T R L
c l i c k $ ( " a . m y L i n k " )
k e y U p K e y s . C T R L
}
SIMULATE DRAG-N-DROP
i n t e r a c t {
c l i c k A n d H o l d ( $ ( ' # d r a g g a b l e ' ) )
m o v e B y O f f s e t ( 1 5 0 , 2 0 0 )
r e l e a s e ( )
}
Or easier
i n t e r a c t {
d r a g A n d D r o p B y ( $ ( " # d r a g g a b l e " ) , 1 5 0 , 2 0 0 )
}
6 . 12
MORE INTERACTION WITH FORMS
Consider the following HTML…
< f o r m >
< i n p u t t y p e = " t e x t " n a m e = " g e b " v a l u e = " F u n c t i o n a l " / >
< / f o r m >
The value can be read and written via property notation…
$ ( " f o r m " ) . g e b = = " F u n c t i o n a l "
$ ( " f o r m " ) . g e b = " T e s t i n g "
$ ( " f o r m " ) . g e b = = " T e s t i n g "
These are literally shortcuts for…
$ ( " f o r m " ) . f i n d ( " i n p u t " , n a m e : " g e b " ) . v a l u e ( ) = = " F u n c t i o n a l "
$ ( " f o r m " ) . f i n d ( " i n p u t " , n a m e : " g e b " ) . v a l u e ( " T e s t i n g " )
$ ( " f o r m " ) . f i n d ( " i n p u t " , n a m e : " g e b " ) . v a l u e ( ) = = " T e s t i n g "
6 . 13
VARIABLES AVAILABLE
title
browser
currentUrl
currentWindow
6 . 14
MORE POSSIBILITIES
Uploading files
Downloading files
Interacting with javascript
js object (Example later)
6 . 157 . 1
STANDALONE GEB SCRIPT
GEB STANDALONE EXAMPLE
Lets try to automate:
Searching for GR8Conf India
Click the first link
Hopefully end up on the right homepage
7 . 2
GEB STANDALONE EXAMPLE
g o " h t t p : / / d u c k d u c k g o . c o m "
$ ( ' i n p u t ' , n a m e : ' q ' ) . v a l u e ( " G R 8 C o n f I n d i a " )
$ ( ' i n p u t ' , n a m e : ' q ' ) < < K e y s . E N T E R
w a i t F o r ( 1 0 , 1 ) { $ ( " # l i n k s " ) . d i s p l a y e d }
s l e e p ( 3 0 0 0 ) / / F o r d e m o r e a s o n s
$ ( " h 2 . r e s u l t _ _ t i t l e " ) . f i r s t ( ) . c l i c k ( )
w a i t F o r { t i t l e = " G R 8 C o n f I N - 2 0 1 6 " }
7 . 38 . 1
STRUCTURING GEB TESTS
SCENARIO
Lets test a CRUD part of a grails application registrering
conference attendees
Lets test the following
1. Goto list of attendees page
2. Create new attendee (incl. invalid data once)
3. Update the attendee
4. Check data is updated
8 . 28 . 3
GEB SPEC BASICS
i m p o r t g e b . s p o c k . G e b S p e c
@ S t e p w i s e / / E n s u r e s t h e t e s t s a r e r u n s e q u e n t i a l l y
c l a s s A t t e n d e e F u n c t i o n a l S p e c e x t e n d s G e b S p e c {
/ / S p o c k s p e c s h e r e
}
GEB SPEC (1)
The naive inmaintainable way!
v o i d " G o t o l i s t p a g e - c h e c k i n i t i a l s t a t e " ( ) {
w h e n : " T h e h o m e p a g e i s v i s i t e d "
g o ' / a t t e n d e e / i n d e x '
t h e n :
t i t l e = = " A t t e n d e e L i s t "
}
8 . 4
GEB SPEC (2)
The naive inmaintainable way!
v o i d " C l i c k n e w a t t e n d e e b u t t o n " ( ) {
w h e n :
$ ( " a . c r e a t e " ) . c l i c k ( )
t h e n :
t i t l e = = " C r e a t e A t t e n d e e "
}
8 . 5
GEB SPEC (3)
The naive inmaintainable way!
v o i d " S u b m i t f o r m w i t h e r r o r s " ( ) {
w h e n :
$ ( " b u t t o n . b t n - p r i m a r y " ) . c l i c k ( )
t h e n :
t i t l e = = " C r e a t e A t t e n d e e "
}
8 . 6
GEB SPEC (4)
The naive inmaintainable way!
v o i d " S u b m i t f o r m w i t h n o e r r o r s " ( ) {
w h e n :
$ ( ' f o r m ' ) . n a m e = ' D e e p a k '
$ ( ' f o r m ' ) . e m a i l = ' d e e p a k @ m a i l . o r g '
a n d :
$ ( " b u t t o n . b t n - p r i m a r y " ) . c l i c k ( )
t h e n :
t i t l e = = ' S h o w A t t e n d e e '
$ ( ' d i v . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' D e e p a k ' }
$ ( ' d i v . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' d e e p a k @ m a i l . o r g ' }
}
8 . 7
GEB SPEC (5)
The naive inmaintainable way!
v o i d " C l i c k E d i t B u t t o n " ( ) {
w h e n :
$ ( " a . b t n - p r i m a r y " ) . c l i c k ( )
t h e n :
t i t l e = = ' E d i t A t t e n d e e '
}
8 . 8
GEB SPEC (6)
The naive inmaintainable way!
v o i d " U p d a t e A t t e n d e e " ( ) {
w h e n :
$ ( ' f o r m ' ) . n a m e = ' A m i t '
$ ( ' f o r m ' ) . e m a i l = ' a m i t @ m a i l . o r g '
a n d :
$ ( " b u t t o n . b t n - p r i m a r y " ) . c l i c k ( )
t h e n :
t i t l e = = ' S h o w A t t e n d e e '
$ ( ' s p a n . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' A m i t ' }
$ ( ' s p a n . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' a m i t @ m a i l . o r g ' }
}
8 . 99 . 1
GEB SPEC - THE BETTER WAY
If we make a few scenarios, there will be
Much duplication
Many places to correct if we change the layout / DOM
9 . 29 . 3
SOLUTION
Use pages and modules
PAGE OBJECTS
Describes a web page
Url
How to check if we are at the correct place
Content we wish to interact with
.. and how it is found
Helper methods
9 . 4
PAGE OBJECTS
i m p o r t e u . g r 8 c o n f . g r a i l s d e m o . m o d u l e s . N a v i g a t i o n B a r M o d u l e
i m p o r t g e b . P a g e
c l a s s A t t e n d e e S h o w P a g e e x t e n d s P a g e {
s t a t i c u r l = " / a t t e n d e e / s h o w "
s t a t i c a t = { t i t l e = = ~ / S h o w A t t e n d e e / }
s t a t i c c o n t e n t = {
a t t P r o p { $ ( ' s p a n . p r o p e r t y - l a b e l ' ) }
n a m e { a t t P r o p . f i n d { i t . t e x t ( ) = = ' N a m e ' } . n e x t ( ) . t e x t ( ) }
e m a i l { a t t P r o . f i n d { i t . t e x t ( ) = = ' E m a i l ' } . n e x t ( ) . t e x t ( ) }
e d i t B u t t o n { $ ( " a . b t n - p r i m a r y " ) }
}
}
9 . 59 . 6
CONTENT CLOSURE
s t a t i c c o n t e n t = {
i n f o ( r e q u i r e d : f a l s e ) { $ ( " d i v . i n f o " ) }
m e s s a g e ( w a i t : f a l s e ) { $ ( " d i v . m e s s a g e " ) }
}
9 . 7
MODULES
Describes repeated content
Across pages
Within the same page
MODULES
i m p o r t g e b . M o d u l e
c l a s s N a v i g a t i o n B a r M o d u l e e x t e n d s M o d u l e {
s t a t i c b a s e = { $ ( ' n a v . n a v b a r ' ) }
s t a t i c c o n t e n t = {
h o m e ( r e q u i r e d : f a l s e ) { $ ( ' a . h o m e ' ) }
l i s t A t t e n d e e ( r e q u i r e d : f a l s e ) { $ ( ' a . l i s t ' ) }
n e w A t t e n d e e ( r e q u i r e d : f a l s e ) { $ ( ' a . c r e a t e ' ) }
}
}
9 . 89 . 9
MODULES
s t a t i c c o n t e n t = {
/ / L i k e t h i s , t h e m o d u l e d o e s n o t n e e d a b a s e
/ / f o r m { m o d u l e N a v i g a t i o n B a r M o d u l e , $ ( ' n a v . n a v b a r ' ) }
f o r m { m o d u l e N a v i g a t i o n B a r M o d u l e }
}
MODULE FOR REPEATED CONTENT
IN A PAGE
i m p o r t g e b . M o d u l e
c l a s s A t t e n d e e L i s t I t e m M o d u l e e x t e n d s M o d u l e {
s t a t i c c o n t e n t = {
d a t a { $ ( " t d " , i t ) }
n a m e { d a t a ( 0 ) . t e x t ( ) }
e m a i l { d a t a ( 1 ) . t e x t ( ) }
n a t i o n a l i t y { d a t a ( 2 ) . t e x t ( ) }
d a t e C r e a t e d { d a t a ( 3 ) . t e x t ( ) }
l a s t U p d a t e d { d a t a ( 4 ) . t e x t ( ) }
}
}
9 . 10
MODULE FOR REPEATED CONTENT
IN A PAGE
AttendeeListPage.groovy
s t a t i c c o n t e n t = {
m e n u b a r { m o d u l e N a v i g a t i o n B a r M o d u l e }
a t t e n d e e s { m o d u l e L i s t A t t e n d e e L i s t I t e m M o d u l e ,
$ ( " t a b l e t r " ) . t a i l ( ) }
}
9 . 119 . 12
MODULE FOR REPEATED CONTENT
IN A PAGE
w h e n :
t o A t t e n d e e L i s t P a g e
t h e n :
a t t e n d e e s * . n a m e . c o n t a i n s ( ' B u r t B e c k w i t h ' )
GEB SPEC - STRUCTURED (1)
Lets try to restructure the ugly spec from before
v o i d " G o t o l i s t p a g e - c h e c k i n i t i a l s t a t e " ( ) {
w h e n :
t o A t t e n d e e I n d e x P a g e
t h e n :
a t A t t e n d e e I n d e x P a g e
}
9 . 139 . 14
GEB SPEC - STRUCTURED (2)
v o i d " C l i c k n e w a t t e n d e e b u t t o n " ( ) {
w h e n :
m e n u b a r . n e w A t t e n d e e . c l i c k ( )
t h e n :
a t A t t e n d e e C r e a t e P a g e
}
9 . 15
GEB SPEC - STRUCTURED (3)
v o i d " S u b m i t f o r m w i t h e r r o r s " ( ) {
w h e n :
s u b m i t B u t t o n . c l i c k ( )
t h e n :
a t A t t e n d e e C r e a t e P a g e
}
GEB SPEC - STRUCTURED (4)
v o i d " S u b m i t f o r m w i t h n o e r r o r s " ( ) {
w h e n :
f o r m . n a m e = ' D e e p a k '
f o r m . e m a i l = ' d e e p a k @ m a i l . o r g '
a n d :
s u b m i t B u t t o n . c l i c k ( )
t h e n :
a t A t t e n d e e S h o w P a g e
n a m e = = ' D e e p a k '
e m a i l = = ' d e e p a k @ m a i l . o r g '
}
9 . 169 . 17
GEB SPEC - STRUCTURED (5)
v o i d " C l i c k E d i t B u t t o n " ( ) {
w h e n :
e d i t B u t t o n . c l i c k ( )
t h e n :
a t A t t e n d e e E d i t P a g e
}
GEB SPEC - STRUCTURED (6)
v o i d " U p d a t e A t t e n d e e " ( ) {
w h e n :
f o r m . n a m e = ' A m i t '
f o r m . e m a i l = ' a m i t @ s o m e m a i l . c o m '
a n d :
u p d a t e B u t t o n . c l i c k ( )
t h e n :
a t A t t e n d e e S h o w P a g e
n a m e = = ' A m i t '
e m a i l = = ' a m i t @ s o m e m a i l . c o m '
}
9 . 18
STANDALONE REVISITED
t o D u c k D u c k G o P a g e
i n p u t F i e l d < < " G R 8 C o n f I n d i a "
s u b m i t ( )
w a i t F o r ( 1 0 , 0 . 5 ) {
a t D u c k D u c k G o R e s u l t P a g e
}
s l e e p ( 3 0 0 0 ) / / F o r d e m o r e a s o n s
c l i c k L i n k ( 0 )
w a i t F o r {
a t G R 8 C o n f I n d i a P a g e
}
9 . 19
STANDALONE REVISITED
c l a s s D u c k D u c k G o P a g e e x t e n d s g e b . P a g e {
s t a t i c u r l = " h t t p : / / d u c k d u c k g o . c o m "
s t a t i c a t = { t i t l e = = ~ / D u c k D u c k G o / }
s t a t i c c o n t e n t = {
i n p u t F i e l d { $ ( ' i n p u t ' , n a m e : ' q ' ) }
}
d e f s u b m i t ( ) {
i n p u t F i e l d < < K e y s . E N T E R
}
}
9 . 2010 . 1
GEB WITH GRAILS
GEB AND GRAILS 2.X
Must install plugin in BuildConfig.groovy
d e p e n d e n c i e s {
. . .
t e s t ( " o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - s u p p o r t : 2 . 4 5 . 0 " )
t e s t ( " o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - f i r e f o x - d r i v e r : 2 . 4 5 . 0 " )
t e s t " o r g . g e b i s h : g e b - s p o c k : 0 . 1 0 . 0 "
}
p l u g i n s {
. . .
t e s t " o r g . g r a i l s . p l u g i n s : g e b : 0 . 1 0 . 0 "
}
10 . 210 . 3
GEB TESTS IN GRAILS 2.X
Tests placed in test/functionalfolder
Running the tests
g r a i l s t e s t - a p p f u n c t i o n a l :
GEB AND GRAILS 3
Geb is default in build.gradle
d e p e n d e n c i e s {
. . .
t e s t C o m p i l e " o r g . g r a i l s . p l u g i n s : g e b "
/ / N o t e : I t i s r e c o m m e n d e d t o u p d a t e t o a m o r e r o b u s t d r i v e r
/ / ( C h r o m e , F i r e f o x e t c . )
t e s t R u n t i m e ' o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - h t m l u n i t - d r i v e r : 2 . 4 4 . 0
}
10 . 4
GEB TESTS IN GRAILS 3
Creating Geb Spec
g r a i l s c r e a t e - f u n c t i o n a l - t e s t M y G e b S c e n a r i o
Placing the test in src/integration-test/groovy
Running the tests
g r a i l s t e s t - a p p - i n t e g r a t i o n
10 . 5
GENERATED CLASS
@ I n t e g r a t i o n
@ R o l l b a c k
c l a s s M a n y A t t e n d e e s S p e c e x t e n d s G e b S p e c {
v o i d " t e s t s o m e t h i n g " ( ) {
w h e n : " T h e h o m e p a g e i s v i s i t e d "
g o ' / '
t h e n : " T h e t i t l e i s c o r r e c t "
$ ( ' t i t l e ' ) . t e x t ( ) = = " W e l c o m e t o G r a i l s "
}
}
10 . 610 . 7
INTERACTING WITH APPLICATION
When some functionality is needed that is not exposed
through the browser, it can be necessary to interact with the
application under test.
GRAILS 2.5
Tests not running in same JVM
Done with remote-control plugin
Send a closure for execution in application
c o m p i l e " : r e m o t e - c o n t r o l : 2 . 0 "
10 . 810 . 9
REMOTE CONTROL
s e t u p : ' C r e a t e s o m e i t e m n o t a v a i l a b l e t h r o u g h G U I '
d e f i d = r e m o t e {
I t e m i t e m = n e w I t e m ( n a m e : " M y I t e m " )
i t e m . s a v e ( )
i t e m . i d
}
10 . 10
GRAILS 3.0
Application is in same jvm
Interaction is possible directly
Tests run as integration tests
INTERACTING WITH APPLICATION
v o i d " T e s t P a g i n a t i o n i s s h o w n w i t h 1 5 a t t e n d e e s " ( ) {
s e t u p :
A t t e n d e e . w i t h N e w T r a n s a c t i o n {
1 5 . t i m e s {
n e w A t t e n d e e ( n a m e : " N $ i t " , e m a i l : " m $ i t @ t . d k " ) . s a v e ( )
}
}
w h e n :
t o A t t e n d e e I n d e x P a g e
t h e n :
h a s P a g i n a t i o n ( )
}
10 . 1110 . 12
INTERACTING WITH APPLICATION
s t a t i c c o n t e n t = {
m e n u b a r { m o d u l e N a v i g a t i o n B a r M o d u l e }
p a g i n a t i o n ( r e q u i r e d : f a l s e ) { $ ( ' s p a n . c u r r e n t S t e p ' ) }
}
b o o l e a n h a s P a g i n a t i o n ( ) {
p a g i n a t i o n . t e x t ( )
}
11 . 1
CONFIGURATION AND BROWSER
SUPPORT
11 . 2
GEBCONFIG
Configuration for Geb is placed in GebConfig.groovy
In Grails 3, place it in ´src/integration-test/groovy`
 http://www.gebish.org/manual/current/configuration.htm
11 . 3
DRIVER
It is possible to configure the browser used.
SUPPORTED DRIVERS
Firefox
Chrome
InternetExplorer
Safari
HtmlUnit
PhantomJS
11 . 411 . 5
DRIVER
It is possible to configure the browser used.
build.gradle
c o m p i l e ' o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - c h r o m e - d r i v e r : 2 . 4 9 . 0 '
c o m p i l e ' o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - f i r e f o x - d r i v e r : 2 . 4 9 . 0 '
FIREFOX
GebConfig.groovy
i m p o r t o r g . o p e n q a . s e l e n i u m . f i r e f o x . F i r e f o x P r o f i l e
i m p o r t o r g . o p e n q a . s e l e n i u m . f i r e f o x . F i r e f o x D r i v e r
d r i v e r = {
F i r e f o x P r o f i l e p r o f i l e = n e w F i r e f o x P r o f i l e ( )
p r o f i l e . s e t P r e f e r e n c e ( " b r o w s e r . d o w n l o a d . f o l d e r L i s t " , 2 )
p r o f i l e . s e t P r e f e r e n c e ( " b r o w s e r . d o w n l o a d . d i r " , " / t m p " )
p r o f i l e . s e t P r e f e r e n c e (
" b r o w s e r . h e l p e r A p p s . n e v e r A s k . s a v e T o D i s k " , " t e x t / c s v " )
d e f d r i v e r I n s t a n c e = n e w F i r e f o x D r i v e r ( p r o f i l e )
d r i v e r I n s t a n c e . m a n a g e ( ) . w i n d o w ( ) . m a x i m i z e ( )
d r i v e r I n s t a n c e
}
11 . 611 . 7
CHROME
Needs ChromeDriver downloaded
Pretty fast and stable
CHROME (1)
GebConfig.groovy
p r i v a t e S t r i n g d r i v e r L o c a t i o n D e p e n d i n g O n O p e r a t i n g S y s t e m ( ) {
S t r i n g o s = S y s t e m . g e t P r o p e r t y ( " o s . n a m e " ) . t o L o w e r C a s e ( ) ;
d e f l o c = " h t t p : / / c h r o m e d r i v e r . s t o r a g e . g o o g l e a p i s . c o m / 2 . 2 0 "
i f ( o s . c o n t a i n s ( ' m a c ' ) ) {
r e t u r n " $ { l o c } / c h r o m e d r i v e r _ m a c 3 2 . z i p "
}
i f ( o s . c o n t a i n s ( ' w i n ' ) ) {
r e t u r n " $ { l o c } / c h r o m e d r i v e r _ w i n 3 2 . z i p "
}
r e t u r n " $ { l o c } / c h r o m e d r i v e r _ l i n u x 6 4 . z i p "
}
11 . 8
CHROME (2)
GebConfig.groovy
p r i v a t e v o i d d o w n l o a d D r i v e r ( F i l e f i l e , S t r i n g p a t h ) {
i f ( ! f i l e . e x i s t s ( ) ) {
d e f a n t = n e w A n t B u i l d e r ( )
a n t . g e t ( s r c : p a t h , d e s t : ' d r i v e r . z i p ' )
a n t . u n z i p ( s r c : ' d r i v e r . z i p ' , d e s t : f i l e . p a r e n t )
a n t . d e l e t e ( f i l e : ' d r i v e r . z i p ' )
a n t . c h m o d ( f i l e : f i l e , p e r m : ' 7 0 0 ' )
}
}
11 . 9
CHROME (3)
GebConfig.groovy
d e f c h r o m e D r i v e r = n e w F i l e ( ' b u i l d / d r i v e r s / c h r o m e / c h r o m e d r i v e r ' )
d o w n l o a d D r i v e r ( c h r o m e D r i v e r ,
d r i v e r L o c a t i o n D e p e n d i n g O n O p e r a t i n g S y s t e m ( ) )
S y s t e m . s e t P r o p e r t y ( ' w e b d r i v e r . c h r o m e . d r i v e r ' ,
c h r o m e D r i v e r . a b s o l u t e P a t h )
d r i v e r = {
d e f d r i v e r I n s t a n c e = n e w C h r o m e D r i v e r ( )
d e f b r o w s e r W i n d o w = d r i v e r I n s t a n c e . m a n a g e ( ) . w i n d o w ( )
/ / w i d t h , h e i g h t
b r o w s e r W i n d o w . s i z e = n e w D i m e n s i o n ( 1 0 0 0 , 2 5 0 0 )
b r o w s e r W i n d o w . p o s i t i o n = n e w P o i n t ( 0 , 0 )
d r i v e r I n s t a n c e
}
11 . 10
WAITING
GebConfig.groovy
w a i t i n g {
t i m e o u t = 1 0
r e t r y I n t e r v a l = 0 . 5
}
b a s e N a v i g a t o r W a i t i n g = t r u e
a t C h e c k W a i t i n g = t r u e
11 . 11
USING WAITING
< d i v c l a s s = " f a d e - m e - i n " s t y l e = " d i s p l a y : n o n e " >
H i - a r e y o w a i t i n g f o r m e ?
< / d i v >
< s c r i p t >
$ ( ' d i v . f a d e - m e - i n ' ) . d e l a y ( 3 0 0 0 ) . s l i d e D o w n ( ) ;
< / s c r i p t >
s t a t i c c o n t e n t = {
f a d e I n M e s s a g e { $ ( ' d i v . f a d e - m e - i n ' ) }
}
t h e n :
w a i t F o r {
f a d e I n M e s s a g e . t e x t ( ) = = ' H i - a r e y o w a i t i n g f o r m e ? '
}
11 . 12
PAUSING GEB
p r i v a t e v o i d p a u s e ( ) {
j s . e x e c " " " ( f u n c t i o n ( ) {
w i n d o w . _ _ g e b P a u s e d = t r u e ;
v a r d i v = d o c u m e n t . c r e a t e E l e m e n t ( " d i v " ) ;
d i v . s e t A t t r i b u t e ( ' s t y l e ' , " p o s i t i o n : a b s o l u t e ; t o p : 0 p x ;  
z - i n d e x : 3 0 0 0 ; p a d d i n g : 1 0 p x ; b a c k g r o u n d - c o l o r : r e d ; ) ;
v a r b u t t o n = d o c u m e n t . c r e a t e E l e m e n t ( " b u t t o n " ) ;
b u t t o n . i n n e r H T M L = " U n p a u s e G e b " ;
b u t t o n . o n c l i c k = f u n c t i o n ( ) {
w i n d o w . _ _ g e b P a u s e d = f a l s e ;
}
d i v . a p p e n d C h i l d ( b u t t o n ) ;
d o c u m e n t . g e t E l e m e n t s B y T a g N a m e ( " b o d y " ) [ 0 ] . a p p e n d C h i l d ( d i v ) ;
} ) ( ) ; " " "
w a i t F o r ( 3 0 0 ) { ! j s . _ _ g e b P a u s e d }
}
11 . 1311 . 14
PAUSING GEB
w h e n :
p a u s e ( ) / / P a u s e G e b u n t i l b u t t o n p r e s s e d
12 . 1
REPORTING
12 . 2
TEST REPORTS
Nicely formatted
Spock power-assert format
SCREENSHOTS
Screenshots and HTML from end of each test:
Extend from GebReportingSpec
c l a s s A t t e n d e e F u n c t i o n a l S p e c e x t e n d s G e b R e p o r t i n g S p e c
GebConfig.groovy
r e p o r t s D i r = n e w F i l e ( " b u i l d / g e b - r e p o r t s " )
12 . 312 . 4
AD-HOC SCREENSHOTS
r e p o r t " W h e n - f o r m - i s - j u s t - f i l l e d "
Saves a report in reportsDir
Numbered in increasing order
13 . 1
JAVASCRIPT
In case you need to interact using javascript
13 . 2
EXECUTING JAVASCRIPT
Clicking a button that is hidden will create a
ElementNotVisibleException
< f i e l d s e t c l a s s = " w e l l " s t y l e = " d i s p l a y : n o n e " >
< g : l i n k c l a s s = " b t n " a c t i o n = " i n d e x " > L i s t < / g : l i n k >
< / f i e l d s e t >
13 . 3
EXECUTING JAVASCRIPT
J a v a s c r i p t E x e c u t o r e x e c u t o r = ( J a v a s c r i p t E x e c u t o r ) d r i v e r
e x e c u t o r . e x e c u t e S c r i p t ( ' j Q u e r y ( " . w e l l " ) . s h o w ( ) ; ' )
13 . 4
WRAPPING JAVASCRIPT
d e f j s ( S t r i n g s c r i p t ) {
( d r i v e r a s J a v a s c r i p t E x e c u t o r ) . e x e c u t e S c r i p t ( s c r i p t )
}
j s ( ' j Q u e r y ( " . w e l l " ) . s h o w ( ) ; ' )
13 . 5
JQUERY SHORTHAND
$ ( " d i v # a " ) . j q u e r y . m o u s e o v e r ( )
$ ( " # a " ) . j q u e r y . t r i g g e r ( ' m o u s e o v e r ' )
14
OTHER USAGES
Screenscraping of a site
Solving complex problems like 2048
RESOURCES
http://gebish.org
https://groups.google.com/forum/#!forum/geb-user
https://github.com/geb
https://gist.github.com/melix/9619800
https://github.com/tomaslin/grails-test-recipes
https://fbflex.wordpress.com/2010/08/25/geb-and-grails-
tips-tricks-and-gotchas/
https://github.com/JacobAae/gr8conf-in-2016-geb-for-
grails
1516
QUESTIONS?

More Related Content

What's hot

ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
Ian Barber
 
Semantic Web & TYPO3
Semantic Web & TYPO3Semantic Web & TYPO3
Semantic Web & TYPO3
André Wuttig
 
Code obfuscation, php shells & more
Code obfuscation, php shells & moreCode obfuscation, php shells & more
Code obfuscation, php shells & more
Mattias Geniar
 
Créer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heureCréer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heure
Amaury Bouchard
 
Malcon2017
Malcon2017Malcon2017
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The Answer
Ian Barber
 
Speeding up Red Team engagements with carnivorall
Speeding up Red Team engagements with carnivorallSpeeding up Red Team engagements with carnivorall
Speeding up Red Team engagements with carnivorall
Nullbyte Security Conference
 
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
John Ford
 
Using Phing for Fun and Profit
Using Phing for Fun and ProfitUsing Phing for Fun and Profit
Using Phing for Fun and Profit
Nicholas Jansma
 
Php101
Php101Php101
Pop3ck sh
Pop3ck shPop3ck sh
Pop3ck sh
Ben Pope
 
Ch3(working with file)
Ch3(working with file)Ch3(working with file)
Ch3(working with file)
Chhom Karath
 
Service intergration
Service intergration Service intergration
Service intergration
재민 장
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type System
abrummett
 
Introduction to Guzzle
Introduction to GuzzleIntroduction to Guzzle
Introduction to Guzzle
DQNEO
 
Dropping ACID with MongoDB
Dropping ACID with MongoDBDropping ACID with MongoDB
Dropping ACID with MongoDB
kchodorow
 
API Pain Points (PHPNE)
API Pain Points (PHPNE)API Pain Points (PHPNE)
API Pain Points (PHPNE)
Phil Sturgeon
 
Perl 6 for Concurrency and Parallel Computing
Perl 6 for Concurrency and Parallel ComputingPerl 6 for Concurrency and Parallel Computing
Perl 6 for Concurrency and Parallel Computing
Andrew Shitov
 
PHP Secure Programming
PHP Secure ProgrammingPHP Secure Programming
PHP Secure Programming
Balavignesh Kasinathan
 

What's hot (20)

ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
 
Semantic Web & TYPO3
Semantic Web & TYPO3Semantic Web & TYPO3
Semantic Web & TYPO3
 
Code obfuscation, php shells & more
Code obfuscation, php shells & moreCode obfuscation, php shells & more
Code obfuscation, php shells & more
 
Créer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heureCréer une base NoSQL en 1 heure
Créer une base NoSQL en 1 heure
 
Malcon2017
Malcon2017Malcon2017
Malcon2017
 
ZeroMQ Is The Answer
ZeroMQ Is The AnswerZeroMQ Is The Answer
ZeroMQ Is The Answer
 
Speeding up Red Team engagements with carnivorall
Speeding up Red Team engagements with carnivorallSpeeding up Red Team engagements with carnivorall
Speeding up Red Team engagements with carnivorall
 
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
 
Using Phing for Fun and Profit
Using Phing for Fun and ProfitUsing Phing for Fun and Profit
Using Phing for Fun and Profit
 
Php101
Php101Php101
Php101
 
Pop3ck sh
Pop3ck shPop3ck sh
Pop3ck sh
 
Ch3(working with file)
Ch3(working with file)Ch3(working with file)
Ch3(working with file)
 
Service intergration
Service intergration Service intergration
Service intergration
 
Inc
IncInc
Inc
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type System
 
Introduction to Guzzle
Introduction to GuzzleIntroduction to Guzzle
Introduction to Guzzle
 
Dropping ACID with MongoDB
Dropping ACID with MongoDBDropping ACID with MongoDB
Dropping ACID with MongoDB
 
API Pain Points (PHPNE)
API Pain Points (PHPNE)API Pain Points (PHPNE)
API Pain Points (PHPNE)
 
Perl 6 for Concurrency and Parallel Computing
Perl 6 for Concurrency and Parallel ComputingPerl 6 for Concurrency and Parallel Computing
Perl 6 for Concurrency and Parallel Computing
 
PHP Secure Programming
PHP Secure ProgrammingPHP Secure Programming
PHP Secure Programming
 

Similar to Geb for Testing Your Grails Application GR8Conf India 2016

Geb for browser automation
Geb for browser automationGeb for browser automation
Geb for browser automation
Jacob Aae Mikkelsen
 
PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!
Blanca Mancilla
 
Awesome Traefik - Ingress Controller for Kubernetes - Swapnasagar Pradhan
Awesome Traefik - Ingress Controller for Kubernetes - Swapnasagar PradhanAwesome Traefik - Ingress Controller for Kubernetes - Swapnasagar Pradhan
Awesome Traefik - Ingress Controller for Kubernetes - Swapnasagar Pradhan
Ajeet Singh Raina
 
Social Network Analysis With R
Social Network Analysis With RSocial Network Analysis With R
Social Network Analysis With R
David Chiu
 
Spring scala - Sneaking Scala into your corporation
Spring scala  - Sneaking Scala into your corporationSpring scala  - Sneaking Scala into your corporation
Spring scala - Sneaking Scala into your corporationHenryk Konsek
 
Profiling Web Archives IIPC GA 2015
Profiling Web Archives IIPC GA 2015Profiling Web Archives IIPC GA 2015
Profiling Web Archives IIPC GA 2015
Sawood Alam
 
GraphQL Relay Introduction
GraphQL Relay IntroductionGraphQL Relay Introduction
GraphQL Relay Introduction
Chen-Tsu Lin
 
PostgreSQL Day italy 2016 Unit Test
PostgreSQL Day italy 2016 Unit TestPostgreSQL Day italy 2016 Unit Test
PostgreSQL Day italy 2016 Unit Test
Andrea Adami
 
Modeling avengers – open source technology mix for saving the world
Modeling avengers – open source technology mix for saving the worldModeling avengers – open source technology mix for saving the world
Modeling avengers – open source technology mix for saving the world
Cédric Brun
 
Modeling avengers – open source technology mix for saving the world econ fr
Modeling avengers – open source technology mix for saving the world econ frModeling avengers – open source technology mix for saving the world econ fr
Modeling avengers – open source technology mix for saving the world econ fr
Cédric Brun
 
톰캣 #05-배치
톰캣 #05-배치톰캣 #05-배치
톰캣 #05-배치
GyuSeok Lee
 
Continuous delivery with Gradle
Continuous delivery with GradleContinuous delivery with Gradle
Continuous delivery with GradleBob Paulin
 
201412 seccon2014 オンライン予選(英語) write-up
201412 seccon2014 オンライン予選(英語) write-up201412 seccon2014 オンライン予選(英語) write-up
201412 seccon2014 オンライン予選(英語) write-up恵寿 東
 
Profile Serialization IIPC GA 2015
Profile Serialization IIPC GA 2015Profile Serialization IIPC GA 2015
Profile Serialization IIPC GA 2015
Sawood Alam
 
The Backside of the Class (CSS Day 2015)
The Backside of the Class (CSS Day 2015)The Backside of the Class (CSS Day 2015)
The Backside of the Class (CSS Day 2015)
Stephen Hay
 
톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment
GyuSeok Lee
 
No Flex Zone: Empathy Driven Development
No Flex Zone: Empathy Driven DevelopmentNo Flex Zone: Empathy Driven Development
No Flex Zone: Empathy Driven Development
Duretti H.
 
Tong Hop Bai Tap C
Tong Hop Bai Tap CTong Hop Bai Tap C
Tong Hop Bai Tap CSamQuiDaiBo
 
Keep it simple web development stack
Keep it simple web development stackKeep it simple web development stack
Keep it simple web development stack
Eric Ahn
 
Top 10 php classic traps
Top 10 php classic trapsTop 10 php classic traps
Top 10 php classic traps
Damien Seguy
 

Similar to Geb for Testing Your Grails Application GR8Conf India 2016 (20)

Geb for browser automation
Geb for browser automationGeb for browser automation
Geb for browser automation
 
PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!
 
Awesome Traefik - Ingress Controller for Kubernetes - Swapnasagar Pradhan
Awesome Traefik - Ingress Controller for Kubernetes - Swapnasagar PradhanAwesome Traefik - Ingress Controller for Kubernetes - Swapnasagar Pradhan
Awesome Traefik - Ingress Controller for Kubernetes - Swapnasagar Pradhan
 
Social Network Analysis With R
Social Network Analysis With RSocial Network Analysis With R
Social Network Analysis With R
 
Spring scala - Sneaking Scala into your corporation
Spring scala  - Sneaking Scala into your corporationSpring scala  - Sneaking Scala into your corporation
Spring scala - Sneaking Scala into your corporation
 
Profiling Web Archives IIPC GA 2015
Profiling Web Archives IIPC GA 2015Profiling Web Archives IIPC GA 2015
Profiling Web Archives IIPC GA 2015
 
GraphQL Relay Introduction
GraphQL Relay IntroductionGraphQL Relay Introduction
GraphQL Relay Introduction
 
PostgreSQL Day italy 2016 Unit Test
PostgreSQL Day italy 2016 Unit TestPostgreSQL Day italy 2016 Unit Test
PostgreSQL Day italy 2016 Unit Test
 
Modeling avengers – open source technology mix for saving the world
Modeling avengers – open source technology mix for saving the worldModeling avengers – open source technology mix for saving the world
Modeling avengers – open source technology mix for saving the world
 
Modeling avengers – open source technology mix for saving the world econ fr
Modeling avengers – open source technology mix for saving the world econ frModeling avengers – open source technology mix for saving the world econ fr
Modeling avengers – open source technology mix for saving the world econ fr
 
톰캣 #05-배치
톰캣 #05-배치톰캣 #05-배치
톰캣 #05-배치
 
Continuous delivery with Gradle
Continuous delivery with GradleContinuous delivery with Gradle
Continuous delivery with Gradle
 
201412 seccon2014 オンライン予選(英語) write-up
201412 seccon2014 オンライン予選(英語) write-up201412 seccon2014 オンライン予選(英語) write-up
201412 seccon2014 オンライン予選(英語) write-up
 
Profile Serialization IIPC GA 2015
Profile Serialization IIPC GA 2015Profile Serialization IIPC GA 2015
Profile Serialization IIPC GA 2015
 
The Backside of the Class (CSS Day 2015)
The Backside of the Class (CSS Day 2015)The Backside of the Class (CSS Day 2015)
The Backside of the Class (CSS Day 2015)
 
톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment
 
No Flex Zone: Empathy Driven Development
No Flex Zone: Empathy Driven DevelopmentNo Flex Zone: Empathy Driven Development
No Flex Zone: Empathy Driven Development
 
Tong Hop Bai Tap C
Tong Hop Bai Tap CTong Hop Bai Tap C
Tong Hop Bai Tap C
 
Keep it simple web development stack
Keep it simple web development stackKeep it simple web development stack
Keep it simple web development stack
 
Top 10 php classic traps
Top 10 php classic trapsTop 10 php classic traps
Top 10 php classic traps
 

Recently uploaded

急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
3ipehhoa
 
学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作
学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作
学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作
zyfovom
 
guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...
Rogerio Filho
 
国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理
国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理
国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理
zoowe
 
一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理
一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理
一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理
keoku
 
Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...
Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...
Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...
CIOWomenMagazine
 
test test test test testtest test testtest test testtest test testtest test ...
test test  test test testtest test testtest test testtest test testtest test ...test test  test test testtest test testtest test testtest test testtest test ...
test test test test testtest test testtest test testtest test testtest test ...
Arif0071
 
7 Best Cloud Hosting Services to Try Out in 2024
7 Best Cloud Hosting Services to Try Out in 20247 Best Cloud Hosting Services to Try Out in 2024
7 Best Cloud Hosting Services to Try Out in 2024
Danica Gill
 
1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...
JeyaPerumal1
 
Gen Z and the marketplaces - let's translate their needs
Gen Z and the marketplaces - let's translate their needsGen Z and the marketplaces - let's translate their needs
Gen Z and the marketplaces - let's translate their needs
Laura Szabó
 
假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理
假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理
假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理
cuobya
 
Understanding User Behavior with Google Analytics.pdf
Understanding User Behavior with Google Analytics.pdfUnderstanding User Behavior with Google Analytics.pdf
Understanding User Behavior with Google Analytics.pdf
SEO Article Boost
 
一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理
一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理
一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理
eutxy
 
Explore-Insanony: Watch Instagram Stories Secretly
Explore-Insanony: Watch Instagram Stories SecretlyExplore-Insanony: Watch Instagram Stories Secretly
Explore-Insanony: Watch Instagram Stories Secretly
Trending Blogers
 
制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理
制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理
制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理
cuobya
 
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
3ipehhoa
 
2.Cellular Networks_The final stage of connectivity is achieved by segmenting...
2.Cellular Networks_The final stage of connectivity is achieved by segmenting...2.Cellular Networks_The final stage of connectivity is achieved by segmenting...
2.Cellular Networks_The final stage of connectivity is achieved by segmenting...
JeyaPerumal1
 
Search Result Showing My Post is Now Buried
Search Result Showing My Post is Now BuriedSearch Result Showing My Post is Now Buried
Search Result Showing My Post is Now Buried
Trish Parr
 
Bridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptx
Bridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptxBridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptx
Bridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptx
Brad Spiegel Macon GA
 
一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理
一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理
一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理
ufdana
 

Recently uploaded (20)

急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
急速办(bedfordhire毕业证书)英国贝德福特大学毕业证成绩单原版一模一样
 
学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作
学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作
学位认证网(DU毕业证)迪肯大学毕业证成绩单一比一原版制作
 
guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...guildmasters guide to ravnica Dungeons & Dragons 5...
guildmasters guide to ravnica Dungeons & Dragons 5...
 
国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理
国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理
国外证书(Lincoln毕业证)新西兰林肯大学毕业证成绩单不能毕业办理
 
一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理
一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理
一比一原版(SLU毕业证)圣路易斯大学毕业证成绩单专业办理
 
Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...
Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...
Internet of Things in Manufacturing: Revolutionizing Efficiency & Quality | C...
 
test test test test testtest test testtest test testtest test testtest test ...
test test  test test testtest test testtest test testtest test testtest test ...test test  test test testtest test testtest test testtest test testtest test ...
test test test test testtest test testtest test testtest test testtest test ...
 
7 Best Cloud Hosting Services to Try Out in 2024
7 Best Cloud Hosting Services to Try Out in 20247 Best Cloud Hosting Services to Try Out in 2024
7 Best Cloud Hosting Services to Try Out in 2024
 
1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...1.Wireless Communication System_Wireless communication is a broad term that i...
1.Wireless Communication System_Wireless communication is a broad term that i...
 
Gen Z and the marketplaces - let's translate their needs
Gen Z and the marketplaces - let's translate their needsGen Z and the marketplaces - let's translate their needs
Gen Z and the marketplaces - let's translate their needs
 
假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理
假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理
假文凭国外(Adelaide毕业证)澳大利亚国立大学毕业证成绩单办理
 
Understanding User Behavior with Google Analytics.pdf
Understanding User Behavior with Google Analytics.pdfUnderstanding User Behavior with Google Analytics.pdf
Understanding User Behavior with Google Analytics.pdf
 
一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理
一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理
一比一原版(LBS毕业证)伦敦商学院毕业证成绩单专业办理
 
Explore-Insanony: Watch Instagram Stories Secretly
Explore-Insanony: Watch Instagram Stories SecretlyExplore-Insanony: Watch Instagram Stories Secretly
Explore-Insanony: Watch Instagram Stories Secretly
 
制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理
制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理
制作毕业证书(ANU毕业证)莫纳什大学毕业证成绩单官方原版办理
 
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
1比1复刻(bath毕业证书)英国巴斯大学毕业证学位证原版一模一样
 
2.Cellular Networks_The final stage of connectivity is achieved by segmenting...
2.Cellular Networks_The final stage of connectivity is achieved by segmenting...2.Cellular Networks_The final stage of connectivity is achieved by segmenting...
2.Cellular Networks_The final stage of connectivity is achieved by segmenting...
 
Search Result Showing My Post is Now Buried
Search Result Showing My Post is Now BuriedSearch Result Showing My Post is Now Buried
Search Result Showing My Post is Now Buried
 
Bridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptx
Bridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptxBridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptx
Bridging the Digital Gap Brad Spiegel Macon, GA Initiative.pptx
 
一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理
一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理
一比一原版(CSU毕业证)加利福尼亚州立大学毕业证成绩单专业办理
 

Geb for Testing Your Grails Application GR8Conf India 2016

  • 1. 1 GEB FOR TESTING YOUR GRAILS APPLICATION Jacob Aae Mikkelsen
  • 3. AGENDA Functional testing Geb - cudos and history How Geb works Geb and Grails 2 and 3 Browser support Javascript
  • 4. 3 . 1 JACOB AAE MIKKELSEN Senior Engineer at LEGO Microservice based architechture on JVM Previously 4 years at Gennemtænkt IT Consultant on Groovy and Grails External Associate Professor - University of Southern Denmark @JacobAae Blogs The Grails Diary
  • 5. 3 . 24 . 1 FUNCTIONAL TESTING
  • 6.
  • 9. 4 . 4 FUNCTIONAL TESTING Ignores the specifics of the underlying software component under test. Whitebox / Greybox Merely asserts that providing certain input results in certain output. Web-application: Programmatically controlling a web browser to simulate the actions of a user on a web page.
  • 10. 4 . 5 BROWSER AUTOMATION
  • 11. 4 . 64 . 7 PAIN Traditionally been tedious, cumbersome and brittle to do  Geb helps ease the pain
  • 12. 4 . 8 GAIN Any browser based application can be tested
  • 14. 5 . 2 GEB HISTORY Started in November 2009 Created by Luke Daley Current project lead Marcin Erdman
  • 15. WHY GEB jQuery like selector syntax Power of WebDriver (Easier api) Robustness of Page Object modeling Expressiveness of the Groovy language Integrates well with build systems (Gradle/Maven) Excellent user manual/documentation
  • 16. 5 . 3 GEB IMPLEMENTATION Build on top of the WebDriver browser automation library successor to the Selenium Remote Control (RC) testing framework. Selenium RC → JavaScript to interact WebDriver → native browser drivers Use JUnit or Spock
  • 17. 5 . 4 WEBDRIVER Very active development Stable API and feature set Verbose Low level Not a complete solution
  • 18. 5 . 5
  • 19. 6 . 1 USING GEB
  • 20. 5 . 6 6 . 2 NAVIGATOR The $() method returns a Navigator object General format $ ( < c s s s e l e c t o r > , < i n d e x / r a n g e > , < a t t r i b u t e / t e x t m a t c h e r s > )
  • 21. GEB SELECTORS (1) Jquery like selecter syntax / / m a t c h a l l ' p ' e l e m e n t s o n p a g e $ ( " p " ) / / m a t c h t h e f i r s t ' p ' e l e m e n t o n t h e p a g e $ ( " p " , 0 ) / / A l l ' d i v ' e l e m e n t s w i t h a t i t l e v a l u e ' s e c t i o n ' $ ( " d i v " , t i t l e : " s e c t i o n " ) / / m a t c h t h e f i r s t ' d i v ' e l e m e n t t e x t ' s e c t i o n ' $ ( " d i v " , 0 , t e x t : " s e c t i o n " ) / / m a t c h t h e f i r s t ' d i v ' e l e m e n t w i t h t h e c l a s s ' m a i n ' $ ( " d i v . m a i n " , 0 )
  • 22. 6 . 3 GEB SELECTORS (2) Text attribute supports regex / / A n y d i v w i t h t h e t e x t s t a r t i n g w i h G R 8 $ ( " d i v " , t e x t : ~ / G R 8 . + / ) $ ( " p " , t e x t : s t a r t s W i t h ( " G R 8 " ) ) / / A n d o t h e r h a n d y p r e d i c a t e s $ ( " d i v " , c l a s s : c o n t a i n s ( " u i - " ) )
  • 23. 6 . 4 GEB SELECTORS (3) Selecting returns Navigatorobjects / / T h e p a r e n t o f t h e f i r s t d i v $ ( " d i v " , 0 ) . p a r e n t ( ) / / A l l t a b l e s w i t h a c e l l s p a c i n g / / a t t r i b u t e v a l u e o f 0 t h a t a r e n e s t e d i n a p a r a g r a p h $ ( " p " ) . f i n d ( " t a b l e " , c e l l s p a c i n g : ' 0 ' )
  • 24. 6 . 56 . 6 CSS SUPPORT $ ( " t a b l e t r : n t h - c h i l d ( 2 n + 1 ) t d " )
  • 25. 6 . 7 RETRIVING INFORMATION $ ( " p " ) . t e x t ( ) = = " a " $ ( " p " ) . t a g ( ) = = " p " $ ( " p " ) . @ t i t l e = = " a " $ ( " p " ) . c l a s s e s ( ) = = [ " a " , " p a r a " ]
  • 26. INTERACTION WITH CONTENT click() isDisplayed() withConfirm{} withAlert{} $ ( " a . b t n " ) . c l i c k ( ) $ ( " d i v " ) . i s D i s p l a y e d ( ) w i t h C o n f i r m { $ ( " b u t t o n . d e l e t e " ) . c l i c k ( ) }
  • 27. 6 . 86 . 9 SENDING INPUT i m p o r t o r g . o p e n q a . s e l e n i u m . K e y s / / S h o r t h a n d f o r s e n d K e y s ( ) m e t h o d o f W e b D r i v e r . $ ( " d i v " ) < < " a b c " $ ( " i n p u t " , n a m e : " f o o " ) < < K e y s . c h o r d ( K e y s . C O N T R O L , " c " )
  • 28. 6 . 10 INTERACTION Using ActionsAPI from WebDriver is possible. But Geb provides the interactclosure
  • 29. 6 . 11 CONTROL-CLICKING i m p o r t o r g . o p e n q a . s e l e n i u m . K e y s i n t e r a c t { k e y D o w n K e y s . C T R L c l i c k $ ( " a . m y L i n k " ) k e y U p K e y s . C T R L }
  • 30. SIMULATE DRAG-N-DROP i n t e r a c t { c l i c k A n d H o l d ( $ ( ' # d r a g g a b l e ' ) ) m o v e B y O f f s e t ( 1 5 0 , 2 0 0 ) r e l e a s e ( ) } Or easier i n t e r a c t { d r a g A n d D r o p B y ( $ ( " # d r a g g a b l e " ) , 1 5 0 , 2 0 0 ) }
  • 31. 6 . 12 MORE INTERACTION WITH FORMS Consider the following HTML… < f o r m > < i n p u t t y p e = " t e x t " n a m e = " g e b " v a l u e = " F u n c t i o n a l " / > < / f o r m > The value can be read and written via property notation… $ ( " f o r m " ) . g e b = = " F u n c t i o n a l " $ ( " f o r m " ) . g e b = " T e s t i n g " $ ( " f o r m " ) . g e b = = " T e s t i n g " These are literally shortcuts for… $ ( " f o r m " ) . f i n d ( " i n p u t " , n a m e : " g e b " ) . v a l u e ( ) = = " F u n c t i o n a l " $ ( " f o r m " ) . f i n d ( " i n p u t " , n a m e : " g e b " ) . v a l u e ( " T e s t i n g " ) $ ( " f o r m " ) . f i n d ( " i n p u t " , n a m e : " g e b " ) . v a l u e ( ) = = " T e s t i n g "
  • 32. 6 . 13 VARIABLES AVAILABLE title browser currentUrl currentWindow
  • 33. 6 . 14 MORE POSSIBILITIES Uploading files Downloading files Interacting with javascript js object (Example later)
  • 34. 6 . 157 . 1 STANDALONE GEB SCRIPT
  • 35. GEB STANDALONE EXAMPLE Lets try to automate: Searching for GR8Conf India Click the first link Hopefully end up on the right homepage
  • 36. 7 . 2 GEB STANDALONE EXAMPLE g o " h t t p : / / d u c k d u c k g o . c o m " $ ( ' i n p u t ' , n a m e : ' q ' ) . v a l u e ( " G R 8 C o n f I n d i a " ) $ ( ' i n p u t ' , n a m e : ' q ' ) < < K e y s . E N T E R w a i t F o r ( 1 0 , 1 ) { $ ( " # l i n k s " ) . d i s p l a y e d } s l e e p ( 3 0 0 0 ) / / F o r d e m o r e a s o n s $ ( " h 2 . r e s u l t _ _ t i t l e " ) . f i r s t ( ) . c l i c k ( ) w a i t F o r { t i t l e = " G R 8 C o n f I N - 2 0 1 6 " }
  • 37. 7 . 38 . 1 STRUCTURING GEB TESTS
  • 38. SCENARIO Lets test a CRUD part of a grails application registrering conference attendees Lets test the following 1. Goto list of attendees page 2. Create new attendee (incl. invalid data once) 3. Update the attendee 4. Check data is updated
  • 39. 8 . 28 . 3 GEB SPEC BASICS i m p o r t g e b . s p o c k . G e b S p e c @ S t e p w i s e / / E n s u r e s t h e t e s t s a r e r u n s e q u e n t i a l l y c l a s s A t t e n d e e F u n c t i o n a l S p e c e x t e n d s G e b S p e c { / / S p o c k s p e c s h e r e }
  • 40. GEB SPEC (1) The naive inmaintainable way! v o i d " G o t o l i s t p a g e - c h e c k i n i t i a l s t a t e " ( ) { w h e n : " T h e h o m e p a g e i s v i s i t e d " g o ' / a t t e n d e e / i n d e x ' t h e n : t i t l e = = " A t t e n d e e L i s t " }
  • 41. 8 . 4 GEB SPEC (2) The naive inmaintainable way! v o i d " C l i c k n e w a t t e n d e e b u t t o n " ( ) { w h e n : $ ( " a . c r e a t e " ) . c l i c k ( ) t h e n : t i t l e = = " C r e a t e A t t e n d e e " }
  • 42. 8 . 5 GEB SPEC (3) The naive inmaintainable way! v o i d " S u b m i t f o r m w i t h e r r o r s " ( ) { w h e n : $ ( " b u t t o n . b t n - p r i m a r y " ) . c l i c k ( ) t h e n : t i t l e = = " C r e a t e A t t e n d e e " }
  • 43. 8 . 6 GEB SPEC (4) The naive inmaintainable way! v o i d " S u b m i t f o r m w i t h n o e r r o r s " ( ) { w h e n : $ ( ' f o r m ' ) . n a m e = ' D e e p a k ' $ ( ' f o r m ' ) . e m a i l = ' d e e p a k @ m a i l . o r g ' a n d : $ ( " b u t t o n . b t n - p r i m a r y " ) . c l i c k ( ) t h e n : t i t l e = = ' S h o w A t t e n d e e ' $ ( ' d i v . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' D e e p a k ' } $ ( ' d i v . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' d e e p a k @ m a i l . o r g ' } }
  • 44. 8 . 7 GEB SPEC (5) The naive inmaintainable way! v o i d " C l i c k E d i t B u t t o n " ( ) { w h e n : $ ( " a . b t n - p r i m a r y " ) . c l i c k ( ) t h e n : t i t l e = = ' E d i t A t t e n d e e ' }
  • 45. 8 . 8 GEB SPEC (6) The naive inmaintainable way! v o i d " U p d a t e A t t e n d e e " ( ) { w h e n : $ ( ' f o r m ' ) . n a m e = ' A m i t ' $ ( ' f o r m ' ) . e m a i l = ' a m i t @ m a i l . o r g ' a n d : $ ( " b u t t o n . b t n - p r i m a r y " ) . c l i c k ( ) t h e n : t i t l e = = ' S h o w A t t e n d e e ' $ ( ' s p a n . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' A m i t ' } $ ( ' s p a n . p r o p e r t y - v a l u e ' ) . f i n d { i t . t e x t ( ) = = ' a m i t @ m a i l . o r g ' } }
  • 46. 8 . 99 . 1 GEB SPEC - THE BETTER WAY If we make a few scenarios, there will be Much duplication Many places to correct if we change the layout / DOM
  • 47.
  • 48. 9 . 29 . 3 SOLUTION Use pages and modules
  • 49. PAGE OBJECTS Describes a web page Url How to check if we are at the correct place Content we wish to interact with .. and how it is found Helper methods
  • 50. 9 . 4 PAGE OBJECTS i m p o r t e u . g r 8 c o n f . g r a i l s d e m o . m o d u l e s . N a v i g a t i o n B a r M o d u l e i m p o r t g e b . P a g e c l a s s A t t e n d e e S h o w P a g e e x t e n d s P a g e { s t a t i c u r l = " / a t t e n d e e / s h o w " s t a t i c a t = { t i t l e = = ~ / S h o w A t t e n d e e / } s t a t i c c o n t e n t = { a t t P r o p { $ ( ' s p a n . p r o p e r t y - l a b e l ' ) } n a m e { a t t P r o p . f i n d { i t . t e x t ( ) = = ' N a m e ' } . n e x t ( ) . t e x t ( ) } e m a i l { a t t P r o . f i n d { i t . t e x t ( ) = = ' E m a i l ' } . n e x t ( ) . t e x t ( ) } e d i t B u t t o n { $ ( " a . b t n - p r i m a r y " ) } } }
  • 51. 9 . 59 . 6 CONTENT CLOSURE s t a t i c c o n t e n t = { i n f o ( r e q u i r e d : f a l s e ) { $ ( " d i v . i n f o " ) } m e s s a g e ( w a i t : f a l s e ) { $ ( " d i v . m e s s a g e " ) } }
  • 52. 9 . 7 MODULES Describes repeated content Across pages Within the same page
  • 53. MODULES i m p o r t g e b . M o d u l e c l a s s N a v i g a t i o n B a r M o d u l e e x t e n d s M o d u l e { s t a t i c b a s e = { $ ( ' n a v . n a v b a r ' ) } s t a t i c c o n t e n t = { h o m e ( r e q u i r e d : f a l s e ) { $ ( ' a . h o m e ' ) } l i s t A t t e n d e e ( r e q u i r e d : f a l s e ) { $ ( ' a . l i s t ' ) } n e w A t t e n d e e ( r e q u i r e d : f a l s e ) { $ ( ' a . c r e a t e ' ) } } }
  • 54. 9 . 89 . 9 MODULES s t a t i c c o n t e n t = { / / L i k e t h i s , t h e m o d u l e d o e s n o t n e e d a b a s e / / f o r m { m o d u l e N a v i g a t i o n B a r M o d u l e , $ ( ' n a v . n a v b a r ' ) } f o r m { m o d u l e N a v i g a t i o n B a r M o d u l e } }
  • 55. MODULE FOR REPEATED CONTENT IN A PAGE i m p o r t g e b . M o d u l e c l a s s A t t e n d e e L i s t I t e m M o d u l e e x t e n d s M o d u l e { s t a t i c c o n t e n t = { d a t a { $ ( " t d " , i t ) } n a m e { d a t a ( 0 ) . t e x t ( ) } e m a i l { d a t a ( 1 ) . t e x t ( ) } n a t i o n a l i t y { d a t a ( 2 ) . t e x t ( ) } d a t e C r e a t e d { d a t a ( 3 ) . t e x t ( ) } l a s t U p d a t e d { d a t a ( 4 ) . t e x t ( ) } } }
  • 56. 9 . 10 MODULE FOR REPEATED CONTENT IN A PAGE AttendeeListPage.groovy s t a t i c c o n t e n t = { m e n u b a r { m o d u l e N a v i g a t i o n B a r M o d u l e } a t t e n d e e s { m o d u l e L i s t A t t e n d e e L i s t I t e m M o d u l e , $ ( " t a b l e t r " ) . t a i l ( ) } }
  • 57. 9 . 119 . 12 MODULE FOR REPEATED CONTENT IN A PAGE w h e n : t o A t t e n d e e L i s t P a g e t h e n : a t t e n d e e s * . n a m e . c o n t a i n s ( ' B u r t B e c k w i t h ' )
  • 58. GEB SPEC - STRUCTURED (1) Lets try to restructure the ugly spec from before v o i d " G o t o l i s t p a g e - c h e c k i n i t i a l s t a t e " ( ) { w h e n : t o A t t e n d e e I n d e x P a g e t h e n : a t A t t e n d e e I n d e x P a g e }
  • 59. 9 . 139 . 14 GEB SPEC - STRUCTURED (2) v o i d " C l i c k n e w a t t e n d e e b u t t o n " ( ) { w h e n : m e n u b a r . n e w A t t e n d e e . c l i c k ( ) t h e n : a t A t t e n d e e C r e a t e P a g e }
  • 60. 9 . 15 GEB SPEC - STRUCTURED (3) v o i d " S u b m i t f o r m w i t h e r r o r s " ( ) { w h e n : s u b m i t B u t t o n . c l i c k ( ) t h e n : a t A t t e n d e e C r e a t e P a g e }
  • 61. GEB SPEC - STRUCTURED (4) v o i d " S u b m i t f o r m w i t h n o e r r o r s " ( ) { w h e n : f o r m . n a m e = ' D e e p a k ' f o r m . e m a i l = ' d e e p a k @ m a i l . o r g ' a n d : s u b m i t B u t t o n . c l i c k ( ) t h e n : a t A t t e n d e e S h o w P a g e n a m e = = ' D e e p a k ' e m a i l = = ' d e e p a k @ m a i l . o r g ' }
  • 62. 9 . 169 . 17 GEB SPEC - STRUCTURED (5) v o i d " C l i c k E d i t B u t t o n " ( ) { w h e n : e d i t B u t t o n . c l i c k ( ) t h e n : a t A t t e n d e e E d i t P a g e }
  • 63. GEB SPEC - STRUCTURED (6) v o i d " U p d a t e A t t e n d e e " ( ) { w h e n : f o r m . n a m e = ' A m i t ' f o r m . e m a i l = ' a m i t @ s o m e m a i l . c o m ' a n d : u p d a t e B u t t o n . c l i c k ( ) t h e n : a t A t t e n d e e S h o w P a g e n a m e = = ' A m i t ' e m a i l = = ' a m i t @ s o m e m a i l . c o m ' }
  • 64. 9 . 18 STANDALONE REVISITED t o D u c k D u c k G o P a g e i n p u t F i e l d < < " G R 8 C o n f I n d i a " s u b m i t ( ) w a i t F o r ( 1 0 , 0 . 5 ) { a t D u c k D u c k G o R e s u l t P a g e } s l e e p ( 3 0 0 0 ) / / F o r d e m o r e a s o n s c l i c k L i n k ( 0 ) w a i t F o r { a t G R 8 C o n f I n d i a P a g e }
  • 65. 9 . 19 STANDALONE REVISITED c l a s s D u c k D u c k G o P a g e e x t e n d s g e b . P a g e { s t a t i c u r l = " h t t p : / / d u c k d u c k g o . c o m " s t a t i c a t = { t i t l e = = ~ / D u c k D u c k G o / } s t a t i c c o n t e n t = { i n p u t F i e l d { $ ( ' i n p u t ' , n a m e : ' q ' ) } } d e f s u b m i t ( ) { i n p u t F i e l d < < K e y s . E N T E R } }
  • 66. 9 . 2010 . 1 GEB WITH GRAILS
  • 67. GEB AND GRAILS 2.X Must install plugin in BuildConfig.groovy d e p e n d e n c i e s { . . . t e s t ( " o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - s u p p o r t : 2 . 4 5 . 0 " ) t e s t ( " o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - f i r e f o x - d r i v e r : 2 . 4 5 . 0 " ) t e s t " o r g . g e b i s h : g e b - s p o c k : 0 . 1 0 . 0 " } p l u g i n s { . . . t e s t " o r g . g r a i l s . p l u g i n s : g e b : 0 . 1 0 . 0 " }
  • 68. 10 . 210 . 3 GEB TESTS IN GRAILS 2.X Tests placed in test/functionalfolder Running the tests g r a i l s t e s t - a p p f u n c t i o n a l :
  • 69. GEB AND GRAILS 3 Geb is default in build.gradle d e p e n d e n c i e s { . . . t e s t C o m p i l e " o r g . g r a i l s . p l u g i n s : g e b " / / N o t e : I t i s r e c o m m e n d e d t o u p d a t e t o a m o r e r o b u s t d r i v e r / / ( C h r o m e , F i r e f o x e t c . ) t e s t R u n t i m e ' o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - h t m l u n i t - d r i v e r : 2 . 4 4 . 0 }
  • 70. 10 . 4 GEB TESTS IN GRAILS 3 Creating Geb Spec g r a i l s c r e a t e - f u n c t i o n a l - t e s t M y G e b S c e n a r i o Placing the test in src/integration-test/groovy Running the tests g r a i l s t e s t - a p p - i n t e g r a t i o n
  • 71. 10 . 5 GENERATED CLASS @ I n t e g r a t i o n @ R o l l b a c k c l a s s M a n y A t t e n d e e s S p e c e x t e n d s G e b S p e c { v o i d " t e s t s o m e t h i n g " ( ) { w h e n : " T h e h o m e p a g e i s v i s i t e d " g o ' / ' t h e n : " T h e t i t l e i s c o r r e c t " $ ( ' t i t l e ' ) . t e x t ( ) = = " W e l c o m e t o G r a i l s " } }
  • 72. 10 . 610 . 7 INTERACTING WITH APPLICATION When some functionality is needed that is not exposed through the browser, it can be necessary to interact with the application under test.
  • 73. GRAILS 2.5 Tests not running in same JVM Done with remote-control plugin Send a closure for execution in application c o m p i l e " : r e m o t e - c o n t r o l : 2 . 0 "
  • 74. 10 . 810 . 9 REMOTE CONTROL s e t u p : ' C r e a t e s o m e i t e m n o t a v a i l a b l e t h r o u g h G U I ' d e f i d = r e m o t e { I t e m i t e m = n e w I t e m ( n a m e : " M y I t e m " ) i t e m . s a v e ( ) i t e m . i d }
  • 75. 10 . 10 GRAILS 3.0 Application is in same jvm Interaction is possible directly Tests run as integration tests
  • 76. INTERACTING WITH APPLICATION v o i d " T e s t P a g i n a t i o n i s s h o w n w i t h 1 5 a t t e n d e e s " ( ) { s e t u p : A t t e n d e e . w i t h N e w T r a n s a c t i o n { 1 5 . t i m e s { n e w A t t e n d e e ( n a m e : " N $ i t " , e m a i l : " m $ i t @ t . d k " ) . s a v e ( ) } } w h e n : t o A t t e n d e e I n d e x P a g e t h e n : h a s P a g i n a t i o n ( ) }
  • 77. 10 . 1110 . 12 INTERACTING WITH APPLICATION s t a t i c c o n t e n t = { m e n u b a r { m o d u l e N a v i g a t i o n B a r M o d u l e } p a g i n a t i o n ( r e q u i r e d : f a l s e ) { $ ( ' s p a n . c u r r e n t S t e p ' ) } } b o o l e a n h a s P a g i n a t i o n ( ) { p a g i n a t i o n . t e x t ( ) }
  • 78. 11 . 1 CONFIGURATION AND BROWSER SUPPORT
  • 79. 11 . 2 GEBCONFIG Configuration for Geb is placed in GebConfig.groovy In Grails 3, place it in ´src/integration-test/groovy`  http://www.gebish.org/manual/current/configuration.htm
  • 80. 11 . 3 DRIVER It is possible to configure the browser used.
  • 82. 11 . 411 . 5 DRIVER It is possible to configure the browser used. build.gradle c o m p i l e ' o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - c h r o m e - d r i v e r : 2 . 4 9 . 0 ' c o m p i l e ' o r g . s e l e n i u m h q . s e l e n i u m : s e l e n i u m - f i r e f o x - d r i v e r : 2 . 4 9 . 0 '
  • 83. FIREFOX GebConfig.groovy i m p o r t o r g . o p e n q a . s e l e n i u m . f i r e f o x . F i r e f o x P r o f i l e i m p o r t o r g . o p e n q a . s e l e n i u m . f i r e f o x . F i r e f o x D r i v e r d r i v e r = { F i r e f o x P r o f i l e p r o f i l e = n e w F i r e f o x P r o f i l e ( ) p r o f i l e . s e t P r e f e r e n c e ( " b r o w s e r . d o w n l o a d . f o l d e r L i s t " , 2 ) p r o f i l e . s e t P r e f e r e n c e ( " b r o w s e r . d o w n l o a d . d i r " , " / t m p " ) p r o f i l e . s e t P r e f e r e n c e ( " b r o w s e r . h e l p e r A p p s . n e v e r A s k . s a v e T o D i s k " , " t e x t / c s v " ) d e f d r i v e r I n s t a n c e = n e w F i r e f o x D r i v e r ( p r o f i l e ) d r i v e r I n s t a n c e . m a n a g e ( ) . w i n d o w ( ) . m a x i m i z e ( ) d r i v e r I n s t a n c e }
  • 84. 11 . 611 . 7 CHROME Needs ChromeDriver downloaded Pretty fast and stable
  • 85. CHROME (1) GebConfig.groovy p r i v a t e S t r i n g d r i v e r L o c a t i o n D e p e n d i n g O n O p e r a t i n g S y s t e m ( ) { S t r i n g o s = S y s t e m . g e t P r o p e r t y ( " o s . n a m e " ) . t o L o w e r C a s e ( ) ; d e f l o c = " h t t p : / / c h r o m e d r i v e r . s t o r a g e . g o o g l e a p i s . c o m / 2 . 2 0 " i f ( o s . c o n t a i n s ( ' m a c ' ) ) { r e t u r n " $ { l o c } / c h r o m e d r i v e r _ m a c 3 2 . z i p " } i f ( o s . c o n t a i n s ( ' w i n ' ) ) { r e t u r n " $ { l o c } / c h r o m e d r i v e r _ w i n 3 2 . z i p " } r e t u r n " $ { l o c } / c h r o m e d r i v e r _ l i n u x 6 4 . z i p " }
  • 86. 11 . 8 CHROME (2) GebConfig.groovy p r i v a t e v o i d d o w n l o a d D r i v e r ( F i l e f i l e , S t r i n g p a t h ) { i f ( ! f i l e . e x i s t s ( ) ) { d e f a n t = n e w A n t B u i l d e r ( ) a n t . g e t ( s r c : p a t h , d e s t : ' d r i v e r . z i p ' ) a n t . u n z i p ( s r c : ' d r i v e r . z i p ' , d e s t : f i l e . p a r e n t ) a n t . d e l e t e ( f i l e : ' d r i v e r . z i p ' ) a n t . c h m o d ( f i l e : f i l e , p e r m : ' 7 0 0 ' ) } }
  • 87. 11 . 9 CHROME (3) GebConfig.groovy d e f c h r o m e D r i v e r = n e w F i l e ( ' b u i l d / d r i v e r s / c h r o m e / c h r o m e d r i v e r ' ) d o w n l o a d D r i v e r ( c h r o m e D r i v e r , d r i v e r L o c a t i o n D e p e n d i n g O n O p e r a t i n g S y s t e m ( ) ) S y s t e m . s e t P r o p e r t y ( ' w e b d r i v e r . c h r o m e . d r i v e r ' , c h r o m e D r i v e r . a b s o l u t e P a t h ) d r i v e r = { d e f d r i v e r I n s t a n c e = n e w C h r o m e D r i v e r ( ) d e f b r o w s e r W i n d o w = d r i v e r I n s t a n c e . m a n a g e ( ) . w i n d o w ( ) / / w i d t h , h e i g h t b r o w s e r W i n d o w . s i z e = n e w D i m e n s i o n ( 1 0 0 0 , 2 5 0 0 ) b r o w s e r W i n d o w . p o s i t i o n = n e w P o i n t ( 0 , 0 ) d r i v e r I n s t a n c e }
  • 88. 11 . 10 WAITING GebConfig.groovy w a i t i n g { t i m e o u t = 1 0 r e t r y I n t e r v a l = 0 . 5 } b a s e N a v i g a t o r W a i t i n g = t r u e a t C h e c k W a i t i n g = t r u e
  • 89. 11 . 11 USING WAITING < d i v c l a s s = " f a d e - m e - i n " s t y l e = " d i s p l a y : n o n e " > H i - a r e y o w a i t i n g f o r m e ? < / d i v > < s c r i p t > $ ( ' d i v . f a d e - m e - i n ' ) . d e l a y ( 3 0 0 0 ) . s l i d e D o w n ( ) ; < / s c r i p t > s t a t i c c o n t e n t = { f a d e I n M e s s a g e { $ ( ' d i v . f a d e - m e - i n ' ) } } t h e n : w a i t F o r { f a d e I n M e s s a g e . t e x t ( ) = = ' H i - a r e y o w a i t i n g f o r m e ? ' }
  • 90. 11 . 12 PAUSING GEB p r i v a t e v o i d p a u s e ( ) { j s . e x e c " " " ( f u n c t i o n ( ) { w i n d o w . _ _ g e b P a u s e d = t r u e ; v a r d i v = d o c u m e n t . c r e a t e E l e m e n t ( " d i v " ) ; d i v . s e t A t t r i b u t e ( ' s t y l e ' , " p o s i t i o n : a b s o l u t e ; t o p : 0 p x ; z - i n d e x : 3 0 0 0 ; p a d d i n g : 1 0 p x ; b a c k g r o u n d - c o l o r : r e d ; ) ; v a r b u t t o n = d o c u m e n t . c r e a t e E l e m e n t ( " b u t t o n " ) ; b u t t o n . i n n e r H T M L = " U n p a u s e G e b " ; b u t t o n . o n c l i c k = f u n c t i o n ( ) { w i n d o w . _ _ g e b P a u s e d = f a l s e ; } d i v . a p p e n d C h i l d ( b u t t o n ) ; d o c u m e n t . g e t E l e m e n t s B y T a g N a m e ( " b o d y " ) [ 0 ] . a p p e n d C h i l d ( d i v ) ; } ) ( ) ; " " " w a i t F o r ( 3 0 0 ) { ! j s . _ _ g e b P a u s e d } }
  • 91. 11 . 1311 . 14 PAUSING GEB w h e n : p a u s e ( ) / / P a u s e G e b u n t i l b u t t o n p r e s s e d
  • 93. 12 . 2 TEST REPORTS Nicely formatted Spock power-assert format
  • 94. SCREENSHOTS Screenshots and HTML from end of each test: Extend from GebReportingSpec c l a s s A t t e n d e e F u n c t i o n a l S p e c e x t e n d s G e b R e p o r t i n g S p e c GebConfig.groovy r e p o r t s D i r = n e w F i l e ( " b u i l d / g e b - r e p o r t s " )
  • 95. 12 . 312 . 4 AD-HOC SCREENSHOTS r e p o r t " W h e n - f o r m - i s - j u s t - f i l l e d " Saves a report in reportsDir Numbered in increasing order
  • 96. 13 . 1 JAVASCRIPT In case you need to interact using javascript
  • 97. 13 . 2 EXECUTING JAVASCRIPT Clicking a button that is hidden will create a ElementNotVisibleException < f i e l d s e t c l a s s = " w e l l " s t y l e = " d i s p l a y : n o n e " > < g : l i n k c l a s s = " b t n " a c t i o n = " i n d e x " > L i s t < / g : l i n k > < / f i e l d s e t >
  • 98. 13 . 3 EXECUTING JAVASCRIPT J a v a s c r i p t E x e c u t o r e x e c u t o r = ( J a v a s c r i p t E x e c u t o r ) d r i v e r e x e c u t o r . e x e c u t e S c r i p t ( ' j Q u e r y ( " . w e l l " ) . s h o w ( ) ; ' )
  • 99. 13 . 4 WRAPPING JAVASCRIPT d e f j s ( S t r i n g s c r i p t ) { ( d r i v e r a s J a v a s c r i p t E x e c u t o r ) . e x e c u t e S c r i p t ( s c r i p t ) } j s ( ' j Q u e r y ( " . w e l l " ) . s h o w ( ) ; ' )
  • 100. 13 . 5 JQUERY SHORTHAND $ ( " d i v # a " ) . j q u e r y . m o u s e o v e r ( ) $ ( " # a " ) . j q u e r y . t r i g g e r ( ' m o u s e o v e r ' )
  • 101. 14 OTHER USAGES Screenscraping of a site Solving complex problems like 2048