Skip to content
This repository has been archived by the owner on Nov 23, 2021. It is now read-only.

Commit

Permalink
#288 Documentation and changes in default values
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrzyzanowski committed Oct 2, 2018
1 parent cdcad67 commit 0c5945b
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 8 deletions.
Expand Up @@ -89,8 +89,7 @@ public BobcatWait ignoring(List<Class<? extends Throwable>> exceptions) {
*
* @param condition Selenium's condition object that is queried cyclically inside the wait loop.
* @param <T> The function's expected return type.
* @return The ExpectedCondition's return value if the function returned something different.
* from null or false before the timeout expired.
* @return The ExpectedCondition's return value if the function returned something different from null or false before the timeout expired.
* @see WebDriverWait#until(Function)
*/
public <T> T until(ExpectedCondition<T> condition) {
Expand All @@ -101,6 +100,7 @@ public <T> T until(ExpectedCondition<T> condition) {
.until(condition);
} finally {
ignoredExceptions = new ArrayList<>();
timings = new TimingsBuilder().build();
restoreImplicitTimeout();
}
}
Expand Down
Expand Up @@ -34,13 +34,13 @@
public class TimingsBuilder {

private long pollingInterval =
Long.valueOf(System.getProperty(ConfigKeys.TIMINGS_POLLING_INTERVAL, "500"));
Long.valueOf(System.getProperty(ConfigKeys.TIMINGS_POLLING_INTERVAL));

private long explicitTimeout =
Long.valueOf(System.getProperty(ConfigKeys.TIMINGS_EXPLICIT_TIMEOUT, "10"));
Long.valueOf(System.getProperty(ConfigKeys.TIMINGS_EXPLICIT_TIMEOUT));

private long implicitTimeout =
Long.valueOf(System.getProperty(ConfigKeys.TIMINGS_IMPLICIT_TIMEOUT, "10"));
Long.valueOf(System.getProperty(ConfigKeys.TIMINGS_IMPLICIT_TIMEOUT));

/**
* Set the explicit timeout
Expand Down
2 changes: 1 addition & 1 deletion bb-core/src/main/resources/default.properties
Expand Up @@ -16,5 +16,5 @@ cookies.loadAutomatically = true

modifiers.implicitTimeout=true
timings.explicitTimeout=10
timings.implicitTimeout=10
timings.implicitTimeout=1
timings.pollingInterval=500
2 changes: 1 addition & 1 deletion bb-core/src/main/resources/default.yaml
Expand Up @@ -25,5 +25,5 @@ default:

modifiers.implicitTimeout: true
timings.explicitTimeout: 10
timings.implicitTimeout: 10
timings.implicitTimeout: 1
timings.pollingInterval: 500
6 changes: 5 additions & 1 deletion docs/_data/navigation.yml
Expand Up @@ -24,6 +24,8 @@ docs:
children:
- title: "Overview"
url: /docs/modules/core/
- title: "Explicit and implicit waiting"
url: /docs/modules/core/waiting
- title: "Setting cookies"
url: /docs/modules/core/cookies
- title: "Other modules"
Expand All @@ -36,7 +38,9 @@ docs:
url: /docs/modules/traffic/
- title: "Email"
url: /docs/modules/email/
- title: "AEM modules (new API incoming!)"
- title: "AEM modules"
children:
- title: "New API incoming in 2.0!"
- title: "EOL Modules"
children:
- title: "AEM Common"
Expand Down
96 changes: 96 additions & 0 deletions docs/_docs/modules/core/waiting.md
@@ -0,0 +1,96 @@
---
title: "Waiting"
---

Available in `bb-core` since version `1.6.0`. Mechanism from previous versions: [link](https://github.com/Cognifide/bobcat/wiki/Explicit-Waits)
{: .notice--info}

## Overview
One of the fundamental problems when automating GUI is handling dynamic elements on a website: pop-ups, carousels, menus, lazy-loaded data in various places, etc.

Bobcat utilizes Selenium's out-of-the-box mechanisms: implicit and explicit waiting. More information about them can be found in [official docs](https://www.seleniumhq.org/docs/04_webdriver_advanced.jsp).

## Implicit waiting

Implicit waiting happens before any lookup of a `WebElement` is being executed during your tests. When searching for an element it waits for a specific period of time to actually report the issue in case of the element not being present on the page.
This implicit timeout can be set manually using: `webDriver.manage().timeouts().implicitlyWait(<TIMEOUT>, <TIME UNIT>)`.

Bobcat has an in-built modifier that sets that timeout for you, just after the `WebDriver` instance is created: `ImplicitTimeoutModifier`.

The modifier is enabled by default. It is set to **1 second**.

To disable it, put the following property in your config file:
```yaml
modifier.implicitTimeout: false
```

To change the value of the timeout to e.g. 5 seconds, put the following property in your config:
```yaml
timings.implicitTimeout: 5
```

## Explicit waiting

Depending on implicit timeout will solve only a tiny fraction of your problems. That is why, the most recommended approach is to use explicit waiting.

Selenium provides the `FluentWait` and its extension, `WebDriverWait`. Bobcat wraps the latter with bunch of useful methods in the form of `BobcatWait`.

### BobcatWait

Explicit waiting relies on evaluating 'expected conditions'. They are the implementation of `ExpectedCondition` interface.

Selenium provides a hefty list of predefined conditions out-of-the-box in the `ExpectedConditions` class. This will your bread-and-butter when working with dynamic elements.

### How to wait?

To wait for a specific condition you can use two methods from `BobcatWait`:

```java
@Inject
private BobcatWait bobcatWait;

@FindBy(css=".my-element")
private WebElement testedElement;

WebElement element = bobcatWait.until(ExpectedConditions.visibilityOf(testedElement));

boolean result = bobcatWait.isConditionMet(ExpectedConditions.visibilityOf(testedElement));
```

`BobcatWait#until(condition)`:
* if the condition is met, the method will return an object of a type declared in the condition itself.
* if the condition has not been met, `TimeoutException` will be thrown
* this behaviour is exactly the same as in Selenium's `WevDriverWait#until`

`BobcatWait#isConditionMet(condition)`:
* if the condition is met, the method will return `true`
* if the condition has not been met, the method will return `false`

### Writing your own conditions

When `ExpectedConditions` does not provide you a condition suiting your needs, you can always write your own. You can either implement it in a similar way to Selenium, i.e. create a dedicated class where you will keep your conditions, or you can also provide one inline with lamda:
`BobcatWait.until(webDriver -> heightOfElement == expectedValue);`.

### Fine-tuning your waits

Bobcat takes the following values as defaults:

```yaml
timings.explicitTimeout: 10 # in seconds
timings.implicitTimeout: 1 # in seconds
timings.pollingInterval: 500 # in milliseconds
```

You can tweak these in various ways:
* globally, by providing the above properties in your config or via command line
* locally, by using the `BobcatWait.tweak(Timings)` method before the `until` call
* it takes an instance of `Timings` as an argument; use the `TimingsBuilder` to create one, e.g.: `new TimingsBuilder().explicitTimeout(5).pollingInterval(200).build()`

### Explicit vs implicit waiting

It is discouraged (also by Selenium maintainers) to use implicit and explicit waiting together, as it may yield unexpected results. That is why Bobcat has an in-built protection against such situations.

After calling `BobcatWait#until(condition)` Bobcat will:
1. reduce the implicit timing before evaluating the condition,
2. evaluate the condition,
3. restore the implicit timeout to the default one, or the customized value from config or a `Timings` instance passed to `BobcatWait` via `tweak(Timings)` method.

0 comments on commit 0c5945b

Please sign in to comment.