When testing AJAX-enabled applications, you are facing big deal of asynchronous behavior:
When calling any actions, it takes time before browser's request is processed on the server.
Test must be written so that it counts with any time before it can proceed with execution.
This does not include only server processing, but also complex client-side computations.
When writing tests, you must be aware what changes are happening on a page as a result of user action and design a appropriate condition to wait for.
Graphene offers two solution to waiting for appropriate conditions:
Graphene uses WebDriverWait object and defines most used waiting conditions in Graphene Utility Class.
When defining waiting conditions, you might use exact or benevolent conditions:
benevolent conditions (e.g. wait for text to appear on the page) are more robust, but does not test a exact page conditions
exact conditions (e.g. wait for given element to have text which is equal to) tests application behavior more closely, but they are more error-prone
You can read more about Waiting API.
More powerful mechanism than conditions - Request Guards - watches request object on the page and waits to the given browser communication (HTTP, AJAX) to happen.
Warning: it is not sufficient to use any mechanism for pausing the test as the mechanism for waiting for conditions (e.g. Thread.sleep) as it leads to unstable tests and increases execution time. The golden rule is that each action must have appropriate reaction on the page, otherwise the UI is not designed well.
Test must be aware that elements which tests depend on might not be present immediatelly, but might be shown after the asynchronous action is processed.
Graphene built-in waiting conditions are coded in defensive manner, it means when you are waiting before the element's background become red, the condition will not fail when element is not present.
AJAX-based applications offen update a page content with replacing a portion of a DOM with another one.
Even though the rendered output might be same, the element references might be different.
Page abstractions created by Graphene are by default aware of stale element, so they try to re-initialize element reference when they find out the reference is stale.