These days I’m in between projects, so I decided to automate a task related to a web interface and a tedious list shaped as an HTML form. This automation would imply two processes: parsing an HTML page and filling some fields in another page, plus some small and simple processing.
I had two options, to use HTTP directly through HTTP Builder or something like that or to code various small scripts with Geb. Of course, I chose the latter.
A little bit of context
From its webpage:
Geb is a browser automation solution.
It brings together the power of WebDriver, the elegance of jQuery content selection, the robustness of Page Object modelling and the expressiveness of the Groovy language.
With a simple script, I can have a Firefox or Google Chrome webdriver (among others) up and running quickly, use jQuery-like selectors to traverse and modify the webpage DOM and process its information with all the power of Groovy.
And best of all, the dependencies are managed by Grape, so the only thing I need in any machine to run this scripts is Groovy itself.
Requirements
To run this examples, the only requirements needed are the Firefox Web Browser and the Groovy Runtime, version 2.X or greater.
Dependencies and Hello World
First of all, we need to add the dependencies to our script.
1 | 'org.gebish', module='geb-core', version='0.10.0') (group= |
Usually, the commons-logging
dependency is transitive to the other two and should be resolved automaticaly, but Groovy is unable to find the transitive version, so we put the one we found on Maven Central explicitly and problem solved.
When used inside a script, Geb works with a simple DSL notation. Our hello world script is going to drive the browser to the google webpage and fill the form with “Hello Geb!”.
1 | 'org.gebish', module='geb-core', version='0.10.0') (group= |
At this point, you can go to your terminal and run:
1 | groovy HelloWorld.groovy |
Selecting content
Geb uses jQuery-like selectors to access the content of the page through the $
function. This selectors return always a geb.navigator.Navigator
object that represents one or many elements on the page. This function can be used through the find
alias.
The signature of the $
function is
1 | $([CSS SELECTOR], [INDEX OR RANGE], [ATTRIBUTE / TEXT MATCHERS]) |
being all the arguments optional, so the following calls are valid
1 | $("#content h1") |
We can select again over a geb.navigator.Navigator
object, calling $
or find
again
1 | // <div class="a"> |
This selectors are iterable too
1 | // <p>Something</p> |
Handling forms
Geb provides us with tools to manage forms and input fields. Input fields have the method value()
that we can use to both get the current field value or set our own. Given this html
1 | // <form action="/" method="POST"> |
We can use value on elements of type input, select or textarea. If we try to set a value on a different type of element, we will get an UnableToSetElementException
exception.
To ease working with forms, we can use shortcuts on the Navigator
objects to access the form fields by their name
1 | // <form action="/" method="POST"> |
Special inputs like textarea, select, checkbox, etc. are accessed each one in its particular way. You can find each case explained in detail in the setting values section of the documentation.
Moving around
Among all the possible interactions that we have in Geb, one of the most important ones is the click. Navigator objects have a click()
method, that simply clicks on the first element of the navigator
1 | $("a").click() |
Geb has tools for waiting to some conditions to happen or some content to appear on the page. This is useful when following links, when interacting with the page or when working with timers.
The waitFor()
method allows us to wait a certain amount of time
1 | waitFor(10) |
and to wait for some closure to return a true object
1 | waitFor { title.contains("Search Results") } |
To finally close the browser, we use the quit()
method of the DSL
Geb and Javascript
If we use Geb with the DSL, we have a js
object to both interact with the data and execute code in Javascript.
Accessing variables
Any Javascript global varialbe is accesible by name
1 | // <html> |
we can even access nested variables
1 | assert js."document.title" == "My Webpage" |
Executing code
You can execute arbitrary javascript code through the js
object
1 | assert js.exec('return 1 + 1;') == 2 |
if you want to send arguments to the javascript snippet, they are the first in the exec()
signature
1 | assert js.exec(1, 2, 'arguments[0] + arguments[1];') == 3 |
Beyond the script
Geb is awesome to write simple and powerful scripts, but its power doesn’t stop there. If we need bigger and more complicated logic, Geb provides us with the Driver
and Page
classes and a lot of abstractions way more structured than a DSL to use.
Reach the manual or the API documentation if you want to find more and have fun with Groovy and Geb.