Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions examples/java/src/test/java/dev/selenium/waits/WaitsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.openqa.selenium.support.ui.WebDriverWait;
Expand Down Expand Up @@ -93,4 +94,21 @@ public void explicitWithOptions() {

Assertions.assertEquals("Displayed", revealed.getDomProperty("value"));
}

@Test
public void expectedConditions() {
startChromeDriver(new ChromeOptions());

driver.get("https://www.selenium.dev/selenium/web/web-form.html");
driver.findElement(By.id("my-text-id")).sendKeys("Selenium");
driver.findElement(By.cssSelector("button")).click();

Wait<WebDriver> wait = new WebDriverWait(driver, Duration.ofSeconds(2));
wait.until(ExpectedConditions.titleIs("Web form - target page"));
WebElement message = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("message")));
wait.until(ExpectedConditions.visibilityOf(message));
wait.until(ExpectedConditions.textToBePresentInElement(message, "Received!"));

Assertions.assertEquals("Received!", message.getText());
}
}
13 changes: 13 additions & 0 deletions examples/javascript/test/waits/waits.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,17 @@ describe('Waits', function () {
await revealed.sendKeys("Displayed");
assert.equal(await revealed.getAttribute("value"), "Displayed")
})

it('expected conditions', async function () {
await driver.get('https://www.selenium.dev/selenium/web/web-form.html');
await driver.findElement(By.id("my-text-id")).sendKeys("Selenium");
await driver.findElement(By.css("button")).click();

await driver.wait(until.titleIs("Web form - target page"), 2000);
let message = await driver.wait(until.elementLocated(By.id("message")), 2000);
await driver.wait(until.elementIsVisible(message), 2000);
await driver.wait(until.elementTextIs(message, "Received!"), 2000);

assert.equal(await message.getText(), "Received!")
})
});
15 changes: 15 additions & 0 deletions examples/python/tests/waits/test_waits.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import time
from selenium.common import NoSuchElementException, ElementNotInteractableException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


Expand Down Expand Up @@ -55,3 +56,17 @@ def test_explicit_options(driver):
wait.until(lambda _ : revealed.send_keys("Displayed") or True)

assert revealed.get_property("value") == "Displayed"


def test_expected_conditions(driver):
driver.get('https://www.selenium.dev/selenium/web/web-form.html')
driver.find_element(By.ID, "my-text-id").send_keys("Selenium")
driver.find_element(By.CSS_SELECTOR, "button").click()

wait = WebDriverWait(driver, timeout=2)
wait.until(EC.title_is("Web form - target page"))
message = wait.until(EC.presence_of_element_located((By.ID, "message")))
wait.until(EC.visibility_of(message))
wait.until(EC.text_to_be_present_in_element((By.ID, "message"), "Received!"))

assert message.text == "Received!"
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,10 @@ Current form:

{{< tabpane text=true >}}
{{< tab header="Java" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L67-L68" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L68-L69" >}}
{{< /tab >}}
{{< tab header="Python" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L41-L42" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L42-L43" >}}
{{< /tab >}}
{{< /tabpane >}}

Expand Down
4 changes: 2 additions & 2 deletions website_and_docs/content/documentation/guides/waiting.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ This example waits for an element that is revealed a couple of seconds after a c

{{< tabpane text=true >}}
{{< tab header="Java" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L67-L68" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L68-L69" >}}
{{< /tab >}}
{{< tab header="Python" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L41-L42" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L42-L43" >}}
{{< /tab >}}
{{< tab header="CSharp" >}}
{{< gh-codeblock path="/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs#L56-L57" >}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ These methods can include conditions such as:
* text is visible
* title contains specified value

The [Waits]({{< ref "../waits#built-in-conditions" >}}) page lists every built-in condition
for each language.

{{< tabpane text=true >}}
{{% tab header="Java" %}}
[Expected Conditions Documentation](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html)
Expand Down
189 changes: 183 additions & 6 deletions website_and_docs/content/documentation/webdriver/waits.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ Solving our example with an implicit wait looks like this:

{{< tabpane text=true >}}
{{< tab header="Java" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L50" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L51" >}}
{{< /tab >}}
{{< tab header="Python" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L27" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L28" >}}
{{< /tab >}}
{{< tab header="CSharp" >}}
{{< gh-codeblock path="/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs#L39" >}}
Expand Down Expand Up @@ -104,12 +104,12 @@ Another nice feature is that, by default, the Selenium Wait class automatically
{{% tab header="Java" %}}
This example shows the condition being waited for as a _lambda_. Java also supports
[Expected Conditions]({{< ref "support_features/expected_conditions" >}})
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L67-L68" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L68-L69" >}}
{{% /tab %}}
{{% tab header="Python" %}}
This example shows the condition being waited for as a _lambda_. Python also supports
[Expected Conditions]({{< ref "support_features/expected_conditions" >}})
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L41-L42" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L42-L43" >}}
{{% /tab %}}
{{< tab header="CSharp" >}}
{{< gh-codeblock path="/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs#L56-L57" >}}
Expand All @@ -126,6 +126,183 @@ JavaScript also supports [Expected Conditions]({{< ref "support_features/expecte
{{< /tab >}}
{{< /tabpane >}}

### Built-in conditions

Most bindings include a set of ready-made conditions
for the situations that come up most often in waits.
You don't have to write a custom lambda for each one.
Conditions that take a locator search for the element on every poll,
so they also wait for it to appear.
Many of them hand back the element (or elements) once the condition is met,
letting you use the result of the wait directly.

This example locates an element, waits for it to be visible,
and then waits for its text, using only built-in conditions:

{{< tabpane text=true >}}
{{< tab header="Java" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L106-L110" >}}
{{< /tab >}}
{{< tab header="Python" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L66-L70" >}}
{{< /tab >}}
{{% tab header="CSharp" %}}
.NET does not ship built-in conditions. Pass a lambda to `WebDriverWait.Until()`, as in the
[explicit wait](#explicit-waits) example.
{{% /tab %}}
{{% tab header="Ruby" %}}
Ruby does not ship built-in conditions. Pass a block to `Selenium::WebDriver::Wait#until`, as in the
[explicit wait](#explicit-waits) example.
{{% /tab %}}
{{< tab header="JavaScript" >}}
{{< gh-codeblock path="/examples/javascript/test/waits/waits.spec.js#L62-L65" >}}
{{< /tab >}}
{{% tab header="Kotlin" %}}
Kotlin uses the Java `ExpectedConditions` class listed in the Java tab below.
{{% /tab %}}
{{< /tabpane >}}

The complete list of built-in conditions for each binding:

{{< tabpane text=true >}}
{{% tab header="Java" %}}
Class `org.openqa.selenium.support.ui.ExpectedConditions`
([API docs](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html)).
Use with `new WebDriverWait(driver, timeout).until(...)`.

| Condition | Waits until |
|-----------|-------------|
| `titleIs(title)` | The page title equals the value |
| `titleContains(title)` | The page title contains the value |
| `urlToBe(url)` | The current URL equals the value |
| `urlContains(fraction)` | The current URL contains the value |
| `urlMatches(regex)` | The current URL matches the regular expression |
| `presenceOfElementLocated(By)` | An element is in the DOM (not necessarily visible); returns it |
| `presenceOfAllElementsLocatedBy(By)` | At least one element is in the DOM; returns them all |
| `presenceOfNestedElementLocatedBy(By or WebElement, By)` | A child element is in the DOM under a parent; returns it |
| `presenceOfNestedElementsLocatedBy(By, By)` | Child elements are in the DOM under a parent; returns them |
| `visibilityOfElementLocated(By)` | An element is in the DOM and displayed; returns it |
| `visibilityOf(WebElement)` | A known element is displayed; returns it |
| `visibilityOfAllElementsLocatedBy(By)` | All matching elements are displayed; returns them |
| `visibilityOfAllElements(WebElement...)` | All given elements are displayed; returns them |
| `visibilityOfNestedElementsLocatedBy(By or WebElement, By)` | Child elements under a parent are displayed; returns them |
| `invisibilityOfElementLocated(By)` | An element is hidden or not in the DOM |
| `invisibilityOf(WebElement)` | A known element is hidden or no longer in the DOM |
| `invisibilityOfAllElements(WebElement...)` | All given elements are hidden |
| `invisibilityOfElementWithText(By, text)` | No displayed element matching the locator has the given text |
| `elementToBeClickable(By or WebElement)` | An element is displayed and enabled; returns it |
| `elementToBeSelected(By or WebElement)` | An element is selected |
| `elementSelectionStateToBe(By or WebElement, selected)` | An element's selected state matches the value |
| `stalenessOf(WebElement)` | An element is no longer attached to the DOM |
| `textToBe(By, text)` | An element's text equals the value |
| `textToBePresentInElement(WebElement, text)` | An element's text contains the value |
| `textToBePresentInElementLocated(By, text)` | A located element's text contains the value |
| `textToBePresentInElementValue(By or WebElement, text)` | An element's `value` contains the value |
| `textMatches(By, Pattern)` | An element's text matches the regular expression |
| `attributeToBe(By or WebElement, attribute, value)` | An element's attribute or CSS property equals the value |
| `attributeContains(By or WebElement, attribute, value)` | An element's attribute or CSS property contains the value |
| `attributeToBeNotEmpty(WebElement, attribute)` | An element's attribute or CSS property is not empty |
| `domAttributeToBe(WebElement, attribute, value)` | An element's DOM attribute equals the value |
| `domPropertyToBe(WebElement, property, value)` | An element's DOM property equals the value |
| `numberOfElementsToBe(By, number)` | The number of matching elements equals the value; returns them |
| `numberOfElementsToBeMoreThan(By, number)` | The number of matching elements is more than the value; returns them |
| `numberOfElementsToBeLessThan(By, number)` | The number of matching elements is less than the value; returns them |
| `numberOfWindowsToBe(number)` | The number of open windows or tabs equals the value |
| `frameToBeAvailableAndSwitchToIt(frame)` | A frame, given as a `By`, name or ID, index, or `WebElement`, is available; then switches to it |
| `alertIsPresent()` | An alert is open; returns it |
| `jsReturnsValue(script)` | The JavaScript returns a value; returns it |
| `javaScriptThrowsNoExceptions(script)` | The JavaScript runs without throwing |
| `and(conditions...)` | All of the conditions are true |
| `or(conditions...)` | Any of the conditions is true |
| `not(condition)` | The condition is false |
| `refreshed(condition)` | The condition is true, retrying it after a stale element error |
{{% /tab %}}
{{% tab header="Python" %}}
Module `selenium.webdriver.support.expected_conditions`
([API docs](https://www.selenium.dev/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html)),
usually imported as `EC`.
Use with `WebDriverWait(driver, timeout).until(...)`.
Locators are tuples, such as `(By.ID, "message")`.

| Condition | Waits until |
|-----------|-------------|
| `title_is(title)` | The page title equals the value |
| `title_contains(title)` | The page title contains the value |
| `url_to_be(url)` | The current URL equals the value |
| `url_contains(url)` | The current URL contains the value |
| `url_matches(pattern)` | The current URL matches the regular expression |
| `url_changes(url)` | The current URL is different from the value |
| `presence_of_element_located(locator)` | An element is in the DOM (not necessarily visible); returns it |
| `presence_of_all_elements_located(locator)` | At least one element is in the DOM; returns them all |
| `visibility_of_element_located(locator)` | An element is in the DOM and displayed; returns it |
| `visibility_of(element)` | A known element is displayed; returns it |
| `visibility_of_any_elements_located(locator)` | At least one matching element is displayed; returns the displayed ones |
| `visibility_of_all_elements_located(locator)` | All matching elements are displayed; returns them |
| `invisibility_of_element_located(locator or element)` | An element is hidden or not in the DOM |
| `invisibility_of_element(element or locator)` | An element is hidden or not in the DOM |
| `element_to_be_clickable(locator or element)` | An element is displayed and enabled; returns it |
| `element_to_be_selected(element)` | A known element is selected |
| `element_located_to_be_selected(locator)` | A located element is selected |
| `element_selection_state_to_be(element, is_selected)` | A known element's selected state matches the value |
| `element_located_selection_state_to_be(locator, is_selected)` | A located element's selected state matches the value |
| `staleness_of(element)` | An element is no longer attached to the DOM |
| `text_to_be_present_in_element(locator, text)` | An element's text contains the value |
| `text_to_be_present_in_element_value(locator, text)` | An element's `value` contains the value |
| `text_to_be_present_in_element_attribute(locator, attribute, text)` | An element's attribute contains the value |
| `element_attribute_to_include(locator, attribute)` | An element has the attribute |
| `number_of_windows_to_be(num_windows)` | The number of open windows or tabs equals the value |
| `new_window_is_opened(current_handles)` | A window or tab has opened since the handles were read |
| `frame_to_be_available_and_switch_to_it(frame)` | A frame, given as a locator, name or ID, or element, is available; then switches to it |
| `alert_is_present()` | An alert is open; returns it |
| `all_of(*conditions)` | All of the conditions are true |
| `any_of(*conditions)` | Any of the conditions is true |
| `none_of(*conditions)` | None of the conditions is true |
{{% /tab %}}
{{% tab header="CSharp" %}}
.NET does not ship built-in conditions.
The `ExpectedConditions` class was removed from the bindings in Selenium 4.
Pass a lambda to `WebDriverWait.Until()` that returns a non-null value or `true`
when the condition is met.
{{% /tab %}}
{{% tab header="Ruby" %}}
Ruby does not ship built-in conditions.
Pass a block to `Selenium::WebDriver::Wait#until` that returns a truthy value
when the condition is met.
{{% /tab %}}
{{% tab header="JavaScript" %}}
Module `until` from `selenium-webdriver`
([API docs](https://www.selenium.dev/selenium/docs/api/javascript/index.html)).
Use with `await driver.wait(until.condition(...), timeout)`.
Conditions that check an element resolve to that element once they are met.

| Condition | Waits until |
|-----------|-------------|
| `titleIs(title)` | The page title equals the value |
| `titleContains(substr)` | The page title contains the value |
| `titleMatches(regex)` | The page title matches the regular expression |
| `urlIs(url)` | The current URL equals the value |
| `urlContains(substrUrl)` | The current URL contains the value |
| `urlMatches(regex)` | The current URL matches the regular expression |
| `elementLocated(locator)` | An element is in the DOM; returns it |
| `elementsLocated(locator)` | At least one element is in the DOM; returns them all |
| `elementIsVisible(element)` | An element is displayed |
| `elementIsNotVisible(element)` | An element is not displayed |
| `elementIsEnabled(element)` | An element is enabled |
| `elementIsDisabled(element)` | An element is disabled |
| `elementIsSelected(element)` | An element is selected |
| `elementIsNotSelected(element)` | An element is not selected |
| `elementTextIs(element, text)` | An element's text equals the value |
| `elementTextContains(element, substr)` | An element's text contains the value |
| `elementTextMatches(element, regex)` | An element's text matches the regular expression |
| `stalenessOf(element)` | An element is no longer attached to the DOM |
| `ableToSwitchToFrame(frame)` | A frame is available, then switches to it |
| `alertIsPresent()` | An alert is open; returns it |
{{% /tab %}}
{{% tab header="Kotlin" %}}
Kotlin uses the Java `ExpectedConditions` class. See the Java tab.
{{% /tab %}}
{{< /tabpane >}}

### Customization

The Wait class can be instantiated with various parameters that will change how the conditions are evaluated.
Expand All @@ -143,10 +320,10 @@ make sure that the code returns `true` when it is successful):
{{< tabpane text=true >}}
{{% tab header="Java" %}}
The easiest way to customize Waits in Java is to use the `FluentWait` class:
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L82-L92" >}}
{{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L83-L93" >}}
{{% /tab %}}
{{< tab header="Python" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L53-L55" >}}
{{< gh-codeblock path="/examples/python/tests/waits/test_waits.py#L54-L56" >}}
{{< /tab >}}
{{< tab header="CSharp" >}}
{{< gh-codeblock path="/examples/dotnet/SeleniumDocs/Waits/WaitsTest.cs#L70-L79" >}}
Expand Down
Loading
Loading