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
Geb for Testing Your Grails Application  GR8Conf India 2016
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
Geb for Testing Your Grails Application  GR8Conf India 2016
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

PPTX
Representing Material Culture Online: Historic Clothing in Omeka
PDF
TypeScriptใงๆ›ธใAngularJS @ GDG็ฅžๆˆธ2014.8.23
PDF
ใƒขใƒ€ใƒณAngularJS @ GDGไธญๅ›ฝ2014.12.6
TXT
Wsomdp
PDF
PHP Backdoor: The rise of the vuln
PDF
Testing TYPO3 Applications
PDF
Php web backdoor obfuscation
PDF
R57php 1231677414471772-2
ย 
Representing Material Culture Online: Historic Clothing in Omeka
TypeScriptใงๆ›ธใAngularJS @ GDG็ฅžๆˆธ2014.8.23
ใƒขใƒ€ใƒณAngularJS @ GDGไธญๅ›ฝ2014.12.6
Wsomdp
PHP Backdoor: The rise of the vuln
Testing TYPO3 Applications
Php web backdoor obfuscation
R57php 1231677414471772-2
ย 

What's hot (20)

PDF
ZeroMQ: Messaging Made Simple
PDF
Semantic Web & TYPO3
PDF
Code obfuscation, php shells & more
PDF
Crรฉer une base NoSQL en 1 heure
PDF
Malcon2017
PDF
ZeroMQ Is The Answer
PDF
Speeding up Red Team engagements with carnivorall
PDF
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
PDF
Using Phing for Fun and Profit
TXT
Pop3ck sh
PPTX
Ch3(working with file)
PDF
Service intergration
TXT
Inc
PDF
The Perl6 Type System
PPTX
Introduction to Guzzle
ย 
PPTX
Dropping ACID with MongoDB
PPTX
API Pain Points (PHPNE)
PDF
Perl 6 for Concurrency and Parallel Computing
PDF
PHP Secure Programming
ZeroMQ: Messaging Made Simple
Semantic Web & TYPO3
Code obfuscation, php shells & more
Crรฉer une base NoSQL en 1 heure
Malcon2017
ZeroMQ Is The Answer
Speeding up Red Team engagements with carnivorall
Security: The Great WordPress Lockdown - WordCamp Melbourne - February 2011
Using Phing for Fun and Profit
Pop3ck sh
Ch3(working with file)
Service intergration
Inc
The Perl6 Type System
Introduction to Guzzle
ย 
Dropping ACID with MongoDB
API Pain Points (PHPNE)
Perl 6 for Concurrency and Parallel Computing
PHP Secure Programming
Ad

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

PDF
Geb for browser automation
PDF
www.webre24h.com - [O`reilly] javascript cookbook - [powers]
PPTX
Agile NCR 2013 - Gaurav Bansal- web_automation
PDF
jQuery Rescue Adventure
PDF
Testing Web Applications with GEB
PDF
jQuery Introduction
PDF
mobl presentation @ IHomer
PDF
Geb for testing your grails application
PDF
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
PDF
Download full ebook of (Ebook) learning javascript 3e by kan instant download...
PDF
HTML5: Building the Next Generation of Web Applications
PDF
DEF CON 27 - JUNYU ZHOU and CE QUIN and JIANING WANG - web2 own attacking des...
KEY
An in-depth look at jQuery
PDF
Html5, css3 y js
PDF
Opa hackathon
PDF
Taming Functional Web Testing with Spock and Geb
ย 
KEY
JavaScript Neednt Hurt - JavaBin talk
PDF
Software Language Design & Engineering: Mobl & Spoofax
PDF
Model-Driven Software Development - Strategies for Design & Implementation of...
PDF
Strategies for Design & Implementation of Domain-Specific Languages
Geb for browser automation
www.webre24h.com - [O`reilly] javascript cookbook - [powers]
Agile NCR 2013 - Gaurav Bansal- web_automation
jQuery Rescue Adventure
Testing Web Applications with GEB
jQuery Introduction
mobl presentation @ IHomer
Geb for testing your grails application
BDD, ATDD, Page Objects: The Road to Sustainable Web Testing
Download full ebook of (Ebook) learning javascript 3e by kan instant download...
HTML5: Building the Next Generation of Web Applications
DEF CON 27 - JUNYU ZHOU and CE QUIN and JIANING WANG - web2 own attacking des...
An in-depth look at jQuery
Html5, css3 y js
Opa hackathon
Taming Functional Web Testing with Spock and Geb
ย 
JavaScript Neednt Hurt - JavaBin talk
Software Language Design & Engineering: Mobl & Spoofax
Model-Driven Software Development - Strategies for Design & Implementation of...
Strategies for Design & Implementation of Domain-Specific Languages
Ad

Recently uploaded (20)

PPTX
Internet___Basics___Styled_ presentation
PPTX
Funds Management Learning Material for Beg
PPTX
international classification of diseases ICD-10 review PPT.pptx
PDF
Unit-1 introduction to cyber security discuss about how to secure a system
PDF
WebRTC in SignalWire - troubleshooting media negotiation
PDF
SASE Traffic Flow - ZTNA Connector-1.pdf
PPTX
INTERNET------BASICS-------UPDATED PPT PRESENTATION
PDF
Tenda Login Guide: Access Your Router in 5 Easy Steps
PPTX
Job_Card_System_Styled_lorem_ipsum_.pptx
PDF
Automated vs Manual WooCommerce to Shopify Migration_ Pros & Cons.pdf
PPTX
Introduction to Information and Communication Technology
PDF
The New Creative Director: How AI Tools for Social Media Content Creation Are...
PDF
๐Ÿ’ฐ ๐”๐Š๐“๐ˆ ๐Š๐„๐Œ๐„๐๐€๐๐†๐€๐ ๐Š๐ˆ๐๐„๐‘๐Ÿ’๐ƒ ๐‡๐€๐‘๐ˆ ๐ˆ๐๐ˆ ๐Ÿ๐ŸŽ๐Ÿ๐Ÿ“ ๐Ÿ’ฐ
ย 
PDF
Triggering QUIC, presented by Geoff Huston at IETF 123
ย 
PPT
tcp ip networks nd ip layering assotred slides
PDF
Paper PDF World Game (s) Great Redesign.pdf
PPTX
presentation_pfe-universite-molay-seltan.pptx
PDF
Decoding a Decade: 10 Years of Applied CTI Discipline
PDF
RPKI Status Update, presented by Makito Lay at IDNOG 10
ย 
PPTX
Introuction about ICD -10 and ICD-11 PPT.pptx
Internet___Basics___Styled_ presentation
Funds Management Learning Material for Beg
international classification of diseases ICD-10 review PPT.pptx
Unit-1 introduction to cyber security discuss about how to secure a system
WebRTC in SignalWire - troubleshooting media negotiation
SASE Traffic Flow - ZTNA Connector-1.pdf
INTERNET------BASICS-------UPDATED PPT PRESENTATION
Tenda Login Guide: Access Your Router in 5 Easy Steps
Job_Card_System_Styled_lorem_ipsum_.pptx
Automated vs Manual WooCommerce to Shopify Migration_ Pros & Cons.pdf
Introduction to Information and Communication Technology
The New Creative Director: How AI Tools for Social Media Content Creation Are...
๐Ÿ’ฐ ๐”๐Š๐“๐ˆ ๐Š๐„๐Œ๐„๐๐€๐๐†๐€๐ ๐Š๐ˆ๐๐„๐‘๐Ÿ’๐ƒ ๐‡๐€๐‘๐ˆ ๐ˆ๐๐ˆ ๐Ÿ๐ŸŽ๐Ÿ๐Ÿ“ ๐Ÿ’ฐ
ย 
Triggering QUIC, presented by Geoff Huston at IETF 123
ย 
tcp ip networks nd ip layering assotred slides
Paper PDF World Game (s) Great Redesign.pdf
presentation_pfe-universite-molay-seltan.pptx
Decoding a Decade: 10 Years of Applied CTI Discipline
RPKI Status Update, presented by Makito Lay at IDNOG 10
ย 
Introuction about ICD -10 and ICD-11 PPT.pptx

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
  • 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
  • 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