elem_expect | R Documentation |
elem_expect()
waits for a set of conditions to return TRUE. If, after a
certain period of time (by default 4 seconds), this does not happen, an
informative error is thrown. Otherwise, the original element is returned.
elem_wait_until()
does the same, but returns a logical value (whether or
not the test passed), allowing you to handle the failure case explicitly.
elem_expect(x, ..., testthat = NULL, timeout = NULL)
elem_wait_until(x, ..., timeout = NULL)
x |
A |
... |
< |
testthat |
Whether to treat the expectation as a |
timeout |
The number of seconds to wait for a condition to pass. If not
specified, the timeout used for |
elem_expect()
invisibly returns the element(s) x
, or NULL
if an
element or collection of elements was not given in x
.
elem_wait_for()
returns a boolean flag: TRUE if the test passes, FALSE
otherwise.
Conditions can be supplied as functions or calls.
Functions allow you to use unary conditions without formatting them as a
call (e.g. is_present
rather than is_present()
). It also allows you to
make use of R's anonymous function syntax to quickly
create custom conditions. x
will be supplied as the first argument of this
function.
Function calls allow you to use conditions that take multiple arguments
(e.g. has_text()
) without the use of an intermediate function. The call
will be modified so that x
is the first argument to the function call. For
example, has_text("a")
will be modified to become: has_text(x, "a")
.
The and (&&
), or (||
) and not (!
) functions can be used on both types
of conditions. If more than one condition are given in ...
, they are
combined using &&
.
Any function which takes a selenider element or element collection as its first argument, and returns a logical value, can be used as a condition.
Additionally, these functions provide a few features that make creating custom conditions easy:
Errors with class expect_error_continue
are handled, and
the function is prevented from terminating early. This means that if
an element is not found, the function will retry instead of immediately
throwing an error.
selenider
functions used inside conditions have their timeout, by
default, set to 0, ignoring the local timeout. This is important, since
elem_expect()
and elem_wait_until()
implement a retry mechanic
manually. To override this default, manually specify a timeout.
These two features allow you to use functions like elem_text()
to access
properties of an element, without needing to worry about the errors that
they throw or the timeouts that they use. See Examples for a few examples of
a custom condition.
These custom conditions can also be used with elem_filter()
and
elem_find()
.
is_present()
and other conditions for predicates for HTML elements.
(If you scroll down to the See also section, you will find the rest).
elem_expect_all()
and elem_wait_until_all()
for an easy way to test a
single condition on multiple elements.
elem_filter()
and elem_find()
to use conditions to filter elements.
html <- "
<div class='class1'>
<button id='disabled-button' disabled>Disabled</button>
<p>Example text</p>
<button id='enabled-button'>Enabled</button>
</div>
<div class='class3'>
</div>
"
session <- minimal_selenider_session(html)
s(".class1") |>
elem_expect(is_present)
s("#enabled-button") |>
elem_expect(is_visible, is_enabled)
s("#disabled-button") |>
elem_expect(is_disabled)
# Error: element is visible but not enabled
s("#disabled-button") |>
elem_expect(is_visible, is_enabled, timeout = 0.5) |>
try() # Since this condition will fail
s(".class2") |>
elem_expect(!is_present, !is_in_dom, is_absent) # All 3 are equivalent
# All other conditions will error if the element does not exist
s(".class2") |>
elem_expect(is_invisible, timeout = 0.1) |>
try()
# elem_expect() returns the element, so can be used in chains
s("#enabled-button") |>
elem_expect(is_visible && is_enabled) |>
elem_click()
# Note that elem_click() will do this automatically
s("p") |>
elem_expect(is_visible, has_exact_text("Example text"))
# Or use an anonymous function
s("p") |>
elem_expect(\(elem) identical(elem_text(elem), "Example text"))
# If your conditions are not specific to an element, you can omit the `x`
# argument
elem_1 <- s(".class1")
elem_2 <- s(".class2")
elem_expect(is_present(elem_1) || is_present(elem_2))
# We can now use the conditions on their own to figure out which element
# exists
if (is_present(elem_1)) {
print("Element 1 is visible")
} else {
print("Element 2 is visible")
}
# Use elem_wait_until() to handle failures manually
elem <- s(".class2")
if (elem_wait_until(elem, is_present)) {
elem_click(elem)
} else {
reload()
}
# Creating a custom condition is easiest with an anonymous function
s("p") |>
elem_expect(
\(elem) elem |>
elem_text() |>
grepl(pattern = "Example .*")
)
# Or create a function, to reuse the condition multiple times
text_contains <- function(x, pattern) {
text <- elem_text(x)
grepl(pattern, text)
}
s("p") |>
elem_expect(text_contains("Example *"))
# If we want to continue on error, we need to use the
# "expect_error_continue" class.
# This involves making a custom error object.
error_condition <- function() {
my_condition <- list(message = "Custom error!")
class(my_condition) <- c("expect_error_continue", "error", "condition")
stop(my_condition)
}
# This is much easier with rlang::abort() / cli::cli_abort():
error_condition_2 <- function() {
rlang::abort("Custom error!", class = "expect_error_continue")
}
# This error will not be caught
try(elem_expect(stop("Uncaught error!")))
# These will eventually throw an error, but will wait 0.5 seconds to do so.
try(elem_expect(error_condition(), timeout = 0.5))
try(elem_expect(error_condition_2(), timeout = 0.5))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.