ifndef::snippets-dir[]
:snippets-dir: ../../../../manual-snippets/src/test/groovy
:rb-snippets-dir: ../../../../manual-snippets/real-browser/src/test/groovy
:cm-snippets-dir: ../../../../../module/geb-core/src/main/groovy
:ct-snippets-dir: ../../../../../module/geb-core/src/test/groovy
endif::[]
[[testing]]
= Testing

Geb provides first class support for functional web testing via integration with popular testing frameworks such as {spock}, {junit}, {testng} and {cucumber-jvm}.

[[spock-junit-testng]]
== Spock, JUnit &amp; TestNG

The Spock, JUnit and TestNG integrations work fundamentally the same way.
They provide superclasses that setup a `{browser-api}` instance that all method calls and property accesses/references resolve against via Groovy's `methodMissing` and `propertyMissing` mechanism.
These superclasses are just a thin layer on top of `{geb-test-manager-api}` and utilize an AST transformation registered using `{dynamically-dispatches-to-browser-api}` annotation to implement dynamic method and property dispatching onto the instance of `{browser-api}`.
If the provided superclasses are inconvenient to use, or you wish to use a testing framework for which an integration is not provided out of the box then it's highly recommended to use `{geb-test-manager-api}` together with `{dynamically-dispatches-to-browser-api}` when implementing your custom integration.
Taking a look at the code of the superclasses providing the built-in support for test frameworks is a good starting point when undertaking implementation of a custom integration.

[TIP]
====
Recall that the browser instance also forwards any method calls or property accesses/references that it can't handle to its current page object, which helps to remove a lot of noise from the test.
====

Consider the following Spock spec...

[source,groovy]
----
include::{snippets-dir}/testing/FunctionalSpec.groovy[tag=concise,indent=0]
----

Which is equivalent to...

[source,groovy]
----
include::{snippets-dir}/testing/FunctionalSpec.groovy[tag=verbose,indent=0]
----

=== Configuration

The browser instance is created by the testing integrations via use of `{geb-test-manager-api}`. The <<configuration, configuration mechanism>> allows you to control aspects such as the driver implementation and base URL.

[[testing-reporting]]
=== Reporting

The Spock, JUnit and TestNG integrations also ship a superclass (the name of the class for each integration module is provided below) that automatically takes reports with the label "`failure`" if a test fails.
They also set the <<report-group, report group>> to the name of the test class (substituting "`.`" with "`/`").

The `{browser-report-method-api}` browser method is replaced with a specialised version.
This method works the same as the browser method, but adds counters and the current test method name as prefixes to the given label.

[source,groovy]
----
include::{snippets-dir}/testing/ReportingFunctionalSpec.groovy[tag=example,indent=0]
----
<1> Take a report of the login screen.

Assuming a configured `reportsDir` of `reports/geb` and the default reporters (i.e. `{screenshot-reporter-api}` and `{page-source-reporter-api}`), we would find the following files:

* `reports/geb/my/tests/LoginSpec/001-001-login-login screen.html`
* `reports/geb/my/tests/LoginSpec/001-001-login-login screen.png`

If the assertion on the title fails then the following files would be generated as well:

* `reports/geb/my/tests/LoginSpec/001-002-login-failure.html`
* `reports/geb/my/tests/LoginSpec/001-002-login-failure.png`

The report file name format is:

----
«test method number»-«report number in test method»-«test method name»-«label».«extension»
----

Reporting is an extremely useful feature and can help you diagnose test failures much easier.
Wherever possible, favour the use of the auto-reporting base classes.

[[cookie-management-in-tests]]
=== Cookie management

`{geb-test-manager-api}` and thus also the Spock, JUnit and TestNG built-in integrations will automatically clear the browser's cookies for the current domain at the end of each test method.
This happens when `GebTestManager.afterTest()` is called unless `GebTestManager.resetBrowserAfterEachTestPredicate` evaluates to `false` like it does for `@Stepwise` Spock specifications - in such case cookie clearing happens in `GebTestManager.afterTestClass()` (meaning that all feature methods in a stepwise spec share the same browser state).

This auto-clearing of cookies can be <<auto-clearing-cookies-configuration, disabled via configuration>>.

If you need to clear cookies in multiple domains you will need to manually track the urls and call `{browser-clear-cookies-urls-api}`.

[[web-storage-management-in-tests]]
=== Web storage management

`{geb-test-manager-api}` and thus also the Spock, JUnit and TestNG built-in integrations can be <<auto-clearing-web-storage-configuration, configured>> to automatically clear the browser's web storage, that is both local and session storage, for the current domain at the end of each test method.
This happens when `GebTestManager.afterTest()` is called unless `GebTestManager.resetBrowserAfterEachTestPredicate` evaluates to `false` like it does for `@Stepwise` Spock specifications - in such case cookie clearing happens in `GebTestManager.afterTestClass()` (meaning that all feature methods in a stepwise spec share the same browser state).

=== Restarting the browser mid-test

Should you ever wish to restart the browser mid-test you have to be aware that there are two layers of caching of the driver instance within Geb's testing support.
Firstly the lazy initialised `Browser` instance stored as a field in the `{geb-test-manager-api}` instance held by base classes providing support for various test frameworks holds a reference to a `WebDriver` instance - you will therefore need to call the `resetBrowser()` method on the `{geb-test-manager-api}` instance to clear that field.
Secondly, Geb caches `WebDriver` instances by default as described in the section about <<implicit-driver-lifecycle, implicit driver lifecycle>>. To clear the cache and quit the browser you will need to call `{clear-browser-cache-and-quit-api}`.

Therefore, you can use the following code within a test to restart the browser:
[source,groovy]
----
include::{snippets-dir}/testing/BrowserRestartSpec.groovy[tag=restart,indent=0]
----

=== JAR and class names

The following table illustrates the specific JARs and class names for various test frameworks that Geb integrates with.

|===
|Framework |JAR |Base Class |Reporting Base Class

|Spock |https://mvnrepository.com/artifact/{geb-group}/geb-spock[geb-spock] |link:api/geb/spock/GebSpec.html[`geb.spock.GebSpec`] |link:api/geb/spock/GebReportingSpec.html[`geb.spock.GebReportingSpec`]
|JUnit 4 |https://mvnrepository.com/artifact/{geb-group}/geb-junit4[geb-junit4] |link:api/geb/junit4/GebTest.html[`geb.junit4.GebTest`] |link:api/geb/junit4/GebReportingTest.html[`geb.junit4.GebReportingTest`]
|JUnit 5 |https://mvnrepository.com/artifact/{geb-group}/geb-junit5[geb-junit5] |link:api/geb/junit5/GebTest.html[`geb.junit5.GebTest`] |link:api/geb/junit5/GebReportingTest.html[`geb.junit5.GebReportingTest`]
|TestNG |https://mvnrepository.com/artifact/{geb-group}/geb-testng[geb-testng] |link:api/geb/testng/GebTest.html[`geb.testng.GebTest`] |link:api/geb/testng/GebReportingTest.html[`geb.testng.GebReportingTest`]
|===

=== Example projects

The following projects can be used as starting references:

* link:https://github.com/geb/geb-example-gradle[geb-example-gradle]

[[cucumber-jvm]]
== Cucumber (Cucumber-JVM)

It is possible to both:

* Write your own {cucumber-jvm} steps that manipulate Geb
* Use a library of pre-built steps that drives Geb to do many common tasks

=== Writing your own steps

Use Geb's <<binding, binding management features>> to bind a browser in before / after hooks, often in a file named `env.groovy`:

[source,groovy]
----
def bindingUpdater
Before() { scenario ->
    bindingUpdater = new BindingUpdater(binding, new Browser())
    bindingUpdater.initialize()
}

After() { scenario ->
    bindingUpdater.remove()
}
----

Then normal Geb commands and objects are available in your Cucumber steps:

[source,groovy]
----
import static cucumber.api.groovy.EN.*

Given(~/I am on the DuckDuckGo search page/) { ->
    to DuckDuckGoHomePage
    waitFor { at(DuckDuckGoHomePage) }
}

When(~/I search for "(.*)"/) { String query ->
    page.search.value(query)
    page.searchButton.click()
}

Then(~/I can see some results/) { ->
    assert at(DuckDuckGoResultsPage)
}

Then(~/the first link should be "(.*)"/) { String text ->
    waitFor { page.results }
    assert page.resultLink(0).text()?.contains(text)
}
----

=== Using pre-built steps

The {geb-cucumber} project has a set of pre-built cucumber steps that drive Geb. So for example a feature with steps similar to the above would look like:

----
When I go to the duck duck go home page
And I enter "cucumber-jvm github" into the search field
And I click the search button
Then the results table 1st row link matches /cucumber\/cucumber-jvm · GitHub.*/
----

See {geb-cucumber} for more examples.

geb-cucumber also does Geb binding automatically, so if it is picked up you don't need to do it yourself as above.

=== Example project

The following project has examples of both writing your own steps and using geb-cucumber:

* link:https://github.com/geb/geb-example-cucumber-jvm[geb-example-cucumber-jvm]
