2. AGENDA
Functional testing
Geb - cudos and history
How Geb works
Geb and Ratpack, Grails 2 and 3
Browser support
Tips and Tricks
3. 2 . 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
8. 3 . 4
FUNCTIONAL TESTING
Ignores the specifics of the underlying so ware
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.
11. 4 . 2
GEB HISTORY
Started in November 2009
Created by Luke Daley
Current project lead Marcin Erdman
12. 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
13. 4 . 3
WEBDRIVER
Very active development
Stable API and feature set
Verbose
Low level
Not a complete solution
14. 4 . 4
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
17. 4 . 6
5 . 2
NAVIGATOR
The $()method returns a Navigator object
General format - Jquery like selecter syntax
$ ( < 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 > )
18. GEB SELECTORS (1)
/ / 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 )
19. 5 . 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 - " ) )
20. 5 . 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 ' )
21. 5 . 55 . 6
CSS SUPPORT
$ ( " t a b l e t r : n t h - c h i l d ( 2 n + 1 ) t d " )
22. RETRIVING INFORMATION
< p i d = " s a m p l e " c l a s s = " c l a s s - a c l a s s - b " t i t l e = " S a m p l e p e l e m e n t " >
S a m p l e t e x t
< / p >
$ ( " p " ) . t e x t ( ) = = " S a m p l e t e x t "
$ ( " # s a m p l e " ) . t a g ( ) = = " p "
$ ( " p " ) . @ t i t l e = = " S a m p l e p e l e m e n t "
$ ( " p " ) . c l a s s e s ( ) = = [ " c l a s s - a " , " c l a s s - b " ]
23. 5 . 7
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 ( )
}
24. 5 . 85 . 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 " )
25. 5 . 10
INTERACTION
Using ActionsAPI from WebDriver is possible.
But Geb provides the interactclosure
26. 5 . 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
}
27. 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 )
}
28. 5 . 12
MORE INTERACTION WITH FORMS
< 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 "
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 " )
29. 5 . 13
VARIABLES AVAILABLE
title
browser
currentUrl
currentWindow
30. 5 . 14
MORE POSSIBILITIES
Uploading files
Downloading files
Interacting with javascript
js object (Example later)
32. GEB STANDALONE EXAMPLE
Lets try to automate:
Searching for Greach Conference
Click the first link
Hopefully end up on the right homepage
33. 6 . 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 e a c h C o n f e r e n c e " )
$ ( ' 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 . s t a r t s W i t h " G r e a c h " }
35. SCENARIO
Lets test a small todo application
Lets test the following
1. Goto list of todos
2. Create new item
3. Delete item again
36. 7 . 27 . 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 T o d o 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
}
37. GEB SPEC (1)
The naive inmaintainable way!
d e f " G o t o i n d e x p a g e " ( ) {
w h e n : ' G o t o i n d e x u r l '
g o ' / '
t h e n : ' V e r i f y w e a r e t h e r e '
t i t l e = = " T o d o L i s t "
}
38. 7 . 4
GEB SPEC (2)
The naive inmaintainable way!
d e f " C r e a t e n e w t o d o " ( ) {
w h e n : ' I n p u t t e x t a n d s u b m i t '
$ ( " # n e w - t o d o " ) < < " D o t h i s "
$ ( " # c r e a t e - b t n " ) . c l i c k ( )
t h e n : ' V e r i f y n e w i t e m p r e s e n t i n l i s t '
w a i t F o r { $ ( " # c o u n t " ) . t e x t ( ) = = ' 4 ' }
$ ( ' l i . t o d o - i t e m ' ) . a n y { i t . t e x t ( ) . c o n t a i n s ' D o t h i s ' }
a n d : ' V e r i f y i n p u t f i e l d e m p t y '
! $ ( " # n e w - t o d o " ) . t e x t ( )
}
39. 7 . 5
GEB SPEC (3)
The naive inmaintainable way!
d e f " D e l e t e t o d o i t e m " ( ) {
w h e n : ' C l i c k d e l e t e a n d a c c e p t '
w i t h C o n f i r m {
$ ( ' b u t t o n ' , 4 ) . c l i c k ( )
}
t h e n : ' V e r i f y i t e m d e l e t e d '
w a i t F o r { $ ( " # c o u n t " ) . t e x t ( ) = = ' 3 ' }
$ ( ' l i . t o d o - i t e m ' ) . e v e r y { ! ( i t . t e x t ( ) . c o n t a i n s ( ' D o t h i s ' ) ) }
}
40. 7 . 68 . 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
43. 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
44. 8 . 4
PAGE OBJECTS
p a c k a g e n e t . g r y d e s k e . g r e a c h . p a g e s
i m p o r t g e b . P a g e
c l a s s A b o u t 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 b o u t "
s t a t i c a t = {
t i t l e = = " A b o u t "
}
s t a t i c c o n t e n t = {
h e a d e r { $ ( ' h 1 ' , 0 ) }
}
}
45. 8 . 58 . 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 " ) }
}
47. MODULES ACROSS PAGES
p a c k a g e n e t . g r y d e s k e . g r e a c h . m o d u l e s
i m p o r t g e b . M o d u l e
c l a s s M e n u 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 { $ ( ' a ' , t e x t : ' T o d o L i s t ' ) }
a b o u t { $ ( ' a ' , t e x t : ' A b o u t ' ) }
}
}
48. 8 . 8
MODULES FOR REPEATED CONTENT
p a c k a g e n e t . g r y d e s k e . g r e a c h . m o d u l e s
i m p o r t g e b . M o d u l e
c l a s s T o d o 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 = {
c h e c k b o x { $ ( ' i n p u t ' , t y p e : ' c h e c k b o x ' ) }
l a b e l { $ ( ' l a b e l ' ) . t e x t ( ) }
d e l e t e B t n { $ ( ' b u t t o n ' ) }
}
}
49. 8 . 98 . 10
USING MODULES
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 M e n u b a r M o d u l e }
t o d o s ( r e q u i r e d : f a l s e ) {
$ ( ' l i . t o d o - i t e m ' ) . m o d u l e L i s t ( T o d o I t e m M o d u l e )
}
}
50. 8 . 11
GEB SPEC - STRUCTURED
Lets try to restructure the ugly spec from before
51. 8 . 12
GEB SPEC - STRUCTURED (1)
d e f " G o t o i n d e x p a g e " ( ) {
w h e n : ' G o t o i n d e x u r l '
t o I n d e x P a g e
t h e n : ' V e r i f y 3 i t e m s p r e s e n t '
a t I n d e x P a g e
c o u n t V a l u e = = ' 3 '
}
52. GEB SPEC - STRUCTURED (2)
d e f " C r e a t e n e w t o d o " ( ) {
w h e n : ' I n p u t t e x t a n d s u b m i t '
t o d o I n p u t = " D o t h i s "
t o d o S u b m i t . c l i c k ( )
t h e n : ' V e r i f y n e w i t e m p r e s e n t i n l i s t '
w a i t F o r { c o u n t V a l u e = = ' 4 ' }
t o d o s . a n y { i t . l a b e l = = ' D o t h i s ' }
a n d : ' V e r i f y i n p u t f i e l d e m p t y '
! t o d o I n p u t . t e x t ( )
}
53. 8 . 13
GEB SPEC - STRUCTURED (3)
d e f " D e l e t e t o d o i t e m " ( ) {
w h e n : ' C l i c k d e l e t e a n d a c c e p t '
w i t h C o n f i r m {
t o d o s . f i n d { i t . l a b e l = = ' D o t h i s ' } . d e l e t e B t n . c l i c k ( )
}
t h e n : ' V e r i f y i t e m d e l e t e d '
w a i t F o r { c o u n t V a l u e = = ' 3 ' }
t o d o s . e v e r y { i t . l a b e l ! = ' D o t h i s ' }
}
54. 8 . 14
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
}
}
55. 8 . 15
STANDALONE REVISITED
c l a s s D u c k D u c k G o R e s u l t 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 = { $ ( " # l i n k s " ) . d i s p l a y e d }
s t a t i c c o n t e n t = {
l i n k s { $ ( " h 2 . r e s u l t _ _ t i t l e " ) }
}
d e f c l i c k L i n k ( i n t l i n k N u m b e r ) {
l i n k s [ l i n k N u m b e r ] . c l i c k ( )
}
}
56. 8 . 168 . 17
STANDALONE REVISITED
c l a s s G r e a c h P a g e e x t e n d s g e b . P a g e {
s t a t i c a t = { t i t l e . s t a r t s W i t h ( " G r e a c h " ) }
}
57. STANDALONE REVISITED
b r o w s e r . w i t h {
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 e a c h C o n f e r e n c e "
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 e a c h P a g e
}
}
59. GEB WITH RATPACK
d e p e n d e n c i e s {
. . .
/ / I f u s i n g S p o c k , n e e d t o d e p e n d o n g e b - s p o c k
t e s t C o m p i l e " o r g . g e b i s h : g e b - s p o c k : 0 . 1 3 . 1 "
t e s t C o m p i l e " o r g . s p o c k f r a m e w o r k : s p o c k - c o r e : 1 . 0 - g r o o v y - 2 . 4 "
/ / N e e d a d r i v e r i m p l e m e n t a t i o n
t e s t 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 . 5 3 . 0 "
)
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 - s u p p o r t : 2 . 5 3 . 0 "
)
}
60. 9 . 29 . 3
GEB WITH RATPACK
@ S h a r e d
d e f a u t = n e w G r o o v y R a t p a c k M a i n A p p l i c a t i o n U n d e r T e s t ( )
d e f s e t u p ( ) {
U R I b a s e = a u t . a d d r e s s
b r o w s e r . b a s e U r l = b a s e . t o S t r i n g ( )
}
61. 9 . 4
INTERACTING WITH RATPACK
APPLICATION
When some functionality is needed that is not exposed
through the browser, it can be necessary to interact with the
application under test.
62. 9 . 5
INTERACTING WITH RATPACK
Include in build.gradle
d e p e n d e n c i e s {
. . .
c o m p i l e r a t p a c k . d e p e n d e n c y ( " r e m o t e " )
t e s t C o m p i l e r a t p a c k . d e p e n d e n c y ( " r e m o t e - t e s t " )
. . .
63. INTERACTING WITH RATPACK
@ S h a r e d
d e f a u t = n e w G r o o v y R a t p a c k M a i n A p p l i c a t i o n U n d e r T e s t ( )
R e m o t e C o n t r o l r e m o t e C o n t r o l
d e f s e t u p ( ) {
U R I b a s e = a u t . a d d r e s s
b r o w s e r . b a s e U r l = b a s e . t o S t r i n g ( )
r e m o t e C o n t r o l = n e w R e m o t e C o n t r o l ( a u t )
}
64. 9 . 6
INTERACTING WITH RATPACK
d e f " C o m p l e t e i t e m a n d c h e c k d a t a b a s e " ( ) {
w h e n : ' C h e c k i t e m d o n e '
t o d o s . f i n d { i t . l a b e l = = ' G i v e G e b p r e s e n t a t i o n ' }
. c h e c k b o x . c l i c k ( )
t h e n : ' U s e r e m o t e c o n t r o l t o c h e c k d a t a b a s e '
r e m o t e C o n t r o l . e x e c {
B o o l e a n c o m p l e t e d
T o d o I t e m . w i t h N e w S e s s i o n {
T o d o I t e m t o d o I t e m = T o d o I t e m
. f i n d B y T e x t ( ' G i v e G e b p r e s e n t a t i o n ' )
c o m p l e t e d = t o d o I t e m . c o m p l e t e d
}
c o m p l e t e d
} = = t r u e
}
65. 9 . 7
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 . 5 3 . 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 . 5 3 . 0 " )
t e s t " o r g . g e b i s h : g e b - s p o c k : 0 . 1 2 . 1 "
}
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 2 . 1 "
}
66. 9 . 89 . 9
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 :
67. 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 "
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 7 . 1 "
)
t e s t R u n t i m e " n e t . s o u r c e f o r g e . h t m l u n i t : h t m l u n i t : 2 . 1 8 "
}
68. 9 . 10
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
69. 9 . 11
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 D e m o 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 "
}
}
70. 9 . 12
INTERACTING WITH 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 "
71. 9 . 139 . 14
INTERACTING WITH GRAILS 3.0
Application is in same jvm
Interaction is possible directly
Tests run as integration tests
72. 9 . 15
INTERACTING WITH GRAILS 3.0
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 ( )
}
}
74. 10 . 2
GEBCONFIG
Configuration for Geb is placed in GebConfig.groovy
It must be placed in default package scope
http://www.gebish.org/manual/current/configuration.html
77. 10 . 410 . 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 '
78. 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
}
79. 10 . 610 . 7
CHROME
Needs ChromeDriver downloaded
Pretty fast and stable
80. 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 "
}
81. 10 . 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 ' )
}
}
82. 10 . 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
}
84. SAUCELABS
GebConfig.groovy
i m p o r t g e b . d r i v e r . S a u c e L a b s D r i v e r F a c t o r y
d e f s l B r o w s e r = S y s t e m . g e t P r o p e r t y ( " g e b . s a u c e l a b s . b r o w s e r " )
i f ( s l B r o w s e r ) {
d r i v e r = {
d e f u s e r n a m e = S y s t e m . g e t e n v (
" G E B _ S A U C E _ L A B S _ U S E R " )
a s s e r t u s e r n a m e
d e f a c c e s s K e y = S y s t e m . g e t e n v (
" G E B _ S A U C E _ L A B S _ A C C E S S _ P A S S W O R D " )
a s s e r t a c c e s s K e y
n e w S a u c e L a b s D r i v e r F a c t o r y ( ) . c r e a t e (
s a u c e L a b s B r o w s e r , u s e r n a m e , a c c e s s K e y )
}
}
85. 10 . 12
SAUCELABS
build.gradle
a p p l y p l u g i n : " g e b - s a u c e l a b s "
r e p o s i t o r i e s {
. . .
m a v e n C e n t r a l ( )
}
d e p e n d e n c i e s {
. . .
s a u c e C o n n e c t " c o m . s a u c e l a b s : c i - s a u c e : 1 . 1 1 3 "
}
86. 10 . 13
SAUCELABS
s a u c e L a b s {
b r o w s e r s {
f i r e f o x _ l i n u x _ 1 9
d e l e g a t e . " i n t e r n e t e x p l o r e r _ v i s t a _ 9 "
n e x u s 4 {
c a p a b i l i t i e s (
b r o w s e r N a m e : " a n d r o i d " , p l a t f o r m : " L i n u x " ,
v e r s i o n : " 4 . 4 " , d e v i c e N a m e : " L G N e x u s 4 "
)
} }
t a s k {
t e s t C l a s s e s D i r = t e s t . t e s t C l a s s e s D i r
t e s t S r c D i r s = t e s t . t e s t S r c D i r s
c l a s s p a t h = t e s t . c l a s s p a t h
}
a c c o u n t {
u s e r n a m e = " u s e r n a m e "
a c c e s s K e y = " a p i - k e y "
}
c o n n e c t {
/ / p o r t = 4 4 4 4
/ / a d d i t i o n a l O p t i o n s = [ ' - - p r o x y ' , ' p r o x y . e x a m p l e . c o m : 8 0 8 0 ' ]
} }
87. 10 . 1411 . 1
JAVASCRIPT
In case you need to interact using javascript
88. 11 . 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 " >
< a h r e f = " / l i s t " c l a s s = " b t n " > L i s t < / a >
< / f i e l d s e t >
89. 11 . 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 ( ) ; ' )
90. 11 . 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 ( ) ; ' )
91. 11 . 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 ' )
93. 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
94. 12 . 2
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 ? '
}
95. 12 . 3
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 ; r i g h t : 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 }
}
96. 12 . 412 . 5
PAUSING GEB
w h e n : ' D e m o i n g p a u s e '
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
99. 13 . 2
TEST REPORTS
Nicely formatted
Spock power-assert format
100. 13 . 3
SPOCK REPORTS
Take a look at pluginSpock Reports
t e s t C o m p i l e ( ' c o m . a t h a y d e s : s p o c k - r e p o r t s : 1 . 2 . 1 0 ' ) {
/ / t h i s a v o i d s a f f e c t i n g y o u r v e r s i o n o f G r o o v y / S p o c k
t r a n s i t i v e = f a l s e
}
103. 13 . 4
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 " )
r e p o r t O n T e s t F a i l u r e O n l y = t r u e
104. 13 . 513 . 613 . 7
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