ifndef::snippets-dir[]
:snippets-dir: ../../../../manual-snippets/src/test/groovy
:rb-snippets-dir: ../../../../manual-snippets/real-browser/src/test/groovy
endif::[]
= Introduction

Geb (pronounced "`jeb`" and originally a contraction of "`Groovy web`") is a developer focused tool for automating the interaction between web browsers and web content.
It uses the dynamic language features of {groovy} to provide a powerful content definition DSL (for modelling content for reuse) and key concepts from {jquery} to provide a powerful content
inspection and traversal API (for finding and interacting with content).

Geb was born out of a desire to make browser automation (originally for web testing) easier and more productive.
It aims to be a *developer tool* in that it allows and encourages the using of programming and language constructs instead of creating a restricted environment.
It uses Groovy's dynamism to remove the noise and boilerplate code in order to focus on what's important — the content and interaction.

== The browser automation technology

Geb builds on the {webdriver} browser automation library, which means that Geb can work with
link:https://www.selenium.dev/documentation/webdriver/browsers/[any browser that WebDriver can].
While Geb provides an extra layer of convenience and productivity, it is always possible to "`drop down`" to the WebDriver level to do something directly should you need to.

For more information see the manual section on link:#driver[using a driver implementation].

== The Page Object pattern

The Page Object Pattern gives us a common sense way to model content in a reusable and maintainable way.
From the link:https://www.selenium.dev/documentation/test_practices/encouraged/page_object_models/[Selenium documentation on the Page Object Pattern]:

____

Within your web app's UI, there are areas where your tests interact with.
A Page Object only models these as objects within the test code.
This reduces the amount of duplicated code and means that if the UI changes, the fix needs only to be applied in one place.

____

Furthermore (from the same document):

____

PageObjects can be thought of as facing in two directions simultaneously.
Facing toward the developer of a test, they represent the services offered by a particular page.
Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page) It's simplest to think of the methods on a
Page Object as offering the "`services`" that a page offers rather than exposing the details and mechanics of the page.
As an example, think of the inbox of any web-based email system.
Amongst the services it offers are the ability to compose a new email, choose to read a single email, and list the subject lines of the emails in the inbox.
How these are implemented shouldn't matter to the test.

____

The Page Object Pattern is an important technique, and Geb provides first class support via its <<pages,page>> and <<modules,module>> constructs.

== The jQuery-ish navigator API

The {jquery} JavaScript library provides an excellent API for (among other things) selecting or targeting content on a page and traversing through and around content. Geb takes a lot of inspiration from this.

In Geb, content is selected through the `$` function, which returns a `{navigator-api}` object.
A `Navigator` object is in someways analogous to the `jQuery` data type in jQuery in that it represents one or more targeted elements on the page.

Let's see some examples:

[source,groovy,indent=0]
----
include::{snippets-dir}/intro/IntroSamplesSpec.groovy[tags=dollar_examples]
----
<1> Match all `div` elements on the page.
<2> Match the first `div` element on the page.
<3> Match all `div` elements with a title attribute value of `section`.
<4> Match the first `div` element with a title attribute value of `section`.
<5> Match all `div` elements who have the class `main`.
<6> Match the first `div` element with the class `main`.


These methods return `Navigator` objects that can be used to further refine the content.

[source,groovy,indent=0]
----
include::{snippets-dir}/intro/IntroSamplesSpec.groovy[tags=refining_content]
----
<1> The parent of the first paragraph.
<2> All tables with a cellspacing attribute value of 0 that are nested in a paragraph.

This is just the beginning of what is possible with the Navigator API. See the <<navigator,chapter on the navigator>> for more details.

== Full examples

Let's have a look at a simple case of going to Geb's home page and navigating to the latest version of this manual.

=== Inline scripting

Here's an example of using Geb in an inline (i.e. no page objects or predefined content) scripting style...

[source,groovy]
----
include::{rb-snippets-dir}/intro/ScriptingSpec.groovy[tags=imports,indent=0]

include::{rb-snippets-dir}/intro/ScriptingSpec.groovy[tags=inline,indent=0]
----
<1> Check that we are at Geb's homepage.
<2> Click on the manual menu entry to open it.
<3> Wait for the menu open animation to finish.
<4> Click on the first link to a manual.
<5> Check that we are at The Book of Geb.

=== Scripting with Page Objects

This time let us define our content up front using the Page Object pattern...

[source,groovy]
----
include::{rb-snippets-dir}/intro/module/ManualsMenuModule.groovy[tags=imports,indent=0]
include::{rb-snippets-dir}/intro/page/GebHomePage.groovy[tags=imports,indent=0]

include::{rb-snippets-dir}/intro/module/ManualsMenuModule.groovy[tags=class,indent=0]

include::{rb-snippets-dir}/intro/page/GebHomePage.groovy[tags=class,indent=0]

include::{rb-snippets-dir}/intro/page/TheBookOfGebPage.groovy[tags=class,indent=0]
----
<1> Modules are reusable fragments that can be used across pages. Here we are using a module to model a dropdown menu.
<2> Content DSL.
<3> Content definitions can use other content definitions to define relative content elements.
<4> Modules can contain methods that allow to hide document structure details or interaction complexity.
<5> Pages can define their location, either absolute or relative to a base.
<6> "`at checkers`" allow verifying that the browser is at the expected page.
<7> Include the previously defined module.

Now our script again, using the above defined content...

[source,groovy]
----
include::{rb-snippets-dir}/intro/ScriptingSpec.groovy[tags=imports,indent=0]

include::{rb-snippets-dir}/intro/ScriptingSpec.groovy[tags=using_page_objects,indent=0]
----
<1> Go to the url defined by `GebHomePage` and also verify it's "`at checker`".

[[testing-intro]]
=== Testing

Geb itself does not include any kind of testing or execution framework.
Rather, it works with existing popular tools like {spock}, {junit}, {testng} and {cucumber-jvm}. While Geb works well with all of these test tools, we encourage the use of {spock} as it's a great match for Geb with its focus and style.

Here is our Geb homepage case again, this time using Geb's {spock} integration...

[source,groovy]
----
include::{rb-snippets-dir}/intro/GebHomepageSpec.groovy[tags=imports,indent=0]

include::{rb-snippets-dir}/intro/GebHomepageSpec.groovy[tags=class,indent=0]
----

For more information on using Geb for web and functional testing, see the <<testing,testing chapter>>.

== Installation &amp; usage

Geb itself is available as a single link:https://central.sonatype.com/search?q=g%3{geb-group}+a%3Ageb-core[`geb-core` jar from the Maven Central repository]. To get up and running you simply need this jar, a WebDriver driver implementation and the `selenium-support` jar.

Via `@Grab`...

[source,groovy,subs="+attributes"]
----
@Grab("{geb-group}:geb-core:{geb-version}")
@Grab("org.seleniumhq.selenium:selenium-firefox-driver:{selenium-version}")
import geb.Browser
----

Via Maven...

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>{geb-group}</groupId>
  <artifactId>geb-core</artifactId>
  <version>{geb-version}</version>
</dependency>
<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-firefox-driver</artifactId>
  <version>{selenium-version}</version>
</dependency>
----

Via Gradle...

[source,groovy,subs="+attributes"]
----
testImplementation("{geb-group}:geb-core:{geb-version}")
testImplementation("org.seleniumhq.selenium:selenium-firefox-driver:{selenium-version}")
----

Alternatively, if using an integration such as `geb-spock` or `geb-junit4` you can depend on that instead of `geb-core`. You can check out link:https://central.sonatype.com/search?q=g%3A{geb-group}[the listing of all artifacts in `{geb-group}` group] to see what's available.

[TIP]
====
Be sure to check the chapter on <<build-integrations, build integrations>> for information on using Geb with particular environments.
====

:numbered!:

=== Snapshot repository

If you fancy living on the bleeding edge then you can try out Geb's snapshot artifacts located in the link:https://repository.apache.org/content/repositories/snapshots/{geb-group-dir}/[Apache Snapshot repository] at https://repository.apache.org/content/repositories/snapshots.

NOTE: Snapshots are not official Apache releases and
are intended for the developer community to test upcoming releases.

:numbered:
