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::[]
= Javascript, AJAX and dynamic pages

This section discusses how to deal with some of the challenges in testing and/or automating modern web applications.

[[js-object]]
== The "`js`" object

The browser instance exposes a link:api/geb/Browser.html#getJs()[`js`] object that provides support for working with JavaScript over and above what WebDriver provides.
It's important to understand how WebDriver does handle JavaScript, which is through a driver's implementation of
`{javascript-executor-execute-script-api}`
method.

[IMPORTANT]
====
Before reading further, it's *strongly* recommended to read the description of `{javascript-executor-execute-script-api}` in order to understand how type conversion works between the two worlds.
====

You can execute JavaScript like you would with straight WebDriver using the driver instance via the browser...

[source,groovy]
----
include::{snippets-dir}/javascript/JavaScriptExecutorSpec.groovy[tag=example,indent=0]
----

This is a bit long winded, and as you would expect Geb uses the dynamism of Groovy to make life easier.

[NOTE]
====
The `{javascript-executor-api}` interface does not define any contract in regards to the driver's responsibility when there is some issue executing JavaScript.
All drivers however throw _some kind_ of exception when this happens.
====

=== Accessing variables

Any _global_ JavaScript variables inside the browser can be read as _properties_ of the `js` object.

Given the following page...

[source,html]
----
include::{snippets-dir}/javascript/AccessingVariablesSpec.groovy[tag=html,indent=0]
----

We could access the JavaScript variable `aVariable` with...

[source,groovy]
----
include::{snippets-dir}/javascript/AccessingVariablesSpec.groovy[tag=accessing,indent=0]
----

Or if we wanted to map it to page content...

[source,groovy]
----
include::{snippets-dir}/javascript/AccessingVariablesSpec.groovy[tag=mapping_class,indent=0]

include::{snippets-dir}/javascript/AccessingVariablesSpec.groovy[tag=mapping,indent=0]
----

We can even access _nested_ variables...

[source,groovy]
----
include::{snippets-dir}/javascript/AccessingVariablesSpec.groovy[tag=nested,indent=0]
----

=== Calling methods

Any _global_ JavaScript functions can be called as methods on the `js` object.

Given the following page...

[source,html]
----
include::{snippets-dir}/javascript/CallingMethodsSpec.groovy[tag=calling_methods_html,indent=0]
----

We can call the `addThem()` function with...

[source,groovy]
----
include::{snippets-dir}/javascript/CallingMethodsSpec.groovy[tag=calling_methods,indent=0]
----

This also works from pages and modules.

To call _nested_ methods, given the following page...
[source,html]
----
include::{snippets-dir}/javascript/CallingMethodsSpec.groovy[tag=nested_methods_html,indent=0]
----

We use the same syntax as for properties...

[source,groovy]
----
include::{snippets-dir}/javascript/CallingMethodsSpec.groovy[tag=nested_methods,indent=0]
----

=== Executing arbitrary code

The `js` object also has an `exec()` method that can be used to run snippets of JavaScript.
It is identical to the `{javascript-executor-execute-script-api}` method, except that it expects the code as last argument,
and accepts `Navigator` instances in addition to `WebElement`s...

[source,groovy]
----
include::{snippets-dir}/javascript/ExecutingArbitraryCodeSpec.groovy[tag=single_line,indent=0]
----

You might be wondering why the order has been changed (i.e. the arguments go _before_ the script). It makes writing multiline JavaScript more convenient...

[source,groovy]
----
include::{snippets-dir}/javascript/ExecutingArbitraryCodeSpec.groovy[tag=multiline,indent=0]
----

Alternatively, you can give a `Closure` as last argument that returns the script to enable the following syntax...

[source,groovy]
----
include::{snippets-dir}/javascript/ExecutingArbitraryCodeSpec.groovy[tag=closure,indent=0]
----

[[waiting]]
== Waiting

Geb provides some convenient methods for _waiting_ for a certain condition to be true. This is useful for testing pages using AJAX, timers or effects.

The `waitFor` methods are provided by the `{waiting-support-api}` mixin which delegates to the `{wait-api}` class (see the documentation of the `{wait-for-api}` method of this class for the precise
semantics of _waiting_).
These methods take various parameters that determine how long to wait for the given closure to return a true object according to the {groovy-truth}, and how long to wait in between invoking the
closure again.

[source,groovy]
----
waitFor {} //<1>
waitFor(10) {} //<2>
waitFor(10, 0.5) {} //<3>
waitFor("quick") {} //<4>
----
<1> Use default configuration.
<2> Wait for up to 10 seconds, using the default retry interval.
<3> Wait for up to 10 seconds, waiting half a second in between retries. See the section on <<waiting-configuration, wait configuration>> for how to change the default values and define presets.
<4> Use the preset "`quick`" as the wait settings

[NOTE]
====
It is also possible to declare that content should be implicitly waited on, see <<content-dsl-wait, the `wait` option for content definition>>.
====

=== Examples

Here is an example showing one way of using `waitFor()` to deal with the situation where clicking a button invokes an AJAX request that creates a new `div` on its completion.

[source,groovy]
----
include::{snippets-dir}/javascript/WaitingExamplesSpec.groovy[tag=page,indent=0]
----

[source,groovy]
----
include::{snippets-dir}/javascript/WaitingExamplesSpec.groovy[tag=using_page,indent=0]
----

Recall that the `return` keyword is optional in Groovy, so in the example above `theResultDiv.present` acts as the return value for the closure and is used as the basis on
whether the closure _passed_ or not.
This means that you must ensure that the last statement inside the closure returns a value that is `true` according to the {groovy-truth} (if you're unfamiliar with the Groovy Truth *do* read that
page).

Because the browser delegates method calls to the page object, the above could have been written as...

[source,groovy]
----
include::{snippets-dir}/javascript/WaitingExamplesSpec.groovy[tag=not_using_page,indent=0]
----

[NOTE]
====
Not using explicit `return` statements in closure expressions passed to `waitFor()` is actually preferred.
See the section on <<implicit-assertions, implicit assertions>> for more information.
====

The closures given to the `waitFor()` method(s) do not need to be single statement.

[source,groovy]
----
include::{snippets-dir}/javascript/WaitingExamplesSpec.groovy[tag=multiline,indent=0]
----

That will work fine.

If you wish to _test_ multiple conditions as separate statement inside a `waitFor` closure, you can just put them in separate lines.

[source,groovy]
----
include::{snippets-dir}/javascript/WaitingExamplesSpec.groovy[tag=multiple_conditions,indent=0]
----

[[wait-for-custom-message]]
=== Custom message

If you wish to add a custom message to `WaitTimeoutException` that is being thrown when `waitFor` call times out you can do so by providing a message parameter to the `waitFor` call:

[source,groovy]
----
include::{snippets-dir}/javascript/CustomMessageSpec.groovy[tag=custom_message,indent=0]
----

=== Suppressing `WaitTimeoutException`

If you wish for `WaitTimeoutException` not to be thrown, and the last evaluation result to be returned instead when the wait times out then you can set the `noException` parameter to a truthy value:

[source,groovy]
----
include::{snippets-dir}/javascript/WaitForNoExceptionSpec.groovy[tag=no_exception,indent=0]
----

[[reloading-page-when-waiting]]
== Reloading the page when waiting

Apart from the generic waiting support Geb also comes with a convenience method which reloads the page each time before the block passed to it is evaluated.

The method is available on `Page` class and is called `{refresh-wait-for-api}` and it is the same as the <<waiting, `waitFor()`>> method with regards to everything else than the page reloading behaviour.
This means that you can pass the same arguments to it as to `waitFor()`, the block passed to it is <<implicit-assertions, implicitly asserted>> and it supports <<wait-for-custom-message,custom messages>>.

The following example shows waiting for a static timestamp of when the page was rendered to be at least three hundred milliseconds after the test has started:

[source,groovy]
----
include::{snippets-dir}/javascript/RefreshWaitingSpec.groovy[tag=page,indent=0]

include::{snippets-dir}/javascript/RefreshWaitingSpec.groovy[tag=test,indent=0]
----
== Controlling network conditions

When driving modern, single page, highly asynchronous web applications timing issues frequently appear and are the bane of browser automation leading to flakey tests.
Correctly waiting for asynchronous events to complete becomes essential.
Quite often the asynchronicity is hard to spot if the asynchronous events occur relatively fast and is only exposed when running in a slower execution or networking environment.

[IMPORTANT]
====
This section introduces a feature which depends on a Chromium specific, custom WebDriver command.
Calling the methods mentioned in the next paragraph will only work when driving a Chromium based browser (Chromium, Chrome or Edge) and will throw an exception for other browsers.
====

Thankfully Chrome driver supports controlling network conditions via it's custom `setNetworkConditions` command which allows to control the network conditions of the browser.
Geb provides {browser-set-network-latency-link}[`setNetworkLatency()`] and {browser-reset-network-latency-link}[`resetNetworkLatency()`] methods on the `Browser` class which allow to introduce network latency to the browser being driven.
Adding latency in the region of couple of hundred milliseconds will usually expose network related timing issues.
Temporarily adding network latency during test development allows to shake off timing issues and is useful when debugging such issues which might occur in one environment like the CI server but do not in another like developer machines.

This is how `setNetworkLatency()` method be used:
[source,groovy]
----
include::{ct-snippets-dir}/geb/BrowserNetworkLatencySpec.groovy[tag=setNetworkLatency,indent=0]
----

[NOTE]
====
There are various types of asynchronous events occurring in a browser and AJAX calls which are network related are only one example.
Animations would be another example of asynchronicity in web applications and the methods mentioned above will have no influence on timing issues introduced by animations or any other asynchronous events.
====

== Alert and confirm dialogs

WebDriver currently does not handle the alert() and confirm() dialog windows.
However, we can fake it through some JavaScript magic as link:https://github.com/SeleniumHQ/selenium-google-code-issue-archive/issues/27#issuecomment-191402931[discussed on the WebDriver issue for this].
Geb implements a workaround based on this solution for you.
Note that this feature relies on making changes to the browser's `window` DOM object so may not work on all browsers on all platforms.
At the time when WebDriver adds support for this functionality the underlying implementation of the following methods will change to use that which will presumably be more robust.
Geb adds this functionality through the `{alert-and-confirm-support-api}` class that is mixed into `{page-api}` and `{module-api}`.

The Geb methods *prevent* the browser from actually displaying the dialog, which is a good thing.
This prevents the browser blocking while the dialog is displayed and causing your test to hang indefinitely.

[NOTE]
====
Unexpected `alert()` and `confirm()` calls can have strange results.
This is due to the nature of how Geb handles this internally.
If you are seeing strange results, you may want to run your tests/scripts against a real browser and watch what happens to make sure there aren't any alert or confirm windows being opened that you
aren't expecting.
To do this, you need to disable Geb's handling by changing your code to not use the methods below.
====

[[alert]]
=== `alert()`

There are three methods that deal with `alert()` dialogs:

[source,groovy]
----
include::{cm-snippets-dir}/geb/js/AlertAndConfirmSupport.groovy[tag=alert,indent=0]
----

The first method, `withAlert()`, is used to verify actions that will produce an alert dialog.
This method returns the alert message.

Given the following HTML...

[source,html]
----
include::{snippets-dir}/javascript/AlertSpec.groovy[tag=alert_html,indent=0]
----

The `withAlert()` method is used like so...

[source,groovy]
----
include::{snippets-dir}/javascript/AlertSpec.groovy[tag=alert,indent=0]
----

If an alert dialog is not raised by the given "`actions`" closure, an `AssertionError` will be thrown.

The `withAlert()` method also accepts a wait option.
It is useful if the code in your "`actions`" closure is raising a dialog in an asynchronous manner and can be used like that:

[source,groovy]
----
include::{snippets-dir}/javascript/AlertSpec.groovy[tag=async_alert,indent=0]
----

The possible values for the `wait` option are consistent with the <<content-dsl-wait, ones for `wait` option of content definitions>>.

The second method, `withNoAlert()`, is used to verify actions that will not produce an `alert()` dialog.
If an alert dialog is raised by the given "`actions`" closure, an `AssertionError` will be thrown.

Given the following HTML...

[source,html]
----
include::{snippets-dir}/javascript/AlertSpec.groovy[tag=no_alert_html,indent=0]
----

The `withNoAlert()` method is used like so...

[source,groovy]
----
include::{snippets-dir}/javascript/AlertSpec.groovy[tag=no_alert,indent=0]
----

[TIP]
====
It's a good idea to use `withNoAlert()` when doing something that _might_ raise an alert.
If you don't, the browser is going to raise a real alert dialog and sit there waiting for someone to click it which means your test is going to hang.
Using `withNoAlert()` prevents this.
====

A side effect of the way that this is implemented is that we aren't able to definitively handle actions that cause the browser's actual page to change (e.g. clicking a link in the closure given to
`withAlert()`/`withNoAlert()`).
We can detect that the browser page did change, but we can't know if `alert()` did or did not get called before the page change.
If a page change was detected the `withAlert()` method will return a literal `true` (whereas it would normally return the alert message), while the `withNoAlert()` will succeed.

=== `confirm()`

There are five methods that deal with `confirm()` dialogs:

[source,groovy]
----
include::{cm-snippets-dir}/geb/js/AlertAndConfirmSupport.groovy[tag=confirm,indent=0]
----

The first method, `withConfirm()` (and its ‘`ok`’ defaulted relative), is used to verify actions that will produce a confirm dialog.
This method returns the confirmation message.
The `ok` parameter controls whether the "`OK`" or "`Cancel`" button should be clicked.

Given the following HTML...

[source,html]
----
include::{snippets-dir}/javascript/ConfirmSpec.groovy[tag=confirm_html,indent=0]
----

The `withConfirm()` method is used like so...

[source,groovy]
----
include::{snippets-dir}/javascript/ConfirmSpec.groovy[tag=confirm,indent=0]
----

If a confirmation dialog is not raised by the given "`actions`" closure, an `AssertionError` will be thrown.

The `withConfirm()` method also accepts a wait option just like the `withAlert()` method. See the <<alert, description of `withAlert()`>> to learn about the possible values and usage.

The other method, `withNoConfirm()`, is used to verify actions that will not produce a confirm dialog.
If a confirmation dialog is raised by the given "`actions`" closure, an `AssertionError` will be thrown.

Given the following HTML...

[source,html]
----
include::{snippets-dir}/javascript/ConfirmSpec.groovy[tag=no_confirm_html,indent=0]
----

The `withNoConfirm()` method is used like so...

[source,groovy]
----
include::{snippets-dir}/javascript/ConfirmSpec.groovy[tag=no_confirm,indent=0]
----

[TIP]
====
It's a good idea to use `withNoConfirm()` when doing something that _might_ raise a confirmation.
If you don't, the browser is going to raise a real confirmation dialog and sit there waiting for someone to click it, which means your test is going to hang.
Using `withNoConfirm()` prevents this.
====

A side effect of the way that this is implemented is that we aren't able to definitively handle actions that cause the browser's actual page to change (e.g. clicking a link in the closure given to
`withConfirm()`/`withNoConfirm()`).
We can detect that the browser page did change, but we can't know if `confirm()` did or did not get called before the page change.
If a page change was detected, the `withConfirm()` method will return a literal `true` (whereas it would normally return the alert message), while the `withNoConfirm()` will succeed.

=== `prompt()`

Geb does not provide any support for `prompt()` due to its infrequent and generally discouraged use.

== jQuery integration

Geb has special support for {jquery}.
Navigator objects have a special adapter that makes calling jQuery methods against the underlying DOM elements simple.
This is best explained by example.

[WARNING]
====
The jQuery integration only works when the pages you are working with include jQuery, Geb does not install it in the page for you.
The minimum supported version of jQuery is 1.4.
====

Consider the following page:

[source,html]
----
include::{rb-snippets-dir}/javascript/JQuerySupportSpec.groovy[tag=html,indent=0]
----

We want to click the Geb link, but can't because it's hidden (WebDriver does not let you interact with hidden elements).
The div containing the link (div "`b`") is only displayed when the mouse moves over div "`a`".

The jQuery library provides convenient methods for triggering browser events.
We can use this to simulate the mouse being moved over the div "`a`".

In straight jQuery JavaScript we would do...

[source,javascript]
----
jQuery("div#a").mouseover();
----

Which we could invoke via Geb easy enough...

[source,groovy]
----
include::{rb-snippets-dir}/javascript/JQuerySupportSpec.groovy[tag=using_javascript_executor,indent=0]
----

That will work, but can be inconvenient as it duplicates content definitions in our Geb pages.
Geb's jQuery integration allows you to use your defined content in Geb with jQuery.
Here is how we could call the `mouseover` jQuery function on an element from Geb...

[source,groovy]
----
include::{rb-snippets-dir}/javascript/JQuerySupportSpec.groovy[tag=using_adapter,indent=0]
----

To be clear, that is Groovy (not JavaScript) code. It can be used with pages...

[source,groovy]
----
include::{rb-snippets-dir}/javascript/JQuerySupportSpec.groovy[tag=page,indent=0]
----

[source,groovy]
----
include::{rb-snippets-dir}/javascript/JQuerySupportSpec.groovy[tag=on_content,indent=0]
----

The `jquery` property of a navigator is conceptually equivalent to a jQuery object for _all_ of the navigator's matched page elements.

The methods can also take arguments...

[source,groovy]
----
include::{rb-snippets-dir}/javascript/JQuerySupportSpec.groovy[tag=with_parameters,indent=0]
----

The same set of restricted types as allowed by WebDriver's `{javascript-executor-execute-script-api}` method are permitted here.

The return value of methods called on the `jquery` property depends on what the corresponding jQuery method returns.
A jQuery object will be converted to a Navigator representing the same set of elements, other values such as objects, strings and numbers are returned as per WebDriver's
`{javascript-executor-execute-script-api}` method.

:numbered!:

=== Why?

This functionality was developed to make triggering mouse related events easier.
Some applications are very sensitive to mouse events, and triggering these events in an automated environment is a challenge.
jQuery provides a good API for faking these events, which makes for a good solution.
An alternative is using <<interact-closures, `the interact() method`>>.

:numbered:
