Skip to content

Commit

Permalink
webauto: decided to rename waitForText() and waitForEnabled()
Browse files Browse the repository at this point in the history
  • Loading branch information
ptrthomas committed Aug 20, 2019
1 parent 1302d89 commit 0da4f41
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 66 deletions.
70 changes: 35 additions & 35 deletions karate-core/README.md
Expand Up @@ -117,10 +117,10 @@
<a href="#retry"><code>retry()</code></a>
| <a href="#waitfor"><code>waitFor()</code></a>
| <a href="#waitforany"><code>waitForAny()</code></a>
| <a href="#waitforurl"><code>waitForUrl()</code></a>
| <a href="#waituntil"><code>waitUntil()</code></a>
| <a href="#waituntiltext"><code>waitUntilText()</code></a>
| <a href="#waituntilenabled"><code>waitUntilEnabled()</code></a>
| <a href="#waitforurl"><code>waitForUrl()</code></a>
| <a href="#waitfortext"><code>waitForText()</code></a>
| <a href="#waitforenabled"><code>waitForEnabled()</code></a>
| <a href="#waituntil"><code>waitUntil()</code></a>
| <a href="#delay"><code>delay()</code></a>
| <a href="#script"><code>script()</code></a>
| <a href="#scripts"><code>scripts()</code></a>
Expand Down Expand Up @@ -814,6 +814,30 @@ Very handy for waiting for an expected URL change *and* asserting if it happened

Also see [waits](#wait-api).

## `waitForText()`
This is just a convenience short-cut for `waitUntil(locator, "_.textContent.includes('" + expected + "')")` since it is so frequently needed. Note the use of the JavaScript [`String.includes()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) function to do a *text contains* match for convenience. The need to "wait until some text appears" is so common, and with this - you don't need to worry about dealing with white-space such as line-feeds and invisible tab characters.

Of course, try not to use single-quotes within the string to be matched, or escape them using a back-slash (`\`) character.

```cucumber
* waitForText('#eg01WaitId', 'APPEARED')
```

And if you really need to scan the whole page for some text, you can use this, but it is better to be more specific for better performance:

```cucumber
* waitForText('body', 'APPEARED')
```

## `waitForEnabled()`
This is just a convenience short-cut for `waitUntil(locator, '!_.disabled')` since it is so frequently needed:

```cucumber
And waitForEnabled('#someId').click()
```

Also see [waits](#wait-api).

## `waitFor()`
This is typically used for the *first* element you need to interact with on a freshly loaded page. Use this in case a [`submit()`](#submit) for the previous action is un-reliable, see the section on [`waitFor()` instead of `submit()`](#waitfor-instead-of-submit)

Expand Down Expand Up @@ -876,7 +900,7 @@ Wait for the JS expression to evaluate to `true`. Will poll using the [retry()](
* waitUntil("document.readyState == 'complete'")
```

## `waitUntil(locator,js)`
### `waitUntil(locator,js)`
A very useful variant that takes a [locator](#locators) parameter is where you supply a JavaScript "predicate" function that will be evaluated *on* the element returned by the locator in the HTML DOM. Most of the time you will prefer the short-cut boolean-expression form that begins with an underscore (or "`!`"), and Karate will inject the JavaScript DOM element reference into a variable named "`_`".

Here is a real-life example:
Expand All @@ -887,12 +911,12 @@ Here is a real-life example:
And waitUntil('.alert-message', "_.innerHTML.includes('Some Text')")
```

## Karate vs the Browser
### Karate vs the Browser
One thing you need to get used to is the "separation" between the code that is evaluated by Karate and the JavaScript that is sent to the *browser* (as a raw string) and evaluated. Pay attention to the fact that the [`includes()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) function you see in the above example - is pure JavaScript.

The use of `includes()` is needed in this real-life example, because [`innerHTML()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) can return leading and trailing white-space (such as line-feeds and tabs) - which would cause an exact "`==`" comparison in JavaScript to fail.

But guess what - this example is baked into a Karate API, see [`waitUntilText()`](#waituntiltext).
But guess what - this example is baked into a Karate API, see [`waitForText()`](#waitfortext).

For an example of how JavaScript looks like on the "Karate side" see [Function Composition](#function-composition).

Expand All @@ -906,31 +930,7 @@ And waitUntil('#eg01WaitId', "_.innerHTML == 'APPEARED!'")
And waitUntil('#eg01WaitId', '!_.disabled')
```
Also see [`waitUtntilEnabled`](#waituntilenabled) which is the preferred short-cut for the last example above, also look at the examples for [chaining](#chaining) and then the section on [waits](#wait-api).
## `waitUntilText()`
This is just a convenience short-cut for `waitUntil(locator, "_.textContent.includes('" + expected + "')")` since it is so frequently needed. Note the use of [`includes()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) for a "string contains" match for convenience. Because the need to "wait until some text appears" is so common, and you don't need to worry about dealing with white-space such as line-feeds and invisible tab characters.

Of course, try not to use single-quotes within the string to be matched, or escape them using a back-slash (`\`) character.

```cucumber
* waitUntilText('#eg01WaitId', 'APPEARED')
```

And if you really need to scan the whole page for some text, you can use this:

```cucumber
* waitUntilText('body', 'APPEARED')
```

## `waitUntilEnabled()`
This is just a convenience short-cut for `waitUntil(locator, '!_.disabled')` since it is so frequently needed:

```cucumber
And waitUntilEnabled('#someId').click()
```

Also see [waits](#wait-api).
Also see [`waitForEnabled()`](#waitforenabled) which is the preferred short-cut for the last example above, also look at the examples for [chaining](#chaining) and then the section on [waits](#wait-api).
### `waitUntil(function)`
A *very* powerful variation of `waitUntil()` takes a full-fledged JavaScript function as the argument. This can loop until *any* user-defined condition and can use any variable (or Karate or [Driver JS API](#syntax)) in scope. The signal to stop the loop is to return any not-null object. And as a convenience, whatever object is returned, can be re-used in future steps.
Expand Down Expand Up @@ -958,7 +958,7 @@ Then match searchResults contains 'karate-core/src/main/resources/karate-logo.pn
Also see [waits](#wait-api).
### Function Composition
## Function Composition
The above example can be re-factored in a very elegant way as follows, using Karate's [native support for JavaScript](https://github.com/intuit/karate#javascript-functions):
```cucumber
Expand Down Expand Up @@ -1017,11 +1017,11 @@ Script | Description
[`waitFor('#myId')`](#waitfor) | waits for an element as described above
`retry(10).waitFor('#myId')` | like the above, but temporarily over-rides the settings to wait for a [longer time](#retry-actions), and this can be done for *all* the below examples as well
[`waitForUrl('google.com')`](#waitforurl) | for convenience, this uses a string *contains* match - so for example you can omit the `http` or `https` prefix
[`waitForText('#myId', 'appeared')`](#waitfortext) | frequently needed short-cut for waiting until a string appears - and this uses a "string contains" match for convenience
[`waitForEnabled('#mySubmit')`](#waitforenabled) | frequently needed short-cut for `waitUntil(locator, '!_disabled')`
[`waitForAny('#myId', '#maybe')`](#waitforany) | handle if an element may or *may not* appear, and if it does, handle it - for e.g. to get rid of an ad popup or dialog
[`waitUntil(expression)`](#waituntil) | wait until *any* user defined JavaScript statement to evaluate to `true` in the browser
[`waitUntil(function)`](#waituntilfunction) | use custom logic to handle *any* kind of situation where you need to wait, *and* use other API calls if needed
[`waitUntilText()`](#waituntiltext) | frequently needed short-cut for waiting until a string appears - and this uses a "string contains" match for convenience
[`waitUntilEnabled()`](#waituntilenabled) | frequently needed short-cut for `waitUntil(locator, '!_disabled')`

Also see the examples for [chaining](#chaining).

Expand Down
20 changes: 8 additions & 12 deletions karate-core/src/main/java/com/intuit/karate/driver/Driver.java
Expand Up @@ -149,6 +149,14 @@ default String waitForUrl(String expected) {
return getOptions().waitForUrl(this, expected);
}

default Element waitForText(String locator, String expected) {
return waitUntil(locator, "_.textContent.includes('" + expected + "')");
}

default Element waitForEnabled(String locator) {
return waitUntil(locator, "!_.disabled");
}

default Element waitForAny(String locator1, String locator2) {
return getOptions().waitForAny(this, new String[]{locator1, locator2});
}
Expand All @@ -161,18 +169,6 @@ default Element waitUntil(String locator, String expression) {
return getOptions().waitUntil(this, locator, expression);
}

default Element waitUntilEnabled(String locator) {
return waitUntil(locator, "!_.disabled");
}

default Element waitUntilText(String locator, String expected) {
return waitUntil(locator, "_.textContent.includes('" + expected + "')");
}

default Element waitUntilText(String expected) {
return waitUntil("document", "_.textContent.includes('" + expected + "')");
}

default Object waitUntil(Supplier<Object> condition) {
return getOptions().retry(() -> condition.get(), o -> o != null, "waitUntil (function)");
}
Expand Down
Expand Up @@ -104,7 +104,7 @@ public Element input(String value) {
@Override
public Element input(String[] values) {
return driver.input(locator, values);
}
}

@Override
public Element select(String text) {
Expand Down Expand Up @@ -135,14 +135,14 @@ public Element waitFor() {
}

@Override
public Element waitUntil(String expression) {
return driver.waitUntil(locator, expression); // will throw exception if not found
public Element waitForText(String text) {
return driver.waitForText(locator, text);
}

@Override
public Element waitUntilText(String text) {
return driver.waitUntilText(locator, text);
}
public Element waitUntil(String expression) {
return driver.waitUntil(locator, expression); // will throw exception if not found
}

@Override
public Object script(String expression) {
Expand Down
Expand Up @@ -61,7 +61,7 @@ public interface Element {

Element waitUntil(String expression);

Element waitUntilText(String text);
Element waitForText(String text);

Object script(String expression);

Expand Down
Expand Up @@ -50,7 +50,7 @@ public boolean isExists() {
@Override
public boolean isEnabled() {
return true; // hmm
}
}

@Override
public Element focus() {
Expand All @@ -70,12 +70,12 @@ public Element click() {
@Override
public Element submit() {
return this;
}
}

@Override
public Mouse mouse() {
return null;
}
}

@Override
public Element input(String text) {
Expand All @@ -86,7 +86,7 @@ public Element input(String text) {
public Element input(String[] values) {
return this;
}

@Override
public Element select(String text) {
return this;
Expand All @@ -100,28 +100,28 @@ public Element select(int index) {
@Override
public Element switchFrame() {
return this;
}
}

@Override
public Element delay(int millis) {
driver.delay(millis);
return this;
}
}

@Override
public Element waitFor() {
return this;
}

@Override
public Element waitUntil(String expression) {
public Element waitForText(String text) {
return this;
}

@Override
public Element waitUntilText(String text) {
public Element waitUntil(String expression) {
return this;
}
}

@Override
public Object script(String expression) {
Expand Down
9 changes: 6 additions & 3 deletions karate-demo/src/test/java/driver/core/test-01.feature
Expand Up @@ -13,13 +13,16 @@ Scenario Outline: using <config>
# wait for very slow loading element
And waitFor('#eg01WaitId')

# wait for text (is a string "contains" match for convenience)
And waitForText('#eg01WaitId', 'APPEARED')
And waitForText('body', 'APPEARED')
And waitForEnabled('#eg01WaitId')

# powerful variants of the above, call any js on the element
And waitUntil('#eg01WaitId', "function(e){ return e.innerHTML == 'APPEARED!' }")
And waitUntil('#eg01WaitId', "_.innerHTML == 'APPEARED!'")
And waitUntil('#eg01WaitId', '!_.disabled')
And waitUntilText('#eg01WaitId', 'APPEARED')
And waitUntilText('body', 'APPEARED')
And waitUntilEnabled('#eg01WaitId')

And match script('#eg01WaitId', "function(e){ return e.innerHTML }") == 'APPEARED!'
And match script('#eg01WaitId', '_.innerHTML') == 'APPEARED!'
And match script('#eg01WaitId', '!_.disabled') == true
Expand Down

0 comments on commit 0da4f41

Please sign in to comment.